Ground clamping through calcMinDistance with .obj's help

Started by AugTech, February 08, 2013, 07:33:19 PM

Previous topic - Next topic

AugTech

Hi all !
I'm trying to implement two things at the moment, and after three days its still driving me nuts! >:(

Firstly, and most importantly, I'm trying to automatically 'clamp' objects to the ground....yes that old chestnut! I've read many a post here, but I just can't get a catch all that works for .obj models and in-built primitives (like a cube, which I seem to have fixed now incidentally)

In the app I either create a primitive, such as a cube, or load an .obj model and then add it to the scene through the following method;


public void addObjectsToWorld(A_Object3D[] objects) {

if (objects==null || sceneOrientation==null) return;
SimpleVector frontAxis = sceneOrientation.front.normalize();
SimpleVector upAxis = sceneOrientation.up.normalize();

// Align our object axis to the ECEF axis
for (A_Object3D obj : objects) {
if (obj.requiresOrientation) {
obj.setOrientation(frontAxis, upAxis);
}
obj.applyStyleRotations();
obj.build();
}

// Add...
theWorld.addObjects(objects);

// Now clamp objects to the floor if flagged to do so...
SimpleVector trans = new SimpleVector();

for (A_Object3D obj : objects) {
if (!obj.clampToGround) continue;

float dist = plane.calcMinDistance( obj.getTransformedCenter(), upAxis );

// Move object above plane by 20m and try again
if (dist==Object3D.COLLISION_NONE) {
trans.set( upAxis );
trans.scalarMul( -20f );
obj.translate( trans );

dist = plane.calcMinDistance( obj.getTransformedCenter(), upAxis );

// Couldn't collide, move to original position
if (dist==Object3D.COLLISION_NONE) {
trans.set( upAxis );
trans.scalarMul( 20f );
obj.translate( trans );
}
}

// Do the clamping...
if (dist!=Object3D.COLLISION_NONE) {
float htAdjust = obj.isPlane ? 0f : -obj.getMesh().getBoundingBox()[3];

Log.i(LOG_TAG, "Obj: "+obj.getParentFeatureID()+" Dist: "+(dist+htAdjust));
trans.set( upAxis );
trans.scalarMul( dist-obj.heightOffset+htAdjust );

// (paulscode) Grab a handle to the Object3D's world transformation matrix:
Matrix m = new Matrix( obj.getWorldTransformation() );
// Turn that into a rotation matrix:
float[] dm = m.getDump();
for( int i = 12; i < 15; i++ ) dm[i] = 0;
dm[15] = 1;
m.setDump( dm );
// Apply this rotation matrix to the translation vector:
trans.matMul( m );

obj.translate( trans );
}
}


The plane object is a transparent plane sat 2m below the camera position.
Adding additional planes (map tiles) through the above method works; adding cubes works, but .obj models (and an arrow which I'll get to in the minute) does not. The links should hopefully illustrate;

Screen1: Primitive models sat on ground, but .obj model floating


Screen2: Model the same size and axis alignment, but sat below plane (the rotating arrow is sat below the overlay).



It should be noted that the models (not mine!) are exported from Sketch-up with the swap YZ axis option enabled. To then align the axis to jPCT I use the following;


if (shapeName.endsWith(".obj") || shapeName.endsWith(".3ds")) {
ret = getShapeFromAssets(shapeName);
/* jPCT axis are rotated 180 around X axis,
* contrary to most graphics systems, so we rotate and then
* replace the matrix so this rotation is ignored in later
* translations and rotations */
ret.obj.rotateZ(PI);// Why Z, not X ??? (Is Z so North is aligned)
ret.obj.rotateMesh();
ret.obj.setRotationMatrix( new Matrix() );
ret.obj.getMesh().setLocked(true);
}


I can seem to get a decent value from calcMinDistance, one model is 0.09m, whereas the other is 19.4m. ??

As a secondary issue, I'm trying display an arrow permanently in front of the camera, at a fixed distance, but also clamped to the ground. I suspect a very similar problem as, again, the arrow is loaded from an .obj, added to as a child to a dummyObject at the camera position and then translated to be in front of the camera. With the arrow being 8m in front of the camera, calcMinDistance is returning 6.9 metres from the plane!!??

Many, many thanks to the person who tells me what stupid thing I'm doing!

[attachment deleted by admin]

EgonOlsen

I'm not sure about the actual problem here. The code somehow confuses me ATM, so i'll try a shot in the dark: You are using the bounding box...but the bounding box is in object space. If you've rotated or translated the model, this won't give you the results you want. Try to use something like this instead to get the coordinates in world space: http://www.jpct.net/wiki/index.php/Getting_Worldspace_Bounds

AugTech

Egon, I tried the getWorldBounds() method and get slightly different numbers/ distances, but the objects still translate in odd directions.

This, plus some sleep has made me realise (hopefully) the root of all my evil...
The objects are getting checked for distance on the arbitrary axis I'm providing (sceneOrientation.up), but are still being translated on the world axis (or possibly standard object axis), not the axis I'm providing.

Is it possibly to rotate the world axis? - I'll tell you why!

The sceneOrientation.up and sceneOrientation.front vectors define the orientation of the axis for all objects within the world, with the world camera orientation being set constantly through two similar/ relative vectors, so that the user POV is aligned with the ground within the world. But these axis are not static, they are created dynamically on top of a sphere (the world).
My world space is the green square in this diagram;

So I either need to translate objects according to these arbitrary axis, or rotate and lock the world axis so all objects obey them... Does this make sense?!  :-\

EgonOlsen

Then why don't you simply translate them a long the axis you are using for the distance check?

AugTech

Thats actually what I thought I was doing with;


trans.set( upAxis );
trans.scalarMul( -20f );//Distance to move
obj.translate( trans );


Would the translation vector have to added/ multiplied by the object axis?

EgonOlsen

I'm confused about your actual problem...let us take one step back: You have some object, so calculate the distance to some plane in some direction. You then multiple the nornalized direction vector with that distance and do the translation with the result...why isn't that correct and what does it have to do with the code you've posted that translates by 20 fixed units?

AugTech

Ok, my apologise, the -20 confused things. Replace the -20 with the value I'm getting from calcMinDistance

So;


SimpleVector upAxis = sceneOrientation.up.normalize();
SimpleVector frontAxis = sceneOrientation.front.normalize();
SimpleVector trans = new SimpleVector();

obj.setOrientation(frontAxis, upAxis);
obj.build();
theWorld.addObject( obj );

float dist = plane.calcMinDistance( obj.getTransformedCenter(), upAxis );
trans.set( upAxis );
trans.scalarMul( dist );
obj.translate( trans );


results in objects being translated in different directions

AugTech

Hold on... Am just working through more methodically and it appears my maths is crap!
I think the additional confusion is that child translations are 'forgotten' when the parent is translated - could you just confirm this Egon?

EgonOlsen

Forgotten by your math or forgotten by the engine? If a parent is translated, its children will be translated by the same amount...if that's what you mean.

AugTech

I mean, if a child has been translated by 20m on Y, then the parent get translated by 10 on X, does the child forget the previous 20m on Y?

AugTech


interDist = plane.calcMinDistance( obj.getTransformedCenter(), upAxis );

if (interDist==Object3D.COLLISION_NONE) {
// translate -20 and re-test
}

if(!obj.isPlane) {
bbox = getWorldSpaceBounds(obj);
objHeight = bbox[3]-bbox[2];
}
// Do the clamping...
if (interDist!=Object3D.COLLISION_NONE) {
if(!obj.isPlane) {
Log.i(LOG_TAG, "Obj: "+obj.getParentFeatureID()+" Dist: "+interDist+" Height: "+objHeight/2);
}
trans.set( upAxis );
trans.scalarMul( interDist-obj.heightOffset-(objHeight/2) );
obj.translate( trans );
}


appears to sort all the models except one; this one reports an incorrect bounding box (a height of 16.8m instead of 10m), therefore the adjustment back to ground level is out.

EgonOlsen

Quote from: AugTech on February 09, 2013, 04:14:15 PM
I mean, if a child has been translated by 20m on Y, then the parent get translated by 10 on X, does the child forget the previous 20m on Y?
No, why should it?

EgonOlsen

Quote from: AugTech on February 09, 2013, 04:50:07 PM
appears to sort all the models except one; this one reports an incorrect bounding box (a height of 16.8m instead of 10m), therefore the adjustment back to ground level is out.
The bb is calculated based on the vertices in the object. It doesn't take into account if these vertices are actually used in the model. Maybe some forgotten vertex is still part of the model enlarging its bb.

AugTech

I'll certainly check that out stray vertices...

QuoteNo, why should it?
I wasn't suggesting it should  ;) just wanted to check why I can't get my child item to follow the parent, whilst remaining clamped to the ground. I'm setting the child on the ground, but when the parent is moved the child gets translated off in another direction.

EgonOlsen

Quote from: AugTech on February 09, 2013, 07:15:33 PM
I'm setting the child on the ground, but when the parent is moved the child gets translated off in another direction.
Might be caused by additional rotations that you apply to the child. It can get really complicated to understand why something behaves as it does when child/parent relations in combination with rotations come into play. Maybe you can make all rotations permanent by using rotateMesh()/clearRotation() after rotating them into the correct positions. That should ease things a little.