Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

Bezier surface normal

Started by robinei Feb 24, 2007 at 6:20 AM 1 replies 2k views
Original Post
robinei
robinei
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));
}


Zipster
Zipster
The partial derivative method is correct, but since you're using discrete patches it's most likely caused by the discontinuity along the seams. Catmull-Rom splines are used to give you C1 continuity, the techniques of which you could probably apply to patches.
robinei
robinei
You're absolutely right. It was a seam continuity problem, and using Catmull-Rom splines worked perfectly. Thanks! Or almost perfectly because it's just a big headache to gather the right control points when I'm at the edges of my terrain patches.

Here's my code for that right now, which apparently doesn't handle the edges correctly(I don't ask peaple to find the problems, I just want some sympathy...):

void Patch::getPoints(int x, int z, Vector3 *p) const {	/*		 0  1  2  3		 4  5  6  7		 8  9 10 11		12 13 14 15	*/	p[5] = vertices[z*g_leafdim+x];	p[6] = vertices[z*g_leafdim+x+1];	p[9] = vertices[(z+1)*g_leafdim+x];	p[10] = vertices[(z+1)*g_leafdim+x+1];	if(x == 0) {		if(west) {			p[4] = west->vertices[(z+1)*g_leafdim-2];			p[8] = west->vertices[(z+2)*g_leafdim-2];		}		else {			p[4] = vertices[z*g_leafdim];			p[8] = vertices[(z+1)*g_leafdim];		}		if(z == 0) {			if(north && west)				p[0] = north->west->vertices[(g_leafdim-1)*g_leafdim-2];			else if(north)				p[0] = north->vertices[(g_leafdim-2)*g_leafdim];			else if(west)				p[0] = west->vertices[g_leafdim-2];			else				p[0] = vertices[0];		}		else {			if(west)				p[0] = west->vertices[z*g_leafdim-2];			else				p[0] = vertices[(z-1)*g_leafdim];		}				if(z == g_leafdim-2) {			if(south && west)				p[12] = south->west->vertices[2*g_leafdim-2];			else if(south)				p[12] = south->vertices[g_leafdim];			else if(west)				p[12] = west->vertices[g_leafdim*g_leafdim-2];			else				p[12] = vertices[(g_leafdim-1)*g_leafdim];		}		else {			if(west)				p[12] = west->vertices[(z+3)*g_leafdim-2];			else				p[12] = vertices[(z+2)*g_leafdim];		}	}	else {		p[4] = vertices[z*g_leafdim+x-1];		p[8] = vertices[(z+1)*g_leafdim+x-1];		if(z == 0) {			if(north)				p[0] = north->vertices[(g_leafdim-2)*g_leafdim+x-1];			else				p[0] = vertices[x-1];		}		else			p[0] = vertices[(z-1)*g_leafdim+x-1];		if(z == g_leafdim-2) {			if(south)				p[12] = south->vertices[g_leafdim+x-1];			else				p[12] = vertices[(g_leafdim-1)*g_leafdim+x-1];		}		else			p[12] = vertices[(z+2)*g_leafdim+x-1];	}		if(x == g_leafdim-2) {		if(east) {			p[7] = east->vertices[z*g_leafdim+1];			p[11] = east->vertices[(z+1)*g_leafdim+1];		}		else {			p[7] = vertices[z*g_leafdim+x+1];			p[11] = vertices[(z+1)*g_leafdim+x+1];		}		if(z == 0) {			if(north && east)				p[3] = north->east->vertices[(g_leafdim-2)*g_leafdim+1];			else if(north)				p[3] = north->vertices[(g_leafdim-1)*g_leafdim-1];			else if(east)				p[3] = east->vertices[1];			else				p[3] = vertices[g_leafdim-1];		}		else {			if(east)				p[3] = east->vertices[(z-1)*g_leafdim+1];			else				p[3] = vertices[z*g_leafdim-1];		}				if(z == g_leafdim-2) {			if(south && east)				p[15] = south->east->vertices[g_leafdim+1];			else if(south)				p[15] = south->vertices[2*g_leafdim-1];			else if(east)				p[15] = east->vertices[(g_leafdim-1)*g_leafdim+1];			else				p[15] = vertices[g_leafdim*g_leafdim-1];		}		else {			if(east)				p[15] = east->vertices[(z+1)*g_leafdim+1];			else				p[15] = vertices[(z+3)*g_leafdim-1];		}	}	else {		p[7] = vertices[z*g_leafdim+x+2];		p[11] = vertices[(z+1)*g_leafdim+x+2];		if(z == 0) {			if(north)				p[3] = north->vertices[(g_leafdim-2)*g_leafdim+x+2];			else				p[3] = vertices[x+2];		}		else			p[3] = vertices[(z-1)*g_leafdim+x+2];		if(z == g_leafdim-2) {			if(south)				p[15] = south->vertices[g_leafdim+x+2];			else				p[15] = vertices[(g_leafdim-1)*g_leafdim+x+2];		}		else			p[15] = vertices[(z+2)*g_leafdim+x+2];	}	if(z == 0) {		if(north) {			p[1] = north->vertices[(g_leafdim-2)*g_leafdim+x];			p[2] = north->vertices[(g_leafdim-2)*g_leafdim+x+1];		}		else {			p[1] = vertices[x];			p[2] = vertices[x+1];		}	}	else {		p[1] = vertices[(z-1)*g_leafdim+x];		p[2] = vertices[(z-1)*g_leafdim+x+1];	}	if(z == g_leafdim-2) {		if(south) {			p[13] = south->vertices[g_leafdim+x];			p[14] = south->vertices[g_leafdim+x+1];		}		else {			p[13] = vertices[(g_leafdim-1)*g_leafdim+x];			p[14] = vertices[(g_leafdim-1)*g_leafdim+x+1];		}	}	else {		p[13] = vertices[(z+2)*g_leafdim+x];		p[14] = vertices[(z+2)*g_leafdim+x+1];	}}

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.