CollisionShapeFactory inverted normals?

Hey all,



So my player in this first screenshot is standing on a box floor, made with new BoxCollisionShape(…):



http://i.imgur.com/O7kH8.png



… and the getNormalWorldOnB().y (collision normal Y value) returns -1.0.



However, when I step onto the box made with the CollisionShapeFactory.createMeshShape(…), the Y normal inverts:



http://i.imgur.com/DZ0K8.png



If I make both objects with createMeshShape, the normals are both the same. I tried using createBoxShape, but it completely messes up my objects (they get culled too often and I fall through them).



I suspect this isn’t intended behavior…?

Maybe your meshes normals are inverted?

Using the same mesh (created with “new Box(…)”), but just switching between “new BoxCollisionShape” and “CollisionShapeFactory.createMeshShape” causes this behavior… so it looks like it is a bug in one of these functions.



I want to detect when the player is standing on something, and this is causing difficulties :frowning:

One method creates a box collision shape and one uses your mesh to create a mesh collision shape which incidentally is also a box. Thats not the same at all.

The normal collisions should be the same. Why should hitting the top of a BoxCollisionShape return a different normal than a createMeshShape from the built-in Box mesh? Somewhere, normals are not consistent. Even if “they are not the same at all” under the hood, the way it works now isn’t desirable behavior and should be fixed.

Whats the “…” in your BoxCollisionShape constructor?

geoShape = new BoxCollisionShape(new Vector3f(SizeXorRadius, SizeY, SizeZ));



In the case of the floor, that vector is new Vector3f(20f, 0.025f, 14f)

I can’t see any problems on the jme-bullet side, everything is basically translated 1:1, can you make a test case for this?

So I just modified the TestCollisionListener example:



[java]

/*

  • Copyright © 2009-2010 jMonkeyEngine
  • All rights reserved.

    *
  • Redistribution and use in source and binary forms, with or without
  • modification, are permitted provided that the following conditions are
  • met:

    *
    • Redistributions of source code must retain the above copyright
  • notice, this list of conditions and the following disclaimer.

    *
    • Redistributions in binary form must reproduce the above copyright
  • notice, this list of conditions and the following disclaimer in the
  • documentation and/or other materials provided with the distribution.

    *
    • Neither the name of ‘jMonkeyEngine’ nor the names of its contributors
  • may be used to endorse or promote products derived from this software
  • without specific prior written permission.

    *
  • THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  • TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  • PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  • CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  • EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  • PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  • PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  • LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  • NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  • SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    */



    package jme3test.bullet;



    import com.jme3.app.SimpleApplication;

    import com.jme3.bullet.BulletAppState;

    import com.jme3.bullet.PhysicsSpace;

    import com.jme3.bullet.collision.PhysicsCollisionEvent;

    import com.jme3.bullet.collision.PhysicsCollisionListener;

    import com.jme3.bullet.collision.shapes.SphereCollisionShape;

    import com.jme3.renderer.RenderManager;

    import com.jme3.scene.shape.Sphere;

    import com.jme3.scene.shape.Sphere.TextureMode;



    /**

    *
  • @author normenhansen

    */

    public class Main extends SimpleApplication implements PhysicsCollisionListener {



    private BulletAppState bulletAppState;

    private Sphere bullet;

    private SphereCollisionShape bulletCollisionShape;



    public static void main(String[] args) {

    Main app = new Main();

    app.start();

    }



    @Override

    public void simpleInitApp() {

    bulletAppState = new BulletAppState();

    stateManager.attach(bulletAppState);

    bulletAppState.getPhysicsSpace().enableDebug(assetManager);

    bullet = new Sphere(32, 32, 0.4f, true, false);

    bullet.setTextureMode(TextureMode.Projected);

    bulletCollisionShape = new SphereCollisionShape(0.4f);



    PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());

    PhysicsTestHelper.createBallShooter(this, rootNode, bulletAppState.getPhysicsSpace());



    // add ourselves as collision listener

    getPhysicsSpace().addCollisionListener(this);

    }



    private PhysicsSpace getPhysicsSpace(){

    return bulletAppState.getPhysicsSpace();

    }



    @Override

    public void simpleUpdate(float tpf) {

    //TODO: add update code

    }



    @Override

    public void simpleRender(RenderManager rm) {

    //TODO: add render code

    }



    public void collision(PhysicsCollisionEvent event) {

    if (“Box”.equals(event.getNodeA().getName()) || “Box”.equals(event.getNodeB().getName())) {



    System.out.println("Box normal Y: " + Float.toString(event.getNormalWorldOnB().y));



    if (“bullet”.equals(event.getNodeA().getName()) || “bullet”.equals(event.getNodeB().getName())) {

    fpsText.setText(“You hit the box!”);

    }

    }

    }



    }[/java]



    and I also modified the createPhysicsTestWorld function:



    [java]



    public static void createPhysicsTestWorld(Node rootNode, AssetManager assetManager, PhysicsSpace space) {

    AmbientLight light = new AmbientLight();

    light.setColor(ColorRGBA.LightGray);

    rootNode.addLight(light);



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

    material.setTexture(“ColorMap”, assetManager.loadTexture(“Interface/Logo/Monkey.jpg”));



    Box floorBox = new Box(140, 0.25f, 140);

    Geometry floorGeometry = new Geometry(“Floor”, floorBox);

    floorGeometry.setMaterial(material);

    floorGeometry.setLocalTranslation(0, -5, 0);

    // Plane plane = new Plane();

    // plane.setOriginNormal(new Vector3f(0, 0.25f, 0), Vector3f.UNIT_Y);

    // floorGeometry.addControl(new RigidBodyControl(new PlaneCollisionShape(plane), 0));



    // switch these two lines to use the different methods

    //CollisionShape shape = new BoxCollisionShape(new Vector3f(140f, 0.25f, 140f));

    CollisionShape shape = CollisionShapeFactory.createMeshShape(floorGeometry);



    floorGeometry.addControl(new RigidBodyControl(shape, 0));

    rootNode.attachChild(floorGeometry);

    space.add(floorGeometry);



    //movable boxes

    for (int i = 0; i < 12; i++) {

    Box box = new Box(0.25f, 0.25f, 0.25f);

    Geometry boxGeometry = new Geometry(“Box”, box);

    boxGeometry.setMaterial(material);

    boxGeometry.setLocalTranslation(i, 5, -3);

    //RigidBodyControl automatically uses box collision shapes when attached to single geometry with box mesh

    boxGeometry.addControl(new RigidBodyControl(2));

    rootNode.attachChild(boxGeometry);

    space.add(boxGeometry);

    }



    //immovable sphere with mesh collision shape

    Sphere sphere = new Sphere(8, 8, 1);

    Geometry sphereGeometry = new Geometry(“Sphere”, sphere);

    sphereGeometry.setMaterial(material);

    sphereGeometry.setLocalTranslation(4, -4, 2);

    sphereGeometry.addControl(new RigidBodyControl(new MeshCollisionShape(sphere), 0));

    rootNode.attachChild(sphereGeometry);

    space.add(sphereGeometry);



    }

    [/java]



    I have two methods of creating the collision shape for the floorGeometry, and you can comment between them. Running this test, I think I see what is going on wrong: With createMeshShape, the blocks are falling through the floor and colliding with the BOTTOM of the floor, which returns the inverted normal. One block does get flipped around, and DOES land on the top of the floor, which is all just very very weird. Looks like collisions are reversed or something…?



    Also, what is wrong with createBoxShape? If you replace createMeshShape with createBoxShape, the floor doesn’t even render, and the blocks fall right through! :frowning:
1 Like

CreateBoxShape sets a BoundingBox to the spatials. What happens when you create a box in blender and do it with that?

I’ve already tried creating a box in blender and using that, and nothing seems to change. I get the same behavior importing a Blender-created OBJ box vs. using a built-in box mesh. The difference seems to be in BoxCollisionShape vs. createMeshShape (and createBoxShape is even more broken).

Dude, I say it once again, a BoxCollisionShape and a MeshCollision shape are completely different things. A BoxCollisionShape has no normal information, its created when the collision with the box is determined. A BoxCollisionShape neither has vertices nor normals as existing data and its also not generated from the halfextents as a box shape is way easier to compute than 8 vertices and 12 Triangles…!

Did you run my test case I provided? Can you tell me if these two things are desired behavior:


  1. When using createMeshShape for the floor, the falling boxes fall through the top of the floor, only to collide with the bottom of the floor. One box seems to bounce off the bottom of the floor, spin in the air, then rest on the top of the floor. This is very different than using BoxCollisionShape for the floor, where the boxes fall and land on the top of the floor as expected.


  2. When using createBoxShape for the floor, the floor doesn’t even render and the boxes fall like no floor is present.

I get your problem but you don’t seem to get that a box shape and a mesh shape are completely different things in a physics engine and that saying “the box works so the mesh must be broken” makes no sense. If at all the issue is that bullet wants the indices for meshes ordered differently which the fact that the issue is consistent between meshes of different origins seems to suggest.

It seems like you are trying to use the excuse of “they are completely different things” to avoid addressing the problem, which you admit exists.



Even if “they are completely different things” under the hood, creating a BoxCollisionShape, and creating a createMeshShape of a native box of the same size should result in the same physical behavior (we can ignore the normal issue for now, which I suspect will be fixed once we fix the physical behavior).



Also, you haven’t even touched upon the problems with createBoxShape, which stops the box from even being rendered and doesn’t create any collisions, which is a whole other problem.

@phr00t said:
It seems like you are trying to use the excuse of "they are completely different things" to avoid addressing the problem, which you admit exists.

I don't disagree, it seems you don't read what I am writing. I told you I couldn't find out anything wrong about how the mesh gets from bullet to jme which means I do address the issue. Its just that when you write bullcrap I have to correct you.
I told you I couldn’t find out anything wrong about how the mesh gets from bullet to jme


If you are referring to this line:

I can’t see any problems on the jme-bullet side, everything is basically translated 1:1


You then asked me to make a test case, which I did. You then admitted there is a problem. You did give some insight into a possible cause of the problem:

If at all the issue is that bullet wants the indices for meshes ordered differently which the fact that the issue is consistent between meshes of different origins seems to suggest.


I do apologize for missing this following statement, which does at least touch on createBoxMesh:

CreateBoxShape sets a BoundingBox to the spatials.


However, I don't feel like this addresses the issue, as my expected behavior from createBoxShape is to get a box collision shape to be used in physics, which doesn't seem to happen.

Maybe we have a difference of expectations, but I believe "addressing the issue" is either fixing the behavior, or being told the current behavior is the desired behavior. You haven't done either one of these things yet.

Finally, I have to suggest a more professional attitude would have made this discussion much smoother. I'm really trying to help us figure this issue out, by making test cases and taking screenshots. Accusing me of spouting bullcrap and finishing posts with italics like so:

"Thats not the same at all."

... just makes it look like you are intentionally trying to put in a demeaning attitude. Can we just work together on this?

Okay, I apologize for not giving you the line “Problem accepted, we’ll look into this, thank you.” But I don’t know how I could work together with you better than a) telling you what I see is or might be the problem b) check the parts of the engine that I know and have to do with this c) correct your misunderstandings of the issue to help you understand it better as well so you can help. Just like I might have come off like I dismissed the issue you came off like you expect me to be able to magically make it disappear just by you calling its name.

I was looking for a “Problem accepted, we’ll look into this, thank you” or “this is what is suppose to happen” line, because as you say, it can be hard to tell if you are dismissing or accepting the issue. A, B and C are also very appreciated, and I apologize if I came off as expecting you to just make this issue disappear magically. Let me know if I can do anything more to help this issue get resolved.

A simpler test case just for the issue would be much appreciated next time. In your test the Floor is A when its a mesh shape and B when its a Box shape so naturally the normal inverts if you don’t check for the actual objects.