Update Normals using the Matrix

Started by
11 comments, last by newbird 18 years, 9 months ago
Hi everyone, I have a simple problem I was hoping someone could help me with. I have a simple OpenGL program where I need to recompute the normals every frame to point toward the camera. I'm using the well-known ArcBall algorithm for rotating the OpenGL object using mouse input. In my display function I translate the object away from the origin such that I can see the entire object. I then rotate the object according to the 4x4 ArcBall matrix via: float* matrix=Spaceball.GetMatrix(); glMultMatrixf(matrix); Now for every point in my scene, I need to assign the x,y,z values of the new normal for that point (so that it continues to point toward the camera despite having been rotated). I'm sure it's a simple set of equations, but it currently escapes me on how to do this. Can anyone figure out how to assign the normals to point toward the camera by essentially using this modelview matrix? Below is my display function which attempts to use the inverse transpose of this matrix to find the new normal but it is obviously wrong and the actual solution may be simpler: void glutDisplay(void) { int i; unsigned short* pos; float SpaceballInvT[16]; float normalDir[4]; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPushMatrix(); /* translate camera to the coordinates provided by eye array */ glTranslatef (-eye[0], -eye[1], -(eye[2]-zoom*eye[2])); glMultMatrixf(Spaceball.GetMatrix()); Spaceball.GetInvMatrix(SpaceballInvT); TransposeMatr(SpaceballInvT); Spaceball.Update(); //Update the normals for each voxel for(i=0;i<numVerts;i++) { pos = (unsigned short*)&voxels[i*10+4]; MatMult4f(normalDir, SpaceballInvT, (float)pos[0], (float)pos[1], (float)pos[2], 1.f); voxels[i*10+ 1] = (unsigned char)normalDir[0];// x-component of normal voxels[i*10+ 2] = (unsigned char)normalDir[1];// y-component of normal voxels[i*10+ 3] = (unsigned char)normalDir[2];// z-component of normal } glTranslated(-DIM_SIZE/2,-DIM_SIZE/2,-DIM_SIZE/2); VolrSsplats(voxels, numVerts, dimSize); //Draw hairy splats that show directions of the normal if(showNormals) { Disable_Splatting(); for(i=0;i<numVerts;i++) { glBegin(GL_LINES); pos = (unsigned short*)&voxels[i*10+4]; glVertex3f(pos[0],pos[1],pos[2]); glVertex3f(pos[0]+5.f*(float)voxels[i*10+1]/255.f,pos[1]+5.f*(float)voxels[i*10+2]/255.f,pos[2]+5.f*(float)voxels[i*10+3]/255.f); glEnd(); } Enable_Splatting(); } glPopMatrix(); glFlush(); glutSwapBuffers(); }
Advertisement
It's the normalized negative of the vector position of that point minus the vector position of the camera.

new_normal = -(point_pos - camera_pos);
new_normal = Normalize(new_normal);

Oh, the points position has to be in worldspace. You get that by multipling the point by its transformation matrix.
A good idea FlyingDemon, I had thought of trying that before. It seems simple and yet I'm having difficulty. I get the modelview matrix and multiply it by the original point to get the object space coordinate. However, if I try to calculate the vector from that point to the camera (commented as "insta non-render"), my screen shows up but it doesn't render anything...not even the black clear color. Perhaps you have another suggestion?

void glutDisplay(void)
{
int i;
unsigned short* pos;
float SpaceballInv[16];
float normalDir[4];

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

glPushMatrix();

/* translate camera to the coordinates provided by eye array */
glTranslatef (-view.eye[0], -view.eye[1], -(view.eye[2]-view.zoom*view.eye[2]));
glMultMatrixf(Spaceball.GetMatrix());
Spaceball.Update();

glTranslated(-DIM_SIZE/2,-DIM_SIZE/2,-DIM_SIZE/2);
if(updateNormals) {
glGetFloatv (GL_MODELVIEW_MATRIX, SpaceballInv);
for(i=0;i<numVerts;i++) {
pos = (unsigned short*)&voxels[i*10+4];
MatMult4f(normalDir, SpaceballInv, (float)pos[0], (float)pos[1], (float)pos[2], 1.f);
for(j=0;j<3;j++) normalDir[j]=-1.f*(255.f*(float)pos[j] - view.eye[j]);
Normalize3(&normalDir[0]);

voxels[i*10+ 1] = (unsigned char)(255.f*normalDir[0]); // x-component of normal
voxels[i*10+ 2] = (unsigned char)(255.f*normalDir[1]); // y-component of normal
voxels[i*10+ 3] = (unsigned char)(255.f*normalDir[2]); // z-component of normal
}
}//End update normals

VolrSsplats(voxels, numVerts, dimSize);

glPopMatrix();
glFlush();
glutSwapBuffers();
}

[Edited by - newbird on June 25, 2005 2:17:05 PM]
Make sure that your not multiplying your verts twice. You use glMultMatrix at first but later on you also multiply the verts again to get their new positions, i think.

A question...
What are you trying to do? - Have the object constantly lit on the side that points towards the camera?
The glMultMatrix() call allows me to rotate the cubic volume that I have. The pos variable is referencing each voxel's location within that volume. The glMultMatrix simply allows me to move those points to the correct location based upon the ArcBall. Nothing changes the coordinates of each voxel within the volume as these are stored in voxels[i*10+ 4,5,6].

The second "MatMult4f(normalDir, SpaceballInvT, (float)pos[0], (float)pos[1], (float)pos[2], 1.f);" for each voxel simply allows me to store the OpenGL object-space coordinates for the current voxel. Given the current transformation matrix, the new object coordinates of each voxel should be stored in the normalDir vector.

Good question as to what precisely I want to do. Sometimes I leave out the essence. I have a headlight, so the light is positioned at the same place as the camera. So yes, the side facing the camera is always lit. I had hoped to get the normals correctly pointing toward the camera at all times and then adjust the light so that I get a white specular highlight in the middle of every splat (so they appear more round rather than blending together).
"The second "MatMult4f(normalDir, SpaceballInvT, (float)pos[0], (float)pos[1], (float)pos[2], 1.f);" for each voxel simply allows me to store the OpenGL object-space coordinates for the current voxel. Given the current transformation matrix, the new object coordinates of each voxel should be stored in the normalDir vector."


MatMult4f(normalDir, SpaceballInv, (float)pos[0], (float)pos[1], (float)pos[2], 1.f);
/*//Insta-nonrender
for(i=0;i<3;i++) normalDir=-1.f*((float)pos - view.eye);

^^ You filled in the 'normalDir' using MatMult4f, then right after you gave them a different value? - Is that intended?
No, that's not what is intended. Obviously I'm a moron. pos should be normalDir, since normalDir is the transformed location of pos. Even so, I still have the same behavior as far as the window not being rendered. Also, should I be using the MODELVIEW or the PROJECTION matrix? I appreciate your patience, feel free to tell me I'm a moron and move on with your life. ^_^
Im out of ideas( i never has any) about why its not rendering, even the clear color. Comment the entire thing out peice by peice until it starts to render again, that should give an idea.
It's certainly the for i<3 loop that causes the program not to render. I don't know why it'd cause that, I'll inspect the values and see if maybe they're odd values that might be confusing the OpenGL state machine.
Well let this be a lesson to you then!

Only declare variables in the scopes in which they're used...

you're blowing away the value of i from the outter loop when you do i=0;i<3

This topic is closed to new replies.

Advertisement