Problem matching material on geometry when adding to a node for picking

I’m loading a terrain as a OGRE mesh file, applying an image to it, and creating a box (with the monkey logo on it) and I try to add these things to a Node called “shootables” like in the picking example, however, the material doesn’t match up with the debug shapes. I thought I was following the Picking example pretty closely, but it isn’t seeming to work. The code is below. If you see any blatant problems, please let me know.



[java] public class TestPhysicsCar extends SimpleBulletApplication implements ActionListener {



private float steeringValue = 0;

private float accelerationValue = 0;

private PhysicsVehicleNode player;

private final float accelerationForce = 10f;//was 1000.0f;

private final float brakeForce = 1.0f;//was 100.0f

private Vector3f jumpForce = new Vector3f(0, 3000, 0);

Vector3f north3f = new Vector3f(worldMax.x, 0, 0);

Vector2f north2f = new Vector2f();

Vector3f car3f = new Vector3f();

Vector2f car2f = new Vector2f();



Node shootables;



public static void main(String[] args) {

TestPhysicsCar app = new TestPhysicsCar();

app.start();

}



private void setupKeys() {

inputManager.addMapping(“Lefts”, new KeyTrigger(KeyInput.KEY_H));

inputManager.addMapping(“Rights”, new KeyTrigger(KeyInput.KEY_K));

inputManager.addMapping(“Ups”, new KeyTrigger(KeyInput.KEY_U));

inputManager.addMapping(“Downs”, new KeyTrigger(KeyInput.KEY_J));

inputManager.addMapping(“Space”, new KeyTrigger(KeyInput.KEY_SPACE));

inputManager.addMapping(“Reset”, new KeyTrigger(KeyInput.KEY_RETURN));

inputManager.addListener(this, “Lefts”);

inputManager.addListener(this, “Rights”);

inputManager.addListener(this, “Ups”);

inputManager.addListener(this, “Downs”);

inputManager.addListener(this, “Space”);

inputManager.addListener(this, “Reset”);



}

private AnalogListener analogListener = new AnalogListener() {



public void onAnalog(String name, float value, float tpf) {



if (name.equals(“Left”)) {

player.steer(.5f);

//player.rotate(0, valuespeed, 0);

}

if (name.equals(“Right”)) {

player.steer(-.5f);

}

if (name.equals(“Up”)) {

player.accelerate(-300f * value); //was 300f, which caused robot to drive backwards

System.out.println(“accel”);

}

if (name.equals(“Downs”)) {

System.out.println(“brake”);

player.brake(60f * value);

}

}

};



public void onPreUpdate(float tpf) {

player.accelerate(0);

player.brake(0);

player.steer(0);

}



public void onPostUpdate(float tpf) {

}



@Override

public void simpleInitApp() {

setupKeys();

// setupFloor();

loadHintText();

buildPlayer();

//makeBox();



shootables = new Node(“Shootables”);

// rootNode.attachChild(shootables);

shootables.attachChild(setupFloor());

shootables.attachChild(makeBox());



}



public Geometry setupFloor() {

Material mat = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);



/

  • http://www.jmonkeyengine.com/forum/index.php?topic=14248.0

    *
  • This sets the assetManager’s path to the folder just above
  • the base of this project (the netbeans project folder)

    /



    assetManager.registerLocator("…/", FileLocator.class.getName());



    //For some reason, you can’t have “…/” here so I did it above.

    TextureKey key = new TextureKey(“dependencies/1280783806_1_GEI8.jpg”);

    key.setGenerateMips(true); //no clue wtf this does.

    Texture tex = assetManager.loadTexture(key);

    tex.setMinFilter(Texture.MinFilter.Trilinear);

    mat.setTexture(“m_ColorMap”, tex);





    /

  • Loads and OGRE MESH file

    /

    // create the geometry and attach it

    assetManager.registerLocator("…/", FileLocator.class.getName());

    Spatial terrain = assetManager.loadModel(“dependencies/terrain2.mesh.xml”);





    terrain.setLocalTranslation(0f, -4f, 0f);

    rootNode.attachChild(terrain);



    Geometry floorGeom = findGeom(terrain, “”);



    Box floor = new Box(Vector3f.ZERO, 100, 1f, 100);

    // Geometry floorGeom = new Geometry(“Floor”, floor);

    floorGeom.setMaterial(mat);

    floorGeom.updateModelBound();



    MeshCollisionShape groundCollisionShape = new MeshCollisionShape(floorGeom.getMesh());



    PhysicsNode tb = new PhysicsNode(floorGeom, groundCollisionShape, 0);

    tb.setLocalTranslation(new Vector3f(0f, -6, 0f));

    tb.updateModelBound();

    tb.updateGeometricState();

    getPhysicsSpace().add(tb);

    tb.setName(“Floor (tb)”);

    tb.attachDebugShape(assetManager);

    tb.setFriction(100000f);

    tb.updatePhysicsState();

    tb.updateModelBound();

    rootNode.attachChild(tb);



    return floorGeom;



    }



    private Geometry makeBox() {

    /


    *creates an obstacle box

    /

    Material mat1 = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);

    TextureKey key1 = new TextureKey(“Interface/Logo/Monkey.jpg”, true);

    key1.setGenerateMips(true);

    Texture tex1 = assetManager.loadTexture(key1);

    tex1.setMinFilter(Texture.MinFilter.Trilinear);

    mat1.setTexture(“m_ColorMap”, tex1);

    Box boxGeom = new Box(Vector3f.ZERO, 1f, 1f, 1f);

    BoxCollisionShape shape = new BoxCollisionShape(new Vector3f(1, 1, 1));

    // Add some phyisics boxes higher up, to fall down and be tracked.

    Geometry geom0 = new Geometry(“box”, boxGeom);

    geom0.setMaterial(mat1);

    PhysicsNode physicsBox = new PhysicsNode(geom0, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1);

    physicsBox.setName(“box0”);

    physicsBox.setFriction(0.1f);

    physicsBox.setLocalTranslation(new Vector3f(0f, 0f, -15f));

    physicsBox.updateGeometricState();

    physicsBox.updateModelBound();



    physicsBox.attachDebugShape(assetManager);



    rootNode.attachChild(physicsBox);

    getPhysicsSpace().add(physicsBox);

    return geom0;

    }





    private void buildPlayer() {

    /

  • Original values

    /

    float r = 0.6f;

    float mass = 10;//400 for sports car



    Material matBox = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);

    TextureKey keyBox = new TextureKey(“Models/Sign Post/Sign Post.jpg”, true);

    keyBox.setGenerateMips(true);

    Texture texBox = assetManager.loadTexture(keyBox);

    matBox.setTexture(“m_ColorMap”, texBox);

    Material mat = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);

    TextureKey key = new TextureKey(“Interface/Logo/Monkey.jpg”, true);

    key.setGenerateMips(true);

    Texture tex = assetManager.loadTexture(key);

    mat.setTexture(“m_ColorMap”, tex);



    // box stand in

    Vector3f BoxHalfExtents = new Vector3f(0.5f, 0.5f, 2f);

    Vector3f NegBoxHalfExtents = new Vector3f(BoxHalfExtents);

    NegBoxHalfExtents.negateLocal();

    //System.out.println("Box = " +BoxHalfExtents + "t NegBox= "+ NegBoxHalfExtents);



    Box b = new Box(NegBoxHalfExtents, BoxHalfExtents);

    Geometry g = new Geometry(“Box”, b);

    g.setMaterial(matBox);

    player = new PhysicsVehicleNode(g, new BoxCollisionShape(new Vector3f(0.5f, 0.5f, 2f)), mass);



    //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0

    //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0

    // CompoundCollisionShape compoundShape = new CompoundCollisionShape();

    BoxCollisionShape box = new BoxCollisionShape(new Vector3f(BoxHalfExtents)); //

    // compoundShape.addChildShape(box, new Vector3f(0, 1, 0));



    //g.setLocalTranslation(0,1,0);

    //create vehicle node

    // player = new PhysicsVehicleNode(g, box, mass);



    player = new PhysicsVehicleNode(g, box, mass);

    player.setName(“Vehicle”);



    //setting suspension values for wheels, this can be a bit tricky

    //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en

    float stiffness = 60.0f;//200=f1 car

    float compValue = 0.3f; //(should be lower than damp)

    float dampValue = 0.4f;

    player.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));

    player.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));

    player.setSuspensionStiffness(stiffness);

    player.setMaxSuspensionForce(10000.0f);

    player.setFrictionSlip(100000f);



    //Create four wheels and add them at their locations

    Vector3f wheelDirection = new Vector3f(0, -1, 0); // was 0, -1, 0

    Vector3f wheelAxle = new Vector3f(-1, 0, 0); // was -1, 0, 0



    Cylinder wheelMesh = new Cylinder(16, 16, r, r * 0.6f, true);



    //Front passeneger side wheel

    Node node1 = new Node(“wheel 1 node”);

    Geometry wheels1 = new Geometry(“wheel 1”, wheelMesh);

    node1.attachChild(wheels1);

    wheels1.rotate(0, FastMath.HALF_PI, 0);

    wheels1.setMaterial(mat);

    player.addWheel(node1, new Vector3f(-1f, -0.5f, -2f), //-1f, -0.5f, 2f

    wheelDirection, wheelAxle, 0.2f, r, true);



    // Front Driver side wheel

    Node node2 = new Node(“wheel 2 node”);

    Geometry wheels2 = new Geometry(“wheel 2”, wheelMesh);

    node2.attachChild(wheels2);

    wheels2.rotate(0, FastMath.HALF_PI, 0);

    wheels2.setMaterial(mat);

    player.addWheel(node2, new Vector3f(1f, -0.5f, -2f),//1f, -0.5f, 2f

    wheelDirection, wheelAxle, 0.2f, r, true);



    //Rear passenger side wheel

    Node node3 = new Node(“wheel 3 node”);

    Geometry wheels3 = new Geometry(“wheel 3”, wheelMesh);

    node3.attachChild(wheels3);

    wheels3.rotate(0, FastMath.HALF_PI, 0);

    wheels3.setMaterial(matBox);

    player.addWheel(node3, new Vector3f(-1f, -0.5f, 2f),//-1f, -0.5f, -2f

    wheelDirection, wheelAxle, 0.2f, r, false);



    //Rear Driver’s side wheel

    Node node4 = new Node(“wheel 4 node”);

    Geometry wheels4 = new Geometry(“wheel 4”, wheelMesh);

    node4.attachChild(wheels4);

    wheels4.rotate(0, FastMath.HALF_PI, 0);

    wheels4.setMaterial(matBox);

    player.addWheel(node4, new Vector3f(1f, -0.5f, 2f),//1f, -0.5f, -2f

    wheelDirection, wheelAxle, 0.2f, r, false);



    player.setRollInfluence(0, 0.25f);

    player.setRollInfluence(1, 0.25f);

    player.setRollInfluence(2, 0.25f);

    player.setRollInfluence(3, 0.25f);



    player.updateModelBound();

    player.attachDebugShape(assetManager);



    /

  • After everything has been added to the vehicle, then you can add it to the physics space
  • Or you could likely call an update on the player’s physics player.updatePhysicsState();

    */

    getPhysicsSpace().add(player);

    rootNode.attachChild(player);



    }



    } [/java]

What do you mean by “the material doesn’t match up with the debug shapes”?

Well, it doesn’t seem to follow the debug shapes when they move, either by interaction with another object in the world or by setting the localTranslation. The screenshot below shows a box (the logo covered render is at 0,0,0 even though the debug box is translated to (0f, 0f, -15f), then has fallen to the ground below once gravity was turned on) and a mesh terrain I’ve loaded. The terrain is set for a local translation of (0,-6,0).





Now, if I don’t add the geometries to the shootables Node and simply call them by themselves (calling just setupFloor(); and makeBox();), it works right. But when I add them to shootables, I get the problem shown above. Now if I don’t add shootables to the rootNode, then only the debug shapes show on the screen, and not the materials at all.



[java] @Override

public void simpleInitApp() {

setupKeys();

// setupFloor();

loadHintText();

buildPlayer();

//makeBox();



shootables = new Node(“Shootables”);

rootNode.attachChild(shootables);

shootables.attachChild(setupFloor());

shootables.attachChild(makeBox());



}[/java]

Its because the base Geometries you use to create the collision shapes have a local translation, so that is reflected in the CollisionShape. Try just loading your model and using the CollisionShapeFactory on the root Node of the model.

Is there an example somewhere of how to use the CollisionShapeFactory? I can’t seem to find info about how to use it.

The javadoc explains each method… Its just a helper to create CollisionShape objects, you can also create them by hand.

When I attempt to replace [java]MeshCollisionShape groundCollisionShape = new MeshCollisionShape(floorGeom.getMesh());[/java] with the CollisionShapeFactory code [java] CollisionShape groundCollisionShape = CollisionShapeFactory.createMeshShape(floorGeom);[/java]



I get the error:

“Incompatible types.

Required com.bulletphysics.collsision.shapes.CopllisionShape

Found: com.jme3.bullet.collision.shapes.CollisionShape”



What am I doing wrong here?



Here is the relavent code:

[java]// create the geometry and attach it

assetManager.registerLocator("…/", FileLocator.class.getName());

Spatial terrain = assetManager.loadModel(“dependencies/terrain2.mesh.xml”);



//terrain.setLocalTranslation(0f, -4f, 0f);

rootNode.attachChild(terrain);

Geometry floorGeom = findGeom(terrain, “”);



Box floor = new Box(Vector3f.ZERO, 100, 1f, 100);

// Geometry floorGeom = new Geometry(“Floor”, floor);

floorGeom.setMaterial(mat);

floorGeom.updateModelBound();



// MeshCollisionShape groundCollisionShape = new MeshCollisionShape(floorGeom.getMesh());

CollisionShape groundCollisionShape = CollisionShapeFactory.createMeshShape(floorGeom);

[/java]

You import the wrong CollisionShape class.

ok, this is weird. I don’t have the jme collisionShapes import at all in my code, and I do have the bullet import. The bullet import is throwing a warning that it is unused. I’m also getting an error at the line: [java] CollisionShape groundCollisionShape = CollisionShapeFactory.createMeshShape(floorGeom);[/java]



When I click the error icon, it still says the same error as before:

“Incompatible types.

Required com.bulletphysics.collsision.shapes.CopllisionShape

Found: com.jme3.bullet.collision.shapes.CollisionShape”



But now I have options to “Change the type of groundCollisionShape to CollisionShape”



When I do this, it changes that line to the following:



[java] com.jme3.bullet.collision.shapes.CollisionShape groundCollisionShape = CollisionShapeFactory.createMeshShape(floorGeom);

[/java]



This compiles and runs, but still does nothing to fix my problem. I still get the exact screen as the screenshot above.



Am I just not allowed to translate the model of the ground? Again, All I am trying to do is add this all to the “shootables” node for picking. The ground load fine if I call the method alone, but trying to add the geometry to the shootables Node messes everything up. It doesn’t make sense to me that attaching the model to a node changes properties of that model that have already been set.

Its because the base Geometries you use to create the collision shapes have a local translation, so that is reflected in the CollisionShape. Try just loading your model and using the CollisionShapeFactory on the root Node of the model:

[java]

Node myTerrain=(Node)assetManager.loadModel(“myModel”);

CollisionShapeFactory.createMeshShape(myTerrain);

[/java]

Atm you detach the original Geometry from its node, create a collision shape from it and then attach/move it somewhere else, that produces the wrong location of the CollisionShape. Try to understand the concept of nodes, child spatials/geometries and local translation. The “main” node should be the PhysicsNode, it has the CollisionShape which does not move, then you attach the geometry to the terrain so that it fits the CollisionShape. The CollisionShapeGenerator just creates a collision shape from what you give it. If the geometries of the node you give it are off the collision shape will be off.

Thanks for the advice! I got it working after taking a more educated look at how it was done in the HelloCollision example. Instead of returning the Geometry as in the HelloPicking example, I’m just returning the physicsNode. This keeps everything together when attaching it to the shootables Node.



[java]

public PhysicsNode setupFloor() {

Material mat = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);

assetManager.registerLocator("…/", FileLocator.class.getName());



TextureKey key = new TextureKey(“dependencies/1280783806_1_GEI8.jpg”);

key.setGenerateMips(true); //no clue wtf this does.



Texture tex = assetManager.loadTexture(key);

tex.setMinFilter(Texture.MinFilter.Trilinear);

mat.setTexture(“m_ColorMap”, tex);



Spatial myTerrain = assetManager.loadModel(“dependencies/terrain2.mesh.xml”);

CompoundCollisionShape terrainShape = CollisionShapeFactory.createMeshCompoundShape((Node) myTerrain);

PhysicsNode landscape = new PhysicsNode(myTerrain, terrainShape, 0);



myTerrain.setMaterial(mat);

myTerrain.updateModelBound();



landscape.setLocalTranslation(0, -6, 0);

landscape.attachDebugShape(assetManager);

getPhysicsSpace().add(landscape);

return landscape;[/java]

I attempted to do the same as above to the makeBox() method but I can’t seem to get it to work because a Box isn’t a Spatial. How can I get this to match up (as in the screenshot above, the box physics shape falls to the ground, and the material doesn’t still move).

A Box is a Mesh and has to be added to a Geometry which is a Spatial.

I got it working. Again, I had to return the physicsNode instead of the Geometry. Thanks for all your patience and help!



[java] private PhysicsNode makeBox() {

/*

*creates an obstacle box

*/

Material mat1 = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);



TextureKey key1 = new TextureKey(“Interface/Logo/Monkey.jpg”, true);

key1.setGenerateMips(true);



Texture tex1 = assetManager.loadTexture(key1);

tex1.setMinFilter(Texture.MinFilter.Trilinear);

mat1.setTexture(“m_ColorMap”, tex1);



Box boxGeom = new Box(Vector3f.ZERO, 1f, 1f, 1f);

BoxCollisionShape shape = new BoxCollisionShape(new Vector3f(1, 1, 1));



Geometry geom0 = new Geometry(“box”, boxGeom);

geom0.setMaterial(mat1);

geom0.updateModelBound();



PhysicsNode physicsBox = new PhysicsNode(geom0, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1);

physicsBox.setLocalTranslation(new Vector3f(0f, 0f, -15f));

physicsBox.attachDebugShape(assetManager);

getPhysicsSpace().add(physicsBox);

return physicsBox;

}[/java]