www.jpct.net

jPCT-AE - a 3d engine for Android => Support => Topic started by: Tishu on September 12, 2011, 01:06:20 pm

Title: Inconsistency in collision detection
Post by: Tishu on September 12, 2011, 01:06:20 pm
Hello

I am using collision detection from a plane to a point using the calcMinDistance method. I use the following code:

Code: [Select]
public double checkLeftGearCollisionDz(double modelDz)
{
final SimpleVector uiDz = new SimpleVector(0, -1, 0);
final float minDist = ground.calcMinDistance(leftGear.getTransformedCenter(), uiDz);
if(!(minDist == Object3D.COLLISION_NONE) && minDist > modelDz) // values are <0
{
return 0;
//return minDist < 0.5 ? 0 : minDist*modelDz;
}
return Object3D.COLLISION_NONE;
}

I place my plane a bit over the ground, and it falls nicely on it. Collision works fine, as I can see in the figues I write in the logs. Then I start rolling forward, and at some point it will fail. The values I pass to the collision detection are consistent though:

Code: [Select]
Z before(22996): 4.150430202484131
dZ tentative(22996): -0.11481471204757691
actual dZ(22996): 0.0

Z before(22996): 4.150430202484131
dZ tentative(22996): -0.10089619320631027
actual dZ(22996): 0.0

Z before(22996): 4.150430202484131
dZ tentative(22996): -0.12035272479057313
actual dZ(22996): 0.0

Z before(22996): 4.150430202484131
dZ tentative(22996): -0.10804409158229827
actual dZ(22996): -0.10804409158229827

Z before is the position of the plane before calcMinDistance. This remains constant. On each frame I try to move the plane by dZ tentative and check if this makes it collide with the ground. If yes, I use 0 for actual dZ.
On the last frame, my Z before has not changed, the dZ tentative is a value I have tried before, but calcMinDistance returns Object3D.COLLISION_NONE and actual dZ is non zero -> the plane goes trough the ground.

I have taken a look at this thread
http://www.jpct.net/forum2/index.php/topic,1376.msg9655.html#msg9655 (http://www.jpct.net/forum2/index.php/topic,1376.msg9655.html#msg9655)
I increased the value of collideOffset to 500 with no success (even tried 5000, made no difference)

I also saw this one
http://www.jpct.net/forum2/index.php/topic,335.msg1825.html#msg1825 (http://www.jpct.net/forum2/index.php/topic,335.msg1825.html#msg1825)
And I tried using an octree:

Code: [Select]
final Object3D world = loadGround(is, 1);
world.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
final OcTree o = new OcTree(world, 100, OcTree.MODE_OPTIMIZED);
o.setCollisionUse(OcTree.COLLISION_USE);
world.setOcTree(o);     
world.setCollisionOptimization(Object3D.COLLISION_DETECTION_OPTIMIZED);
r.ground = world;

Tried difference values for the maxPoly. I get a StackOverFlowException for values <100, and no difference in collision detection for values >100.

It seems to me that there is an area in the ground where collision just won't happen.

Thx
Nicolas
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on September 12, 2011, 01:20:35 pm
What is modelDz? I'm a bit puzzled about this "minDist > modelDz"-condition...have you checked the actual return value of calcMinDistance in the case that has the problem? I would be interested if the method itself returns "no collision" or if you "invent" this with this condition in your code!?
Title: Re: Inconsistency in collision detection
Post by: Tishu on September 12, 2011, 01:30:14 pm
It does return COLLISION_NONE.

modelDz is how much the model would like the plane to move. I check how much I can move in that direction (minDist, which should rather be called maxDz), and I can move less that what the model wants to move, I stay still Z-axis wise.

I really think there is like  a "hole" in the ground, as no matter how I approach it, it goes trough the floor at the same place.

Thx
Nic
Title: Re: Inconsistency in collision detection
Post by: Tishu on September 12, 2011, 01:38:54 pm
To illustrate this, rolling always is fine until I get to the point on the picture below. I can see the end of a face (with the texture being discontinuous) and when I get to the next one, I fall through it.

(http://www.freeimagehosting.net/t/24ce2.jpg) (http://www.freeimagehosting.net/24ce2)
Title: Re: Inconsistency in collision detection
Post by: Tishu on September 12, 2011, 02:32:30 pm
It seems that the sign of the return value of calcMinDistance is dictated by the direction of the normal of my plane. I fixed the normals in Blender and it works good now.

Thx
Nic

Edit: Correction before I'm told off by EgonOlsen :), if does not just dictate the sign of the return value, it seems to dictate the direction where it moves for collision detection, hence sometimes I got COLLISION_NONE as it was moving in the opposite direction
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on September 12, 2011, 02:57:30 pm
 ??? I'm not doing anything with the normals from any model in jPCT. Or was culling disabled on the model? In that case, you will create holes for the collision detection on all faces that would otherwise be culled, because collision detection doesn't happen on back faces.
Title: Re: Inconsistency in collision detection
Post by: Tishu on September 12, 2011, 03:12:58 pm
That makes completely sense - culling was disabled. I've reenabled it now after sorting the normals. All behave well.

Thx
Nic
Title: Re: Inconsistency in collision detection
Post by: Tishu on September 15, 2011, 09:49:02 pm
Actually I still think the behaviour is weird. I've turned culling back off:

Code: [Select]
plane.setCulling(Object3D.CULLING_DISABLED);
ground.setCulling(Object3D.CULLING_DISABLED);
sky.setCulling(Object3D.CULLING_DISABLED);

Now the code works fine when I check if the plane can move downwards (y and z are flipped):

Code: [Select]
final SimpleVector uiDz = new SimpleVector(0, 1, 0);
final float minDist = ground.calcMinDistance(plane.getTransformedCenter(), uiDz);

minDist takes correct values. Now I want to know if the plane has gone underground, I assume I just have to flip the "direction" vector.

Code: [Select]
final SimpleVector uiDz = new SimpleVector(0, -1, 0);
final float minDist = ground.calcMinDistance(plane.getTransformedCenter(), uiDz);

Issue is this always returns COLLISION_NONE, even when I go trough the ground.

Nic
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on September 15, 2011, 09:56:10 pm
I can't see anything weird here...unless i misunderstood something. You can't check for collisions with the backfaces of polygons in jPCT, not matter if you enable or disable culling.
Title: Re: Inconsistency in collision detection
Post by: Tishu on September 15, 2011, 10:05:03 pm
Ok sorry I just misunderstood the following (or rather misread)

Quote
Or was culling disabled on the model? In that case, you will create holes for the collision detection on all faces that would otherwise be culled, because collision detection doesn't happen on back faces.

Thx
Nicolas
Title: Re: Inconsistency in collision detection
Post by: Tishu on September 15, 2011, 10:10:07 pm
Any chance we get that supported in a future version? I agree it should be disabled by default, but could be useful in some cases to be able to enable it.

Nic
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on September 15, 2011, 10:34:46 pm
Not very likely. The algorithms used for collision detection can't handle this case ATM and franky speaking, i don't much need to change them just for that. If you want to detect this case, you have other options. For example, you could offset plane.getTransformedCenter() by some value like (0,-5,0), so it's above the ground for sure and then do a collision detection with (0,1,0). If the result is lower than your offset (in this case 5), the plane is below the ground....something like that.
Title: Re: Inconsistency in collision detection
Post by: K24A3 on September 23, 2011, 10:52:03 am
I'm  having a bit of difficulty placing an Object3D (an MD2 character) on the ground. I got it working, but the character ends up too high off the ground, so I hack the offset by 20.

The ground is an Object3D plane created with Primitives and modified by a VertexController
terrain = Primitives.getPlane(50, 50);
terrain.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);


On every frame I call this function:

Code: [Select]
private void ObjectToGround(Object3D object)
{
SimpleVector sv = new SimpleVector();

// Get object position
sv = object.getTranslation();

// Determine height above terrain
float terrHeight = terrain.calcMinDistance(sv, new SimpleVector(0,1,0));
if(terrHeight == Object3D.COLLISION_NONE)
{
//Log.v(TAG, "COLLISION_NONE" );
}
else
{
//sv.scalarMul(terrHeight); // object goes underground
terrHeight -= 20; // Hack offset
sv.set(0, terrHeight, 0);
character.translate(sv);

}
}


My question is, how do you determine the height or bottom of the 3D Object and place it on the ground properly without hacking the value?


Do I need to use the ellipse method?

Or scale the value returned by calcMinDistance() to the world scale?

Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on September 23, 2011, 05:56:54 pm
None of the collision detection method has any information about the size of the object that collides. If you don't want to use magic numbers for this, you might want to get the bounding box from the Mesh and calculate the needed values from that.
Title: Re: Inconsistency in collision detection
Post by: K24A3 on September 23, 2011, 06:09:54 pm
I see, ok I may just stay with magic numbers if that's the normal way of doing it.
Title: Re: Inconsistency in collision detection
Post by: K24A3 on December 03, 2011, 09:43:02 am
I'm attempting to use the bounding box to get the magic number but not sure how to calculate it.

// Get mesh
Mesh mesh = object.getMesh();
      
// Get Bounding Box
float[] fBounds = mesh.getBoundingBox();   


The fBounds[2] value is -135f, and the fBounds[3] value is 87f. Object3D.getCenter() is 0,0,0

The magic value is supposed to be -35 (where the lowest polygon touches the terrain). How do I get -35 from -135f and 87f?


// I use this code to calculate and translate the object to the ground
sv = object.getTranslation();
float terrHeight = terrain.calcMinDistance(sv, new SimpleVector(0,1,0));
terrHeight += magicNumber;
sv.set(0, terrHeight, 0);
object.translate(sv);   
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on December 03, 2011, 08:18:02 pm
Hard to tell from your code because your translations add up. You'll end up in a situation, where -calcMinDistance equals your magic number, won't you? I used to do this different: I use a fixed height which is guaranteed to be always above the ground, calculate the distance and apply the offset to that value. Personally, i can understand this approach much better than yours. I'm not even sure if yours works at all...then again, i'm feeling a little sick today, so my thinking is slow... ;)
Title: Re: Inconsistency in collision detection
Post by: K24A3 on December 04, 2011, 02:17:09 am
Quote
I use a fixed height which is guaranteed to be always above the ground, calculate the distance and apply the offset to that value.

That is how I am doing it but I needed to manually supply the offset. The problem is that I have multiple instances of the object with different scales, so the offset is different each time.

Code: [Select]
private void ObjectToGround(Object3D object, float nYOffset)
{
if(terrain==null) return;

SimpleVector sv = new SimpleVector();

// Make sure object is above the terrain
object.translate(0, -200, 0);

// Get object position
sv.set(object.getTranslation());

// Determine height above terrain
float terrHeight = terrain.calcMinDistance(sv, new SimpleVector(0,1,0));
if(terrHeight == Object3D.COLLISION_NONE)
{
//Log.v(TAG, "COLLISION_NONE" );
// Drop back down
object.translate(0, 200, 0);
}
else
{
Log.v(TAG, "COLLISION terrHeight = "+terrHeight );
if(terrHeight>1000)  {object.translate(0, 200, 0); return;}
terrHeight += nYOffset;
sv.set(0, terrHeight, 0);
object.translate(sv);
}
}

And here's my current attempt to automatically get the offset, assuming calcMinDistance is based on the center of the object rather than the bounding box.
Code: [Select]
private void ObjectToGroundAuto(Object3D object)
{
if(terrain==null) return;

float fAutoOffset  = 0;


// Get mesh
Mesh mesh = object.getMesh();

// Get Bounding Box
float[] fBounds = mesh.getBoundingBox();

// Get the middle of the bounds
float fMid = fBounds[3] - fBounds[2];


fAutoOffset = fMid / 2; //(fMid * object.getScale()); // Always 1.0

Log.v(TAG,"fBounds2 = "+fBounds[2]+"  fBounds3 = "+fBounds[3]+" fMid="+fMid+" fAutoOffset="+fAutoOffset+" scale="+object.getScale());

Log.v(TAG,"Center = "+object.getCenter()); // Always 0,0,0 if calcCenter() is not called.

// Ground 
ObjectToGround(object, -fAutoOffset);
}

Are you able to show the code in the function calcMinDistance()? I'd like to see how the starting point of the object is calculated.
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on December 04, 2011, 08:49:33 pm
The starting point is the center in world space. However, you don't have to use this variant. You can use the methods in World if you want to set the starting point yourself. Keep in mind that scaling doesn't affect the bounding box, i.e. you have to apply a scale to the values yourself to get the actual values in world space.
Title: Re: Inconsistency in collision detection
Post by: K24A3 on December 04, 2011, 11:37:15 pm
Sorry I meant the starting point of the collision detection, does calcMinDistance start measuring from the exact center of the object? Or does it start from the closest polygon?
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on December 05, 2011, 09:49:53 am
No, from the center.
Title: Re: Inconsistency in collision detection
Post by: K24A3 on December 05, 2011, 11:44:06 am
Ok so theoretically if the center is 0,0,0,  the lower value of the meshes bounding box should be the offset. I tried that but I'm still needing a corrective offset.

I can't seem to figure out a trending value to use. I'm guessing that calcBoundingBox() is not calculating the boundary exactly at the lowest vertex for performance reasons perhaps.


OBJECT 1
--------
Scale = 40f
Center = 0,0,0
LowerBoundingBox = -77
UpperBoundingBox = 50
Wants Offset = -10
Mesh BoundingBox 0 = -62.069466 1=51.452503 2=-33.44815 3=9.098154 4=-78.36731 5=49.07093

Scale = 80f
Center = 0,0,0
LowerBoundingBox = -67
UpperBoundingBox = 18
Wants Offset = -20
Mesh BoundingBox 0 = -124.13893 1=102.90501 2=-66.8963 3=18.196308 4=-156.73462 5=98.14186



OBJECT 2
--------
Scale = 95f
Center = 0,0,0
LowerBoundingBox = -550
UpperBoundingBox = -9
Wants Offset = 10
Mesh BoundingBox 0 = -80.026985 1=96.586525 2=-550.9481 3=-9.235985 4=-89.274704 5=144.33151

Scale = 35f
Center = 0,0,0
LowerBoundingBox = -202
UpperBoundingBox = -3.4
Wants Offset = 5
Mesh BoundingBox 0 = -29.483627 1=35.58451 2=-202.98088 3=-3.4027314 4=-32.890682 5=53.17477



By the way, there is no scaling being done loading the 3D file, there are no axis rotations (all objects point up natively), there are no animations.

obj = Object3D.mergeAll(Loader.load3DS(myContext.getResources().openRawResource(R.raw.obj7), 40f));
//obj.calcCenter();
//obj.getMesh().compress();
obj.calcBoundingBox();
obj.setTexture("obj7tex");
obj.setSpecularLighting(true);
obj.compile();
//obj.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
world.addObject(obj);
obj.translate(mainArea.getRandomPos());
ObjectToGroundAuto(obj);

The offset seems to follow the scale so I may just calculate the offset manually at scale 100f, then scale that master offset in ratio when scaling the cloned objects.
Title: Re: Inconsistency in collision detection
Post by: EgonOlsen on December 05, 2011, 02:27:19 pm
The center is (0,0,0) only because you don't calculate it. It will be calculated anyway when the object is rendered for the first time, so your distance calculations work with a different center than (0,0,0). Maybe you should calculate the center before...just call build() on the object after loading and remove all other calcXXX-methods, because build() already calls them. The bounding box actually calculates the exact, axis-aligned bounds in object space.
Title: Re: Inconsistency in collision detection
Post by: K24A3 on December 06, 2011, 08:09:41 am
It appears to be working now after your suggestions, all three different objects completely sit flush on the ground. The offset is incorrect if I clone and rescale the objects, but I can take care of that  (I'll just scale the offset accordingly).

Here's the code if anyone is wandering:

Mesh mesh = object.getMesh();
float[] fBounds = mesh.getBoundingBox();      
fAutoOffset = -fBounds[3];
ObjectToGround(object, fAutoOffset);


Appreciate the help, thanks :)