Normals all equal to 0?

Started by
5 comments, last by BFMVfavorite 16 years, 9 months ago
Hey all, I'm trying to make a simple 3D world, but so far it's been a real pain (used to 2D stuff). OK, find the cross product, get the vector length, normalize, and presto, you have a normal? No, not in my case. They all end up = 0 somehow, even when I explicitly put in my own vertices and the normal would be (0,1,0) or some simple normal like that. Here's the code I'm using:

void CrossProduct(CVector point1, CVector point2, CVector point3, CVector normal)
{
    CVector vector,vector2;
	vector.x = point1.x - point2.x;
	vector.y = point1.y - point2.y;
	vector.z = point1.z - point2.z;

	vector2.x = point2.x - point3.x;
	vector2.y = point2.y - point3.y;
	vector2.z = point2.z - point3.z;

	normal.x = vector.y*vector2.z - vector.z*vector2.y;
	normal.y = vector.z*vector2.x - vector.x*vector2.z;
	normal.z = vector.x*vector2.y - vector.y*vector2.x;
}

double VectorLength(CVector vector)
{
	return sqrt((vector.x*vector.x)+(vector.y*vector.y)+(vector.z*vector.z));
}
void Normalize(CVector normalVector)
{
	double length;
	length = VectorLength(normalVector);
	normalVector.x /= length;
	normalVector.y /= length;
	normalVector.z /= length;
}

void CalculateNormal(CVector point1,CVector point2,CVector point3,CVector normal)
{
	CrossProduct(point1,point2,point3,normal);

	Normalize(normal);
}
//and this is what an extremely simple function call looks like, yet it still equals 0
CalculateNormal(CVector(0,0,0),CVector(5,0,0),CVector(5,0,-5),normal);

So, what's the problem with my math? I double AND triple checked it with my book, and that only resulted in me finding an error in my cross product code (which is extremely important), but the big problem is my normals all equal 0. Point me in the right direction! Thanks a bunch, --Nathan --
Advertisement
You are passing the 'normal' parameter by value, which means you're passing a copy of it and anything you do with this copy will not affect the original. To fix this, pass it by reference (or by pointer, if this is straight C). You should also pass the other arguments by const reference, because it is more efficient (unless this is C, not C++, in which case pass them by const pointer):

void CrossProduct(const CVector &point1, const CVector &point2,                  const CVector &point3, CVector &normal){    // The code here doesn't change}


Also, using some operator overloading (or helper functions if this is C), or using a third-party math library will make the code much shorter and less error-prone:

void CrossProduct(const CVector &point1, const CVector &point2,                  const CVector &point3, CVector &normal){    CVector vector = point1 - point2;    CCector vector2 = point2 - point3;        // ...}


And also note that the calculation at the end is really the cross product, so you should move it into a separate function (since the function above does a bit more than just calculating the cross product).
Might you have forgotten your "&" in front of "normal" in the function declaration? everything else is correct.


If i were you i'd also rename that function to something like computeTriangleNormal and just have it return the normal vector, rather than using a misnomer function that requires the user to pre-instantiate a vector for the normal.
Hah, wow I'm so focused on game programming I forget proper C/++ syntax...overthinking I guess. Thanks a bunch for "pointing" out the problem to me :)
It now works with simple normals, when I try a simple triangle with an obvious normal, but when I apply it to my heightfield just about every value equals -1.#IND...another problem.

This is my terrain initialization code:
for (int z = 0; z < MAP_Z; z++){	for (int x = 0; x < MAP_X; x++)	{		terrain[x + z * MAP_X].x = float(x)*MAP_SCALE;						terrain[x + z * MAP_X].y = (float)mapData[(z*MAP_Z+x)*3];		terrain[x + z * MAP_X].z = -float(z)*MAP_SCALE;		//find lighting normals		CalculateNormal(terrain[x+z * MAP_X],terrain[(x+1)+z * MAP_X],terrain[x+(z+1) * MAP_X],normal[x+z * MAP_X]);	}}

Hm, what could the problem be this time...hopefully not another answer that makes me look like an idiot! Haha, thanks a bunch for the help again,
--Nathan

--
Sounds like the result of division by zero. What is the value of length in Normalize?
Normalize should contain an if statement or assert to check that the length is not zero.

Are you sure that all functions concerned are passing by reference and const-reference as appropriate instead of by value now?

Also, did you know that it is faster to calculate 1/length and then use 3 multiplies on each of the x, y, and z components than it is to use 3 divisions?
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
I can see two potential problems.

First, both x and z start at zero and go up. You immediately establish a terrain[] value for [x+z*MAP_X] but in the CalculateNormal call you reference terrain[] elements x+1 and z+1. Those values haven't been established yet.

Also, there could be a potential access past array bounds since your x goes up to MAP_X-1 and z goes up to MAP_Z-1 but you are accessing x+1 and z+1. I see how you need those extra set of points but make sure storage is allocated for it and they too get initialized.
Thanks a bunch guys, again I needed someone to point the little errors out to me. I just made a separate loop after the first one, and set all the normal values after the terrain values had already been initialized. Now the lighting works great! Thanks!
--Nathan

--

This topic is closed to new replies.

Advertisement