Creating ExtendedMeshShape from Direct3D Mesh

Creating ExtendedMeshShape from Direct3D Mesh

Hi All,

I have been a regular viewer of this forum when encountering issues with my ventures into Havok Physics, and usually find the solution, however I'm having issues with something that I just can't seem so resolve.

I'm working on a project that is using Havok Physics and Direct3D9, and have got a number of things working, but now I am trying to import models and reached a snag. I don't have 3dsmax or Maya meaning I can't create .hkx files, so what I'm attempting to do is convert the 3D model that I can import with Direct3D into a hkpExtendedMeshShape so that the physical world will match the real world.

(Click for fullimage)

As you can see in the above image, the cube I'm rendering does not look the same when imported into Havok, and I can't think why. I've been spending ages on this and only just managed to get this far. I tried the same on the terrain, but that had even more issues (but that's perhaps down to it not having triangulated surfaces, which the cube does). Here is the code:

MeshVertex* verts = 0;
meshBlock->LockVertexBuffer(0, (void**)&verts);
int numVertices = meshBlock->GetNumVertices();

float* vertices = new float[numVertices * 3];
		
for(int i = 0; i < numVertices; i++)
{
	int vertex = i * 3;
	vertices[vertex + 0] = verts[i].position.x;
	vertices[vertex + 1] = verts[i].position.y;
	vertices[vertex + 2] = verts[i].position.z;
}

void* indices = 0;
meshBlock->LockIndexBuffer(0, (void**)&indices);
int numTriangles = meshBlock->GetNumFaces();


hkpExtendedMeshShape* m_mesh = new hkpExtendedMeshShape();
{
	hkpExtendedMeshShape::TrianglesSubpart part;
		
	part.m_vertexBase = vertices;
	part.m_vertexStriding = sizeof(float) * 3;
	part.m_numVertices = numVertices;

	part.m_indexBase = indices;
	part.m_indexStriding = sizeof(unsigned short) * 3;
	part.m_numTriangleShapes = numTriangles;

	part.m_stridingType = hkpExtendedMeshShape::INDICES_INT16;

	m_mesh->addTrianglesSubpart(part);
}

meshBlock->UnlockIndexBuffer();
meshBlock->UnlockVertexBuffer();


hkpRigidBodyCinfo blockInfo;

hkVector4 blockPosition(0.0f, 5.0f, 0.0f);
hkReal blockMass = 100.0f;

blockInfo.m_shape = m_mesh;
blockInfo.m_position = blockPosition;
blockInfo.m_mass = blockMass;
blockInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA;
blockInfo.m_qualityType = HK_COLLIDABLE_QUALITY_MOVING;
		
hkpInertiaTensorComputer::setShapeVolumeMassProperties(m_mesh, blockMass, blockInfo);

pRigidBody = new hkpRigidBody(blockInfo);

physics->getWorld()->addEntity(pRigidBody);
pRigidBody->removeReference();
m_mesh->removeReference();

I could potentially remove the first for loop and just cast the MeshVertex (custom FVF), but for now that doesn't seem to be the issue. So using the LPD3DXMesh I'm attempting to extract the vertices and indexes and then apply it to the extended mesh. I get the impression that the indices are getting messed up during the process, but can't figure out how to resolve the issue.

Any help in this matter would be greatly appreciated.

14 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Hi zodius,

A few things that immediately come to mind:

1) Are your vertices actually 16-bit values, or 32-bit? If it's the latter, you'll need to change part.m_indexStriding abd part.m_stridingType.

2) Does the "vertices" array that you allocate get deleted later? It needs to stay around for the life of the Havok object, since we don't make copies of the data.

3) Are you using the debug Havok libs, and are you seeing any asserts?

If those don't work, can you try reproducing the problem with a simple cube (e.g. 8 verts and 12 triangles) in one of our demos, and attach the modified code here?

Cheers,

-Chris

Quoting - havokchris

Hi zodius,

A few things that immediately come to mind:

1) Are your vertices actually 16-bit values, or 32-bit? If it's the latter, you'll need to change part.m_indexStriding abd part.m_stridingType.

2) Does the "vertices" array that you allocate get deleted later? It needs to stay around for the life of the Havok object, since we don't make copies of the data.

3) Are you using the debug Havok libs, and are you seeing any asserts?

If those don't work, can you try reproducing the problem with a simple cube (e.g. 8 verts and 12 triangles) in one of our demos, and attach the modified code here?

Cheers,

-Chris

Thanks Chris,

Following your suggestion, I checked the index buffer depth and it is indeed 16 bits. This gave me an idea though, and thats to check the size of a vertex in direct3D, and it seems that there is more information there than just the three coordinates. So I've now changed this so its the correct value and the model does get generated correctly.

One problem still remains though, which you may or may not be able to help with. I have a terrain model that is imported after the cube shape, and follow the same process but don't get the terrain generated correctly. This is making me suspect that the first model is having an effect upon the second within the index buffer, and so when passed to havok vertices are not placed correctly. Would anybody know how I could resolve this?

Regarding the third suggestion, I'm persuming you are referring to the outputs on the console window? If so then I am making a windowed application and as such do not have a console. Is there any way to have the console appear for debugging purposes?

Edit: Regarding the situation with terrain, the model I'm using has a large number of polygons and I'm beginning to suspect that Havok may have a limit to how many it can accept for a single model. I say this because I changed the model I imported for the terrain to the cube that now works, and that appeared fine. The code itself now seems to work, so is their anything I need to change in ExtendedMeshShape to allow for high poly terrains. I know that for performance I should use that MOPP wrapping technique, but will that help with allowing this model to appear?

Regards

Glad that helped (at least partially).

The terrain problem definitely sounds suspicious. If you import that before the cube, does it work correctly? I'm not saying that would make a good fix, I'm just trying to narrow things down :)

For the asserts, you can define your own implementation of hkError (see hkDefaultError.h for the standard one) and then call hkError::replaceInstance( yourErrorHandler ) when you're setting up Havok. The important method is hkError::message, which gives you the text of the error, along with the file and line number. Then you can route it however you want, e.g. to a dialog box or OutputDebugString. You should do what hkDefaultError does and return true when the message type is ASSERT or ERROR - this pauses the problem so that you can get a callstack.

If you're linking against the Havok release libraries, the asserts (and warnings) are compiled out, so you won't get any messages. That's good in your final game, but not when you're trying to debug stuff like this. Make sure you link to the debug libraries (hk550Libwin32_net_8-0debug_multithreaded or debug_multithreaded_dll) in your debug/development builds.

To make sure your error handler is working, try adding a line like HK_ASSERT(0x123, false) - if the program stops and the debugger comes up, it's working.

Hope that helps!

-Chris

Edit: added the directory for debug DLL libraries too.

Thanks for the responce.
I've tried swapping the import round, whereby I've changed which files get referenced by the direct3d importer, meaning the terrain is now the mobile object (which killed performance). No effect though. The cube was generated correctly by the second section of code so ordering, nor my copy and pasting, have had anyeffect on the system.

(click to enlarge)

Ignore the fact that the model is on its side (thats due to Blender being a pain), I corrected this in Direct3D by rotating 90 degrees. When inspecting the model closely it seems that points matching the surface do exist, but not all of them are there, nor are they being connected together correctly. I've checked this mesh and the indexes are still 16 bit, so my only real thought is that the ExtendedMeshShape needs to be configured more to allow this number of polygons?
As for the stuff on asserting, thanks. I am indeed using the debug dll's, so I appreciate that you've mentioned how I can see any potential error messages.
Regards
-1

Hi Zodius,

How many triangles do you have altogether? It's possible that you'll need to decrease the "numBitsForSubpartIndex" parameter in the hkpExtendedMeshShape constructor to allow for more triangles in the subparts. Although, I think the comment in the header is wrong - it claims the max number of shapes per subpart is 2^20 - 1, but I think it's actually 2^19 - 1.

If that's not the case, can you try a simpler landscape mesh (maybe a few hundred verts) that might be a little easier to debug?

-Chris

Hi,

just the thread I needed, I've been struggling to create an extended mesh from some triangle data myself, with very little luck so far. All I've managed is one triangle in the VDB and even that is wrongly aligned. So tonight I will try this code of yours how it works with my models. But can you explain again what you did exactly to fix your code? Because I see you copy your vertices X, Y and Z from the D3D buffer to a new float array which is pretty much what I do as well, but how does it matter at this point that the D3D buffer has more data in there?

Thanks for posting this.

Best Regards,

Jarno

void* vertices = 0;
meshBlock->LockVertexBuffer(0, (void**)&vertices);
int numVertices = meshBlock->GetNumVertices();

void* indices = 0;
meshBlock->LockIndexBuffer(0, (void**)&indices);
int numTriangles = meshBlock->GetNumFaces();

hkpExtendedMeshShape* m_mesh = new hkpExtendedMeshShape();
{
	hkpExtendedMeshShape::TrianglesSubpart part;
			
	part.m_vertexBase = (float*)vertices;
	part.m_vertexStriding = meshBlock->GetNumBytesPerVertex();
	part.m_numVertices = numVertices;

	part.m_indexBase = indices;
	part.m_indexStriding = sizeof(unsigned short) * 3;
	part.m_numTriangleShapes = numTriangles;

	part.m_stridingType = hkpExtendedMeshShape::INDICES_INT16;

	m_mesh->addTrianglesSubpart(part);
}

meshBlock->UnlockIndexBuffer();
meshBlock->UnlockVertexBuffer();

Here is how I solved it. It seems that conversion I did with the array doesn't filter out the other data, causing vertices's to be created from normal and texture data, so instead I use a void pointer to the vertices's and then call GetNumBytesPerVertex(), and that seemed to do the trick.

Now all that remains is this terrain issue. I tried reducing the num bits thing, but that had no effect. As you mention though a subpart supports 524287 triangles, and my models has 131072, so I will try making a smaller model later when I get chance. One thing I ask though is whether it is possible for an extended mesh to have multiple sub parts, and therefore be able to have such a large mesh broken up into sections (either during the modelling phase or in software)?

Regards,
-1

I have tried a lower poly mesh that only has 3355 faces, which is a small part of the intended terrain. This is generated, and the cube now has 2216 polygons. This is a lot lower than the 2^19 - 1, and even the previous model fell under that limit. So I really can't fathom why large models aren't being created.
On all occations the rendered model within Direct3D looks correct, therefore making me believe the model is being generated by Blender correctly.
So I can't fathom why havok is having issues with such large polygon meshes, as surely thats where the need for a MOPP is needed, as with the current meshes everything runs in real time without having one in place.
Any help with this matter would be greatly appreciated
-1

Hey,

got it working with a simple box mesh, yay! But with a bit more complex mesh I'm having trouble too. I actually don't see it at all in VDB. And gravity does not move it anywhere. But I'll look more in to it later and post if I'll find anything.

Best Regards,

Jarno

Hi,

now that my problem in my own thread is solved, I think I can see the same problem here in your original code, you declare the vertices buffer locally in your method, try changing it to global. Also create own buffer for the indices and copy those over as well. This works for me now, even with a more complex mesh.

For the second code I think the problem might be related to unlocking the buffers, I think (not being 100% sure tho) the memory shouldn't be accessed after unlocking.

Best Regards,

Jarno

Hi guys,

OK, sounds like it might be a D3D problem and not a Havok one. My D3D-specific knowledge is non-existant :) If it's not safe to read the memory after the buffers have been unlocked, then you'll need to make a copy of the data.

zodius, if that still doesn't work, let's try this: can you try looping over the vertices every frame and calling HK_DISPLAY_POINT for each vertex (you'll need to include ) ? That will show up in the Visual debugger (if you have the Debug Display viewer on), so you should see a rough outline of your mesh.

If that doesn't work, then it means something is wrong with your data; if you're doing the drawing explicitly, it might be easier to set breakpoints and see what's going wrong (before anything gets to the hkpExtendedMeshShape).

Once you've got that working, you can try drawing wireframe triangles with HK_DISPLAY_LINE. Same caveat - if that's not working, it doesn't have anything to do with the Havok mesh shape.

And yes, you can have multiple subparts in a mesh; they're just an option to make organizing the data easier (and allow instancing of parts of meshes).

-Chris

Quoting - havokchris

Hi guys,

OK, sounds like it might be a D3D problem and not a Havok one. My D3D-specific knowledge is non-existant :) If it's not safe to read the memory after the buffers have been unlocked, then you'll need to make a copy of the data.

zodius, if that still doesn't work, let's try this: can you try looping over the vertices every frame and calling HK_DISPLAY_POINT for each vertex (you'll need to include ) ? That will show up in the Visual debugger (if you have the Debug Display viewer on), so you should see a rough outline of your mesh.

If that doesn't work, then it means something is wrong with your data; if you're doing the drawing explicitly, it might be easier to set breakpoints and see what's going wrong (before anything gets to the hkpExtendedMeshShape).

Once you've got that working, you can try drawing wireframe triangles with HK_DISPLAY_LINE. Same caveat - if that's not working, it doesn't have anything to do with the Havok mesh shape.

And yes, you can have multiple subparts in a mesh; they're just an option to make organizing the data easier (and allow instancing of parts of meshes).

-Chris

Ok, Now we are getting somewhere, and it seems your right that its a direct3D issue.

Following your suggestion I did the points thing with the full mesh and got this (with shapes still enabled). As can be seen the surface exists, but the debugger isn't quite happy with the points on the right.


(Click to enlarge)

So with this I went with the drawing of lines, by storing each 3 consecutive verticies and drawing lines between giving the result seen below.


(Click to enlarge)

So its clear the vertex information is correct, but what about the indices, and this is where the problem lies. It seems that during the conversion process between Direct3D and Havok, something odd is happening, which isn't happening with the raw data that creates the rendered mesh.


(Click to enlarge)

This is the same shape that is created as a mesh in Havok. This clearly means the indices are wrong, so this got me thinking again about the ranges, which for havok is 2^19 - 1 as was said, but all this time I've been using 16 bit indices for Direct3D which is below the number of indices for this mesh, so clearly Direct3D is at fault, as when I checked it did say the meshes were 16 bit indices. So as a test I changed this line generating thing to 32 bit indices, and sure enough the terrain is created successfully.

Trying to apply this back to the converter code, I have discovered the cause of the problem. If a small mesh is used Direct3D creates a 16bit indices mesh, but if a bigger one is used it changes to 32 bit. As such the cube has to use a 16bit converter and the terrain has to use 32bits. I will now play around with a method of obtaining what the index depth of a mesh is so conversion should work regardless of the model.


(Click to enlarge)

Thanks HavokChris for all the help!! I'm sure I'll be needing assistance when it comes to wrapping the mesh with a MOPP though ;)

Regards
-1

Great, glad that worked out. I had a feeling it was something with index originally :)

Personally, for a landscape like that, I'd look into using a heightfield (should save a nice chunk of memory). But a MOPP would work fine too.

If you run into any problems with either, can you start a new thread, just to keep things separate?

Cheers,

-Chris

Leave a Comment

Please sign in to add a comment. Not a member? Join today