Original Post
To get smooth movement on my terrain I fit quadriatic bezier surfaces to each 3x3 square of it when calculating terrain height and normal for purposes of unit movement. The terrain height function works perfectly and results in continous change in height when traversing the terrain, but the normal calculation results in normals that somtimes vary continously, but sometimes and maybe only at certain angles suddenly jerk 20 degrees or something like that regularly. What I think I'm doing is that I take the normalized cross product of the partial derivatives of the surface. And I think the partial derivative of a surface with respect to u is just the surface function with Bi(u) replaced with dBi(u)/du. (where the surface function is S(u,v) = sum(i=0,2)sum(j=0,2)[Pij*Bi(u)Bj(v)] Is my idea wrong, or my implementation of it? Here's my code:
Vector3 Patch::getNormal(float x, float z, int ix, int iz) const {
ix = (ix >> 1) << 1;
iz = (iz >> 1) << 1;
float u = (x - float(ix)) * 0.5f;
float v = (z - float(iz)) * 0.5f;
float u1 = 1 - u;
float v1 = 1 - v;
// basis functions
float b0u = u1*u1;
float b0v = v1*v1;
float b1u = 2.0f*u*u1;
float b1v = 2.0f*v*v1;
float b2u = u*u;
float b2v = v*v;
// derived basis functions
float db0u = -2.0f*u1;
float db0v = -2.0f*v1;
float db1u = 2.0f-4.0f*u;
float db1v = 2.0f-4.0f*v;
float db2u = 2.0f*u;
float db2v = 2.0f*v;
// partial derivative dS(u,v)/du of the surface
Vector3 du;
du = vertices[ iz *g_leafdim+ix ]*(db0u*b0v);
du += vertices[ iz *g_leafdim+ix+1]*(db1u*b0v);
du += vertices[ iz *g_leafdim+ix+2]*(db2u*b0v);
du += vertices[(iz+1)*g_leafdim+ix ]*(db0u*b1v);
du += vertices[(iz+1)*g_leafdim+ix+1]*(db1u*b1v);
du += vertices[(iz+1)*g_leafdim+ix+2]*(db2u*b1v);
du += vertices[(iz+2)*g_leafdim+ix ]*(db0u*b2v);
du += vertices[(iz+2)*g_leafdim+ix+1]*(db1u*b2v);
du += vertices[(iz+2)*g_leafdim+ix+2]*(db2u*b2v);
// partial derivative dS(u,v)/dv of the surface
Vector3 dv;
dv = vertices[ iz *g_leafdim+ix ]*(b0u*db0v);
dv += vertices[ iz *g_leafdim+ix+1]*(b1u*db0v);
dv += vertices[ iz *g_leafdim+ix+2]*(b2u*db0v);
dv += vertices[(iz+1)*g_leafdim+ix ]*(b0u*db1v);
dv += vertices[(iz+1)*g_leafdim+ix+1]*(b1u*db1v);
dv += vertices[(iz+1)*g_leafdim+ix+2]*(b2u*db1v);
dv += vertices[(iz+2)*g_leafdim+ix ]*(b0u*db2v);
dv += vertices[(iz+2)*g_leafdim+ix+1]*(b1u*db2v);
dv += vertices[(iz+2)*g_leafdim+ix+2]*(b2u*db2v);
return normalize(cross(du, dv));
}