Maybe, just for testing this hypothesis, you can always sample and mix all textures and set the scaling factor to zero for those that you don't need.
Edit: Like so (Note that this could also be done without branches):
void main(void)
{
const vec3 light = vec3(0.5, 1, 0.5);
shade = dot(light, normalize(normal));
const float fRange1 = 0.01f;
const float fRange2 = 0.1f;
const float fRange3 = 0.5f;
const float fRange4 = 0.9f;
float fScale = position.y/TerrainHeight;
float ScaleSand = 0.0f;
float ScaleGrass = 0.0f;
float ScaleRock = 0.0f;
if(fScale >= 0.0 && fScale <= fRange1)
ScaleSand = 1.0f;
else if(fScale <= fRange2)
{
fScale -= fRange1;
fScale /= (fRange2-fRange1);
float fScale2 = fScale;
fScale = 1.0-fScale;
ScaleSand = fScale;
ScaleGrass = fScale2;
}
else if(fScale <= fRange3)
ScaleGrass = 1.0f;
else if(fScale <= fRange4)
{
fScale -= fRange3;
fScale /= (fRange4-fRange3);
float fScale2 = fScale;
fScale = 1.0-fScale;
ScaleGrass = fScale;
ScaleRock = fScale2;
}
else
ScaleRock = 1.0f;
texColor = texture(sandTexture, texCoord) * ScaleSand +
texture(grassTexture, texCoord) * ScaleGrass +
texture(rockTexture, texCoord) * ScaleRock;
out_Color = texColor * shade;
}