PDA

View Full Version : Irrlicht and Newton ConvexHull

Colin
17-01-2011, 12:06 PM
Hi there, long time no see, looking for a little help, i am currently using Irrlicht 1.71 and Newton 2.29. i have so far got everything working apart from convex hull objects, i read that newton and irrlicht both use different sizes, i have fiddled around trying to get it to work with no luck, it "kind of" works, anyways this is my code for creating the collision hull

function CreateConvexHullCollisionFromMesh(nWorld: PNewtonWorld; node: ISceneNode; irr_mesh: IMesh): PNewtonCollision;
var
nMeshBuffer : Integer; //Mesh Buffer count
nVertices : LongWord;
mesh_buffer : IMeshBuffer;
tCounter : LongWord;
vertices : array of Vector3df;
_vertices : PS3DVertex;
i : Integer;
begin
nMeshBuffer := 0;
nVertices := 0;

//get number of vertices
for nMeshBuffer := 0 to irr_mesh.getMeshBufferCount() - 1 do begin
nVertices := nVertices + irr_mesh.getMeshBuffer(nMeshBuffer).getVertexCount ();
end;

//create buffer for vertices
SetLength(vertices, nVertices);
tCounter := 0;

//get (irr_)mesh buffers and copy face vertices
for nMeshBuffer := 0 to irr_mesh.getMeshBufferCount() - 1 do begin
mesh_buffer := irr_mesh.getMeshBuffer(nMeshBuffer);

//get pointer to vertices and indices
_vertices := PS3DVertex(mesh_buffer.getVertices());

{\$POINTERMATH ON}
//copy vertices from mesh to buffer
for i := 0 to mesh_buffer.getVertexCount() - 1 do begin
vertices[tCounter].x := _vertices[i].Pos.x;
vertices[tCounter].y := _vertices[i].Pos.y;
vertices[tCounter].z := _vertices[i].Pos.z;

Inc(tCounter);
end;
{\$POINTERMATH OFF}
end;

//Create Newton collision object
Result := NewtonCreateConvexHull(nWorld, nVertices, @vertices[0].x, sizeof(vector3df), 0, 0, nil);

//remove from mem space
vertices := nil;
end;

currently i have tried with several objects, i am loading it with a cube just to test with... what happens is the cube falls, hits the ground, then gradually (slowly) falls through and then off it goes falling to bottom of newton world size. im guessing my ground is fine since creating newtonbox works just fine, all physics work for this with many objects, 1000s even, just not the convex hull, hope you can help, thanks.

Sascha Willems
18-01-2011, 08:33 AM
Could you please post the rest of the code for creating the actual newton body from the collider? The code above looks correct, so the problem must be caused somewhere else. And if your body acts weird it's often down to a wrong mass / inertia matrix, so that code would be interesting to see. And did you add debug display functionality to see if the hull is actually correct? Maybe it's not the mass / inertia but wrongly assigned vertices or a wrong shape (is your object really convex, and doesn't have holes etc.), so a visual display of what newton actually uses as the shape for convex hull is also very useful.

User137
18-01-2011, 11:17 AM
I don't know either of these libraries, but how do they define faces? Are they Triangles, Triangle_strip or something else, maybe custom?

This is because just vertex alone is not enough to define collision for physics. You can have 1 small triangle and 1 large triangle and if the small one falls on top of the large one it shouldn't go through.

Colin
18-01-2011, 12:17 PM
hi there, thanks for replies, ok so i got up this morning, checked all my libs and realised i had downloaded newton 2.29 but not extracted it .... ok so how silly i am i was still using 2.24 anyways i updated the dll, and now nothing collides correctly, so i moved back to trying to get boxes to collide.

i found 1 strange thing in my box.init procedure if i change the

CreateNewtonBody matrix to the const vPosition value i pass to the procedure it creates the boxes and all is drawn correct and seems to work, only everything is created in 1 place, not the values of vPosition_ and the debug seems has larger scale ( i have tried several things to fix with no success)

if i create from a seperate vector3df then it does not work, draws boxes elsewhere and physics debug is elsewhere also.

the code:

debug rendering:

procedure RenderDebugCollision(body: Pointer; vertexCount: Integer; const FaceArray: PFloat; faceId: Integer); cdecl;
var
i: Integer;
p0: Vector3df;
p1: Vector3df;
irr_p1: Vector3df;
irr_p2: Vector3df;
active: Integer;
color: PSColorf;
begin
active := NewtonBodyGetSleepState(body);

case active of
0: color := getSColorfp(255,0,255,0); //getSColorfp(255,0,255,0);
1: color := getSColorfp(255,255,255,0);
end;

i := vertexcount - 1;

{\$POINTERMATH ON}
p0.x := FaceArray[i * 3 + 0];
p0.y := FaceArray[i * 3 + 1];
p0.z := FaceArray[i * 3 + 2];

for i := 0 to vertexcount-1 do begin
p1.x := FaceArray[i * 3 + 0];
p1.y := FaceArray[i * 3 + 1];
p1.z := FaceArray[i * 3 + 2];

Driver.draw3DLine(@p0.x, @p1.x, color.toSColor);

p0 := p1;
end;
{\$POINTERMATH OFF}
end;

procedure DebugCallback(const body : PNewtonBody); cdecl;
var
m: matrix4;
begin
NewtonBodyGetMatrix(body, @m.M[0]);
NewtonCollisionForEachPolygonDo(NewtonBodyGetColli sion(body), @m.M[0], RenderDebugCollision, Pointer(body));
end;

the loop

lastFPS := -1;
while device.run do begin
driver.beginScene(True, True, getSColor(255, 100, 101, 140), DefEVD, nil);

smgr.drawAll;
gui.drawAll;

DebugCallback(box1.newtonBody);
DebugCallback(box2.newtonBody);
DebugCallback(level.newtonBody);

driver.endScene;
// fps
fps := driver.getFPS;
if (lastFPS <> fps) then begin
device.setWindowCaption(PWideChar(WideString('FPS: ' + str(fps))));
lastFPS := fps;
end;

NewtonUpdate(nWorld, 1.0 / fps);
//NewtonUpdate(nWorld, 0.01);
end;

before the loop i create my game objects (custom records)

box1.Init(nWorld, smgr, 1, nil, -1, getvector3dfp(0,500,0),getvector3dfp(0,0,0),getvec tor3dfp(50,50,50), 10);
setMaterialFlag(box1.node, EMF_LIGHTING, false);
setMaterialTexture(box1.node, 0, getTexture(driver, 'models/crate.jpg'));

box2.Init(nWorld, smgr, 1, nil, -1, getvector3dfp(0,650,0),getvector3dfp(0,0,0),getvec tor3dfp(50,50,50), 10);
setMaterialFlag(box2.node, EMF_LIGHTING, false);
setMaterialTexture(box2.node, 0, getTexture(driver, 'models/crate.jpg'));

for now i just made them static records (no pointer) which then does the following:

procedure TBox.Init(nWorld: PNewtonWorld; smgr: ISceneManager; vSize: Single; vParent: PISceneNode; vId: Integer; const vPosition_: Pvector3dF; const vRotation_: Pvector3dF; const vScale_: Pvector3dF; pMass : Single);
var
Inertia : Vector3df;
Collision : PNewtonCollision;

offset: matrix4;
begin
offset.makeIdentity();
node := smgr.addCubeSceneNode(vSize, vParent, vId, vPosition_,vRotation_,vScale_);

Collision := NewtonCreateBox(nWorld, vScale_.x, vScale_.y, vScale_.z, 0, offset.pointer);
// Create the rigid body
newtonBody := CreateNewtonBody(nWorld, Collision, @vPosition_.x);
NewtonReleaseCollision(nWorld, Collision);

NewtonBodySetUserData(newtonBody, node);

Inertia.x := pMass * (vScale_.y * vScale_.y + vScale_.z * vScale_.z) / 12;
Inertia.y := pMass * (vScale_.x * vScale_.x + vScale_.z * vScale_.z) / 12;
Inertia.z := pMass * (vScale_.x * vScale_.x + vScale_.y * vScale_.y) / 12;

// Set the bodies mass and moment of inertia
NewtonBodySetMassMatrix(newtonBody, pMass, Inertia.x, Inertia.y, Inertia.z);

// Finally set the callback in which the forces on this body will be applied
NewtonBodySetForceAndTorqueCallBack(newtonBody, ForceAndTorqueCallBack);
NewtonBodySetTransformCallback(newtonBody, SetTransformCallback);
end;

callbacks:

procedure SetTransformCallback(const body: PNewtonBody; const matr: PFloat; threadIndex: Integer); cdecl;
var
node: ISceneNode;
irrMat: matrix4;
pos: Vector3df;
rot: Vector3df;
begin
node := NewtonBodyGetUserData(body);

if assigned(node) then begin
CopyMemory(irrMat.pointer(), matr, sizeof(Float)*16);

pos := irrMat.getTranslation^;
rot := irrMat.getRotationDegrees();

node.setPosition(@pos.x);
node.setRotation(@rot.x);
end;
end;

procedure ForceAndTorqueCallback(const body: PNewtonBody; timestep: float; threadindex: integer); cdecl;
var
Mass : Single;
Inertia : Vector3df;
Force : Vector3df;
begin
NewtonBodyGetMassMatrix(body, @Mass, @Inertia.x, @Inertia.y, @Inertia.z);

Force := getvector3df(0, -9.8 * Mass, 0); // earth? :)
end;

example app:

thanks hope you can help.

EDIT:
note to mods, there seems to be a glitch in [ code] it keeps adding extra tabs to my code.

Sascha Willems
18-01-2011, 02:39 PM
newtonBody := CreateNewtonBody(nWorld, Collision, @vPosition_.x);

What's behind vPosition_? If it's only a single vector containint the object's position that could be the problem, cause you need to pass a full matrix as the last parameter. And if it doesn't work when passing a matrix make sure the matrix' alignment is same as the alignment newton uses, dunno if Irrlicht uses a different alignment or something. It has to be a correct 4x4 matrix with valid values or troubles will arise.

Other than that I can't see what's wrong cause you're using a lot of Irrlicht-related stuff and datatypes. Maybe offload everything to a separate app without Irrlicht and try it there again. Or get the basic SDL-demo from my page and take a look at it's source code.

Colin
18-01-2011, 03:09 PM
hi thanks, yes i wrote a directx renderer previously in dx9, added newton and it worked just fine, but now i want to implement it into irrlicht... anyways i think i have solved some of the problems, just having a little trouble with inertia now..

Sascha Willems
18-01-2011, 03:27 PM
Just use NewtonConvexCollisionCalculateInertialMatrix, this function can calculate a correct inertial matrix for you and should work better than calculating it yourself.

Colin
18-01-2011, 04:11 PM
aha, thank you very much, that works great, however there is 1 small thing, is there a way to stop them bouncing so much? makes them look unrealistic, even when i set the mass higher, they still bounce around and look unrealistic, once they start falling and rolling, they look ok, but the bouncing is not good.

thanks

Sascha Willems
18-01-2011, 04:48 PM
Just apply different materials to your objects. Lower the material's softness and change elasticity values to get the object to react like it's heavier.

Colin
18-01-2011, 06:48 PM
aha... thank you :), everything now is working absolutly perfect now, thanks alot for the help.

1 other quick question regarding newton 2.29 does it still have procedure to set the freeze threshold ?

-Colin

Sascha Willems
18-01-2011, 08:44 PM
No, it is no longer necessary in Newton 2.x. Back in 1.x you had to do e.g. unfreeze a body manually using unfreeze and/or setting the threshold, but in 2.x the callbacks for transformation are always called as long as enough force is applied onto the body. So basically this functionality is now handled internally and the user is no longer forced to do it.

Colin
18-01-2011, 08:48 PM
aha excellent, thanks again

if u want to check out how i got along, you can test out the box machine gun (lol) press spacebar once, then move and give it a hold, the boxes are newtoncube and the others are convexhull (i know such object should not be created with hull since slower) but was just a test.. tell me how you like it so far.