Reversing Mesh Normals

Started by
4 comments, last by BornToCode 17 years, 11 months ago
Is there a function or way to invert the normals of an ID3DXMesh* object? I have a box enclosing my scene and wish to invert the normals to make it act like a room.
Advertisement
Culling doesn't care about the normals, it only cares about the winding order.

Thus, you should (ideally) build the box with inverted faces in your modeler, before you export it. However, if that's not an option, then you can change the culling mode render state, to cull away CW faces (such that CCW faces get rendered).

Of course, this means that the normals will point the wrong way if you want to actually do lighting, so in that case, you ALSO need to invert the normals. Typically, you do that by locking the vertex buffer, and walking the buffer, multiplying each normal vector by -1. This is easy if you know C++ and pointers; it's harder if you want to use Managed DirectX; you pretty much have to use unsafe code.

If that's all too cumbersome (manage winding order and updating normals), you can also lock the index buffer, and swap the two first indices of each triangle -- if the triangle index list is 0,1,2, 2,3,0 (for two triangles making a quad), you can swap the first two of each triangle to make it 1,0,2 3,2,0. Then call CalculateNormals to re-calculate the new normals if you want lighting to work right.
enum Bool { True, False, FileNotFound };
Oh, I already took care of culling by simply turning it off (a temporary fix, really). I just want to try my hand at shadows and needed a quick way to get an area to project onto so I used the D3DXCreateBox() function to get my box. I'll try the pointers and reverse the normals. I don't need to change any vertices or indices at all.
So after a few minutes of trying various things with both the vertex and index buffers, I can't figure out how to do this. Can anyone explain how to manipulate the buffers?
One way of doing this is using the CD3DXCrackDecl class which can read and write arbitrary elements from a vertex stream in a very flexible way. The class can be found in the UVAtlas sample directory.

Here's an example that uses it to invert all the normals in the vertex buffer:

void *pVertexData;mesh->LockVertexBuffer(D3DLOCK_NOSYSLOCK, &pVertexData);D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];mesh->GetDeclaration(decl);CD3DXCrackDecl cd;cd.SetDeclaration(decl);cd.SetStreamSource(0, pVertexData, 0);for (int i=0; i<mesh->GetNumVertices(); i++){	D3DXVECTOR3 norm;	cd.DecodeSemantic(D3DDECLUSAGE_NORMAL, 0, i, (float*)&norm, 3);	norm *= -1.0f;	cd.EncodeSemantic(D3DDECLUSAGE_NORMAL, 0, i, (float*)&norm, 3);}mesh->UnlockVertexBuffer();
from your post you said that you are using D3DXCreateBox. So the easiest way to do what you are trying to do is.

First of all D3DXCreateBox will give you a mesh wchich has this attribute

D3DXVECTOR3 position;
D3DXVECTOR3 normal;

so basically the normal will be the second coordinate.

The next step you want to do is lock the vertexbuffer and modify each normal like so.

PBYTE p=NULL;
mesh->LockVertexBuffer(0,(LPVOID*)&p);
for(int i=0;i<mesh->GetNumVertices();i++)
{
//Skip the position
p+=sizeof(float)*3;
//Modify the Normal.
(*(float*)&*p)=(*(float*)&*p)*-1;p+=4;
(*(float*)&*p)=(*(float*)&*p)*-1;p+=4;
(*(float*)&*p)=(*(float*)&*p)*-1;p+=4;
//Go to the next vertex
p+=D3DXGetFVFVertexSize(mesh->GetFVF())-24;
}
mesh->UnlockVertexBuffer();

This topic is closed to new replies.

Advertisement