I'm by no means an expert. I don't think you need to calculate normals in the shader unless you're terrain is moving every frame, as opposed to the camera moving every frame. Below is the code I use to get the terrain normals when I initialize new terrain, in C#, which seems to work. It's not my code, You could probably find a better algorithm for generating the normals, since it doesn't run every frame speed is not a huge factor.
private static Vector3 SimpleCrossFilter(int x, int y, ref float[] heightfield,
float normalStrength, int width, int length)
{
// Create four positions around the specified position
Point[] pos = new Point[]
{
new Point(x - 1, y), // left
new Point(x + 1, y), // right
new Point(x, y - 1), // higher
new Point(x, y + 1), // lower
};
// Get the heightvalues at the four positions we just created
float[] heights = new float[4];
for (byte i = 0; i < 4; i++)
{
// Check if we can access the array with the current coordinates
if (pos[i].X >= 0 && pos[i].X < width &&
pos[i].Y >= 0 && pos[i].Y < length)
{
int j = pos[i].X + pos[i].Y * width;
heights[i] = heightfield[j];
}
else
{
// If not, then set value to zero.
heights[i] = 0;
}
}
// Perform simple cross filter.
float dx = heights[0] - heights[1];
float dz = heights[2] - heights[3];
float hy = 1.0f / normalStrength;
// Create and normalize the final normal
Vector3 normal = new Vector3(dx, hy, dz);
normal.Normalize();
return normal;
}