PDA

View Full Version : Trying to create collision detection for levels using PhysX, NxConvexTriangleDesc


chillypacman
07-20-2007, 07:54 AM
This is really killing me, I've looked over the numbers and Iknow what I'm feeding the following function is right:

NxActor* PhysX::GenerateTriangleMeshFromDXMesh(ID3DXMesh* Mesh, NxVec3 pos, short* indices, float* vertices)
{
//dump indices:
std::ofstream out(L"out.txt");
//Used to copy indices
typedef struct {
int IBNumber[3];
} IndexBufferStruct;

int NumVerticies = Mesh->GetNumVertices();
int NumTriangles = Mesh->GetNumFaces();
DWORD FVFSize = D3DXGetFVFVertexSize(Mesh->GetFVF());

//Create pointer for vertices
NxVec3* verts = new NxVec3[Mesh->GetNumVertices()];

int ii = -1;
for(int i = 0; i < Mesh->GetNumVertices(); i++)
{
++ii;
verts[i].x = vertices[ii]/2;
verts[i].y = vertices[++ii]/2;
verts[i].z = vertices[++ii]/2;
}

//Create pointer for indices
NxU32 *tris = new NxU32[NumTriangles * 3];

IndexBufferStruct *DXMeshIBPtr;

ii = 0;
for(int NumInd = 0; NumInd < NumTriangles * 3; NumInd++)
{
tris[NumInd] = indices[ii];
out<<indices[ii]<<"\n";
NumInd++;
tris[NumInd] = indices[++ii];
out<<indices[ii]<<"\n";
NumInd++;
tris[NumInd] = indices[++ii];
out<<indices[ii]<<"\n";
++ii;
}

NxU16* tri = new NxU16[NumTriangles];

// Build physical model
NxTriangleMeshDesc TriMeshDesc;
TriMeshDesc.numVertices = NumVerticies;
TriMeshDesc.numTriangles = NumTriangles;
TriMeshDesc.pointStrideBytes = sizeof(NxVec3);
TriMeshDesc.triangleStrideBytes = 3*sizeof(NxU16);
TriMeshDesc.points = verts;
TriMeshDesc.triangles = tris;
TriMeshDesc.flags = NX_MF_16_BIT_INDICES;

NxTriangleMeshShapeDesc ShapeDesc;

if(0)
{
// Cooking from file
bool status = NxCookTriangleMesh(TriMeshDesc, UserStream("c:\\tmp.bin", false));
ShapeDesc.meshData = gPhysicsSDK->createTriangleMesh(UserStream("c:\\tmp.bin", true));
}
else
{
// Cooking from memory
MemoryWriteBuffer buf;
bool status = NxCookTriangleMesh(TriMeshDesc, buf); //<-- status always fails
ShapeDesc.meshData = gPhysicsSDK->createTriangleMesh(MemoryReadBuffer(buf.data)); //<-- Null pointer error here
}

NxActorDesc actorDesc;
actorDesc.shapes.pushBack(&ShapeDesc);
actorDesc.globalPose.t = pos;
NxActor* PhysXActor = gScene->createActor(actorDesc);
PhysXActor->userData = (void*)1;

delete[] verts;
delete[] tris;

return PhysXActor;
}


However I keep getting null pointer errors at the point where it's supposed to cook a triangle mesh (NxCookTriangleMesh(trimeshdesc, buf); I don't understand why, I've looked over the SDK and some physx tutorials to no avail.

Kenneth Gorking
07-20-2007, 09:57 AM
You are supplying 32-bit indices to NxCookTriangleMesh, but the NxTriangleMeshDesc is set up to use 16-bit indices.

chillypacman
07-20-2007, 09:40 PM
You are supplying 32-bit indices to NxCookTriangleMesh, but the NxTriangleMeshDesc is set up to use 16-bit indices.

It doesn't matter if I'm using NxU32 or NxU16, same difference.

Kenneth Gorking
07-21-2007, 01:55 AM
Have you tried calling the isValid() function on the NxTriangleMeshDesc structure? If it fails there, single-stepping into it is easy and it will show you the error. If it succeeds, the error may be in the vertex/triangle data provided.

chillypacman
07-21-2007, 06:32 AM
Have you tried calling the isValid() function on the NxTriangleMeshDesc structure? If it fails there, single-stepping into it is easy and it will show you the error. If it succeeds, the error may be in the vertex/triangle data provided.

Yeah it succeeded, I don't see what could be wrong with the vertices/indices I provide to it, worked fine with convex meshes,


Where model is an ID3DXMesh,

This is how I get vertices:

float* vertices = (float*)malloc(model->GetNumVertices() * sizeof(D3DXVECTOR3));

DWORD stride = D3DXGetFVFVertexSize(model->GetFVF());
BYTE* vbptr = NULL;
model->LockVertexBuffer(0, (LPVOID*)&vbptr);

int ii = -1;
for(int i = 0; i < model->GetNumVertices(); i++)
{
ii++;
D3DXVECTOR3* pos = (D3DXVECTOR3*)vbptr;
vertices[ii] = pos->x;
vertices[++ii] = pos->y;
vertices[++ii] = pos->z;

vbptr += stride;
}
model->UnlockVertexBuffer();

return vertices;

and indices:

std::ofstream c(L"indices2.txt");
LPVOID * ppData;
DWORD stride = sizeof(short);
BYTE* ibptr = NULL;

short* indices = new short[model->GetNumFaces() * 3];

model->LockIndexBuffer(0, (LPVOID*)&indices);

for(int i = 0; i < model->GetNumFaces() * 3; i++)
{
c<<indices[i]<<"\n";
}

model->UnlockIndexBuffer();

return indices;


the ofstreams are kind of old actually, from when i was verifying the function swere working correctly. I'm very sure they are.

Nicholas Christopher
07-21-2007, 06:38 AM
Hi,

maybe this line:

for(int NumInd = 0; NumInd < NumTriangles * 3; NumInd++)


should be this:


for(int NumInd = 0; NumInd < NumTriangles ; NumInd++)


taken from code from this link:

http://www.gamedev.net/community/forums/topic.asp?topic_id=453916&whichpage=1&#2997505


after edit... seems that its your own post.. maybe its wrong also. ;)

chillypacman
07-21-2007, 08:46 AM
Hi,

maybe this line:


should be this:



taken from code from this link:

http://www.gamedev.net/community/forums/topic.asp?topic_id=453916&whichpage=1&#2997505


after edit... seems that its your own post.. maybe its wrong also. ;)

haha, yeah, I've been asking around, I've been stuck here for waaaay too long, I almost gave up because of it.

Kenneth Gorking
07-22-2007, 05:22 AM
You are not copying the indices you lock. :) There is no garantee that the pointer to the indices will remain valid after the call to UnlockIndexBuffer(). You should also call GetOptions() on the mesh and check for the D3DXMESH_32BIT flag to see if the indices are really stored as 16-bit integers.

Btw, the memory you are allocating is also leaked, because the pointer is overwritten by the call to LockIndexBuffer(). If you somewhere are deleting the 'indices' pointer being returned (which you should), you will actually be deleting the pointer to the ID3DXMesh's index data, which in turn may or may not be valid, which will most likely chrash you program. Should you get lucky and have a valid pointer, your program will still chrash when the mesh is released :)

chillypacman
07-22-2007, 11:25 PM
oh ok, I'm not *absoloutely* sure I understand what you mean. I changed the getindices return from a short pointer to a vector pointer,

std::vector<short> mesh::GetIndices()
{
std::ofstream c(L"indices1.txt");
LPVOID * ppData;
DWORD stride = sizeof(short);
BYTE* ibptr = NULL;

short* indices = new short[model->GetNumFaces() * 3];

std::vector<short> copy;

model->LockIndexBuffer(0, (LPVOID*)&indices);

for(int i = 0; i < model->GetNumFaces() * 3; i++)
{
copy.push_back(indices[i]);
}

model->UnlockIndexBuffer();

for(int i = 0; i < model->GetNumFaces() * 3; i++)
{
c<<copy[i]<<"\n";
}

delete indices;
return copy;
}

and modified the physx function to accept the vector and move it over to an NxU16 array:

NxActor* PhysX::GenerateTriangleMeshFromDXMesh(ID3DXMesh* Mesh, NxVec3 pos, std::vector<short> indices, float* vertices)
{
int NumVerticies = Mesh->GetNumVertices();
int NumTriangles = Mesh->GetNumFaces();
DWORD FVFSize = D3DXGetFVFVertexSize(Mesh->GetFVF());

//Create pointer for vertices
NxVec3* verts = new NxVec3[Mesh->GetNumVertices()];

int ii = -1;
for(int i = 0; i < Mesh->GetNumVertices(); i++)
{
++ii;
verts[i].x = vertices[ii]/2;
verts[i].y = vertices[++ii]/2;
verts[i].z = vertices[++ii]/2;
}
//Create pointer for indices
NxU16 *tris = new NxU16[NumTriangles * 3];

ii = 0;
for(int NumInd = 0; NumInd < NumTriangles * 3; NumInd++)
{
tris[NumInd] = indices[ii];
NumInd++;
tris[NumInd] = indices[++ii];
NumInd++;
tris[NumInd] = indices[++ii];
++ii;
}

NxU16* tri = new NxU16[NumTriangles];

// Build physical model
NxTriangleMeshDesc TriMeshDesc;
TriMeshDesc.numVertices = NumVerticies;
TriMeshDesc.numTriangles = NumTriangles;
TriMeshDesc.pointStrideBytes = sizeof(NxVec3);
TriMeshDesc.triangleStrideBytes = 3*sizeof(NxU16);
TriMeshDesc.points = verts;
TriMeshDesc.triangles = tris;
TriMeshDesc.flags = NX_MF_16_BIT_INDICES;

if(TriMeshDesc.isValid())
{
::MessageBox(0, L"Is valid", 0, 0);
}

NxTriangleMeshShapeDesc ShapeDesc;
if(0)
{
// Cooking from file
bool status = NxCookTriangleMesh(TriMeshDesc, UserStream("c:\\tmp.bin", false));
ShapeDesc.meshData = gPhysicsSDK->createTriangleMesh(UserStream("c:\\tmp.bin", true));
}
else
{
// Cooking from memory
MemoryWriteBuffer buf;
bool status = NxCookTriangleMesh(TriMeshDesc, buf); //<-- status always fails
ShapeDesc.meshData = gPhysicsSDK->createTriangleMesh(MemoryReadBuffer(buf.data)); //<-- Null pointer error here
}

NxActorDesc actorDesc;
actorDesc.shapes.pushBack(&ShapeDesc);
actorDesc.globalPose.t = pos;
NxActor* PhysXActor = gScene->createActor(actorDesc);
PhysXActor->userData = (void*)1;

delete[] verts;
delete[] tris;

return PhysXActor;
}

umm, it stil doesn't work, I even checked some of the values randomly from the NxU16 array using a message box and if block.

Crashes on the same place.

Could the fact I declare gPhysicsSDK and gScene without static have something to do with it? In the tutorials it's always static NxPhysicsSDK* gPhysicsSDK but mine does'thave the static part. When I do try to change it to static in the header file I get a link 2019 error, I did try to change it to static during runtime like so:

static NxPhysicsSDK* temp = gPhysicsSDK

It worked but still same error, so the problem probably isn't with the static thing.

Retro_J
07-23-2007, 12:38 AM
Not seeing all your code it's difficult to see how you've set your cooking up. But have you called NxInitCooking() ?

chillypacman
07-23-2007, 03:21 AM
Not seeing all your code it's difficult to see how you've set your cooking up. But have you called NxInitCooking() ?

Well i'm hardly a pro-programmer (nothing I got to hide that will revolutionaze realtime physics :P) so whatever of my code you wanna see just ask and I'll upload it.

Anyways, I finally got it working.

After seeing Retro_J ask about the whole NxInitCooking it struck me, I hadn't put that in (unlike all the other cook functions I had before, only this one didn't have the NxInitcooking, dunno how I forgot. It didn't work though :O then it turned out it was because of the short array passing thingamob :8 fixed that and everything works great now :)



Erm, except one thing, everytime the FPS rate goes below 300 (yes, 300 is insanely high but I don't have much going on screen) NxActor::addForce stops working. collions still work fine but whenever I try to add a force it doesn't work, somewhere from 400 to 300 the addforce becomes less and less effective.

Basically it seems like the physics is being affected by the framerate O_O, any suggestions how I can fix this up?

I think the only relevent code is as follows:


bool Display(float timeDelta)
{
box->addForce(...) //<-- add a force to NxActor

StartPhysics(timeDelta);
gScene->fetchResults(NX_RIGID_BODY_FINISHED, true);
}

...

void PhysX::StartPhysics(NxReal time)
{
// Update the time step
//gDeltaTime = time;

NxReal deltaTime = 1.0f/6.0f;

// Start collision and dynamics for delta time since the last frame
gScene->simulate(time);
gScene->flushStream();
}


It's kind of an odd problem, I think I can figure it out soon enough (I hope).

Retro_J
07-23-2007, 05:00 AM
Are you applying the force to the TraingleMesh ? If so, don't forget that they can only be static and not dynamic.

chillypacman
07-24-2007, 12:03 AM
Are you applying the force to the TraingleMesh ? If so, don't forget that they can only be static and not dynamic.

oh yes it is dynamic, it works fine right up until the framerate goes below 400 and stops working when it's going at ~300fps. It's like theres abit of force still being applied when a force is applied but bby and large it isn't working right.

I don't get it, looks like different things are happening based on the framerate :8

Retro_J
07-24-2007, 03:48 AM
You cannot use NxTriangleMesh as a dynamic actor, hence the problems you are having.

You can either use an NxConvexMesh, but they are limited to 256 polys, or decompose your geometry into multiple convex mesh shapes.

chillypacman
07-24-2007, 05:50 PM
You cannot use NxTriangleMesh as a dynamic actor, hence the problems you are having.

You can either use an NxConvexMesh, but they are limited to 256 polys, or decompose your geometry into multiple convex mesh shapes.

Thats what I'm doing.

I have a convex mesh (albeit just a box) and I apply a force to it. Works fine right up to a point where the framerate goes below 400 then everything starts flipping out, collision detection works but the force won't apply properly anymore.

Retro_J
07-25-2007, 02:56 AM
Have you tried playing around with your timestep sizes and switching between fixed and variable ?

Try NX_TIMESTEP_FIXED and

NxReal deltaTime = 1.0f/60.0f;

Also have you worked through; Lesson 112 – Local Forces and Force Modes ?

chillypacman
07-27-2007, 03:23 AM
Have you tried playing around with your timestep sizes and switching between fixed and variable ?

Try NX_TIMESTEP_FIXED and

NxReal deltaTime = 1.0f/60.0f;

Also have you worked through; Lesson 112 – Local Forces and Force Modes ?

tried all that already, no help :8 I've read through 112, doesn't have much to do with it.

The physics is fps dependent, it goes very slow when the fps is 200 and very fast when above that, camera motion and all of that (not physics related) works fine. So it's probably the way I pass the change in time or something. I did try fixed, but it wasn't much help when it was 1/60 and the fps was below 200 (I changed it to 1/600 and it worked fine but not very smoothely), at 500fps the whole thing ran fine and smooth.

I'm probably going to have to lock the framerate at 60fps so I can get the physics to synch, I don't know how to do it with a variable framerate.

Reedbeta
07-27-2007, 10:19 AM
You can run multiple physics updates in one frame if the framerate is high enough...you should be using fixed-timestep physics anyway just for reproducibility.

chillypacman
07-29-2007, 02:18 AM
Well I've locked the framerate at 60fps now and am using a fixed timestep to go with it.

I found that the physics are fps dependent, if I have a time step of 1/100 at 60fps it means I should have a timestep of 1/200 at 120fps, basically there has to be a physics/fps ratio maintained. I'll have to figure out an algorithm for this later on or just keep the fps locked at 60fps (which I'll probably do).

Kenneth Gorking
07-29-2007, 08:58 AM
Locking the framerate seems a bit hackish, especially seeing as you appear to be the only PhysX user experiencing this problem. Perhaps you are doing something wrong? Also, using a fixed timestep means that it will automatically make multiple calls to advance the simulation, if enough time has passed.

Reedbeta
07-29-2007, 11:20 AM
Well I've locked the framerate at 60fps now and am using a fixed timestep to go with it.

I found that the physics are fps dependent, if I have a time step of 1/100 at 60fps it means I should have a timestep of 1/200 at 120fps, basically there has to be a physics/fps ratio maintained. I'll have to figure out an algorithm for this later on or just keep the fps locked at 60fps (which I'll probably do).

This isn't really the way to do it. You should have the physics timestep always fixed, but make multiple physics updates per frame depending on the framerate. For instance, the timestep would always be 1/200, but if you drop to 60fps, you'd do two updates before rendering the frame.