Boxes tunneling like Neutrinos

Anything libgdx related goes here!

Boxes tunneling like Neutrinos

Postby Clark_Kent » Wed Sep 24, 2014 4:32 am

Hi
i'm encountering a strange problem.
The boxes in the example get sucked into the Bhv mesh.
I dont know how to explain it.
You may try it out. THe terrain is in the attachment.
Press L for debug mode.

Code: Select all

public class Demolation extends Game {
    SpriteBatch batch;
    BitmapFont font;
    
    public void create() {
    batch = new SpriteBatch();
    font = new BitmapFont();
    this.setScreen(new MainMenuScreen(this));
    }
    
    public void render() {
    super.render();
    }
    
    public void dispose() {
    batch.dispose();
    font.dispose();
    }
}


Code: Select all

public class MainMenuScreen implements Screen {

   final Demolation game;

   OrthographicCamera camera;

   public MainMenuScreen(final Demolation demolation) {
      game = demolation;

      camera = new OrthographicCamera();
      camera.setToOrtho(false, 800, 480);

   }

   @Override
   public void render(float delta) {
      Gdx.gl.glClearColor(0, 0, 0.2f, 1);
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

      camera.update();
      game.batch.setProjectionMatrix(camera.combined);
      
      game.font.setScale(2f);

      game.batch.begin();
      game.font.draw(game.batch, "Welcome", 100, 150);
      game.font.draw(game.batch, "Tap anywhere to begin!", 100, 100);
      game.batch.end();

      if (Gdx.input.isTouched()) {
         game.setScreen(new Phys(game));
         dispose();
      }
   }

   @Override
   public void resize(int width, int height) {
   }

   @Override
   public void show() {
   }

   @Override
   public void hide() {
   }

   @Override
   public void pause() {
   }

   @Override
   public void resume() {
   }

   @Override
   public void dispose() {
   }
}


Code: Select all

public class Phys implements Screen {
   Demolation game;

   final static short GROUND_FLAG = 1 << 8;
   final static short OBJECT_FLAG = 1 << 9;
   final static short ALL_FLAG = -1;

   PerspectiveCamera cam;
   CameraInputController camController;
   ModelBatch modelBatch;
   Environment environment;
   Model model, model2, rad, rahmen;
   Array<GameObject> instances;
   ArrayMap<String, GameObject.Constructor> constructors;
   float spawnTimer;
   
   btCollisionConfiguration collisionConfig;
   btDispatcher dispatcher;
   MyContactListener contactListener;
   btBroadphaseInterface broadphase;
   btDynamicsWorld dynamicsWorld;
   btConstraintSolver constraintSolver;
   
   PointLight plight;
   DirectionalLight light;
   
   int visibleCount;
   protected Stage stage;
   protected Label label;
   protected BitmapFont font;
   protected StringBuilder stringBuilder;
   
   Vector3 position;
   
   AssetManager assets;
   boolean loading;
   
   DebugDrawer debugDrawer;
   boolean debug = false;

   public Phys(Demolation gam) {
      this.game = gam;
      
      Gdx.gl.glEnable(GL20.GL_BLEND);
      Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
      
      position = new Vector3();
      
      stage = new Stage();
      font = new BitmapFont();
      label = new Label(" ", new Label.LabelStyle(font, Color.WHITE));
      stage.addActor(label);
      stringBuilder = new StringBuilder();
      
      Bullet.init();
      modelBatch = new ModelBatch();
      environment = new Environment();
      environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.1f, 0.1f, 0.1f, 1f));
      
      light = new DirectionalLight();
      
      light.set(Color.WHITE, -90, -90, 90);
      environment.add(light);
      
      plight = new PointLight();
      plight.set(Color.RED, -5f, 5f, -3f, 15f);
      environment.add(plight);
      
      cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
      cam.position.set(3f, 60f, 10f);
      cam.lookAt(0, 40f, 0);
      cam.near = 1f;
      cam.far = 300f;
      cam.update();
      camController = new CameraInputController(cam);
      Gdx.input.setInputProcessor(camController);
      
      ModelBuilder mb = new ModelBuilder();
      
      mb.begin();
      mb.node().id = "ground";
      mb.part("ground", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal,
            new Material(ColorAttribute.createDiffuse(Color.PINK))).box(50f,
            1f, 50f);
      mb.node().id = "sphere";
      mb.part("sphere", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal,
            new Material(ColorAttribute.createDiffuse(Color.GREEN)))
            .sphere(6f, 6f, 6f, 10, 10);
      mb.node().id = "box";
      mb.part("box", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal,
            new Material(ColorAttribute.createDiffuse(Color.BLUE))).box(2f,
            2f, 2f);
      model = mb.end();
      

      
      constructors = new ArrayMap<String, GameObject.Constructor>(
            String.class, GameObject.Constructor.class);
      
      constructors.put("ground", new GameObject.Constructor(model, "ground",
            new btBoxShape(new Vector3(25f, 0.5f, 25f)), 0f));
      constructors.put("sphere", new GameObject.Constructor(model, "sphere",
            new btSphereShape(3f), 100f));
      constructors.put("box", new GameObject.Constructor(model, "box",
            new btBoxShape(new Vector3(1f, 1f, 1f)), 1f));
      
      
      assets = new AssetManager();
      assets.load("model/test.g3db", Model.class);

      while (!assets.update()) {}
      
      collisionConfig = new btDefaultCollisionConfiguration();
      dispatcher = new btCollisionDispatcher(collisionConfig);
      broadphase = new btDbvtBroadphase();
      constraintSolver = new btSequentialImpulseConstraintSolver();
      dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, constraintSolver, collisionConfig);
      dynamicsWorld.setGravity(new Vector3(0, -10f, 0));
      contactListener = new MyContactListener();
      instances = new Array<GameObject>();
      
      terrain();
      
      debugDrawer = new DebugDrawer();
      debugDrawer.setDebugMode(btIDebugDraw.DebugDrawModes.DBG_MAX_DEBUG_DRAW_MODE);
      dynamicsWorld.setDebugDrawer(debugDrawer);
      
//      GameObject object = constructors.get("ground").construct();
//      object.body.setCollisionFlags(object.body.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
//      instances.add(object);
//      dynamicsWorld.addRigidBody(object.body);
//      object.body.setContactCallbackFlag(GROUND_FLAG);
//      object.body.setContactCallbackFilter(0);
//      object.body.setActivationState(Collision.DISABLE_DEACTIVATION);
   }
   
   btBvhTriangleMeshShape terrainbhv;
   Model terrain;
   GameObject terrainGO;
   
   private void terrain() {
      terrain = assets.get("model/test.g3db", Model.class);
      terrain.meshes.first().scale(97f, 97f, 97f);
      String terrainStr = terrain.nodes.first().id;
      
      terrainbhv = (btBvhTriangleMeshShape) Bullet.obtainStaticNodeShape(terrain.nodes);
      terrainbhv.setMargin(0.2f);
      
      constructors.put(terrainStr, new GameObject.Constructor(terrain, terrainStr,terrainbhv, 0.0f));
      terrainGO = constructors.get(terrainStr).construct();
      
      terrainGO.transform.setFromEulerAngles(0,0,0);
      terrainGO.transform.trn(-210,0,-210);
      terrainGO.body.proceedToTransform(terrainGO.transform);
      terrainGO.body.setUserValue(instances.size);
      terrainGO.body.setCollisionFlags(terrainGO.body.getCollisionFlags()
            | btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
      terrainGO.body.setContactCallbackFlag(GROUND_FLAG);
      terrainGO.body.setContactCallbackFilter(0);
      terrainGO.body.setActivationState(Collision.DISABLE_DEACTIVATION);
      
      dynamicsWorld.addRigidBody(terrainGO.body);
      instances.add(terrainGO);
   }

   public void spawn() {
      GameObject obj = constructors.values[1 + MathUtils.random(constructors.size - 3)].construct();
      obj.transform.setFromEulerAngles(MathUtils.random(360f),MathUtils.random(360f), MathUtils.random(360f));
      obj.transform.trn(-1.2f, 50f,2.6f);
      obj.body.proceedToTransform(obj.transform);
      obj.body.setUserValue(instances.size);
      obj.body.setCollisionFlags(obj.body.getCollisionFlags()   | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
      instances.add(obj);
      dynamicsWorld.addRigidBody(obj.body);
      obj.body.setContactCallbackFlag(OBJECT_FLAG);
      obj.body.setContactCallbackFilter(GROUND_FLAG);
   }
   
   protected boolean isVisible(Camera cam1, GameObject instance) {
      instance.transform.getTranslation(position);
      position.add(instance.center);
      return cam1.frustum.sphereInFrustum(position, instance.radius);
   }

   float angle, speed = 90f;

   @Override
   public void render(float delta) {
      //if (loading && assets.update()) geladen();
      
      final float deltaa = Math.min(1f / 30f, Gdx.graphics.getDeltaTime());
      angle = (angle + deltaa * speed) % 360f;
      dynamicsWorld.stepSimulation(delta, 10, 1f / 120f);
      if ((spawnTimer -= delta) < 0) {
         spawn();
         spawnTimer = 0.5f;
      }
      
      
      camController.update();
      Gdx.gl.glClearColor(0, 0, 0, 1.f);
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
      
      if (!debug) {
         modelBatch.begin(cam);
         visibleCount = 0;
         for (final GameObject instance : instances) {
            if (isVisible(cam, instance)) {
               modelBatch.render(instance, environment);
               visibleCount++;
            }
         }
         modelBatch.end();
      } else {
         debugDrawer.begin(cam);
         dynamicsWorld.debugDrawWorld();
         debugDrawer.end();
      }
      
      
      stringBuilder.setLength(0);
      stringBuilder.append(" FPS: ").append(Gdx.graphics.getFramesPerSecond());
      stringBuilder.append(" Visible: ").append(visibleCount);
      label.setText(stringBuilder);
      stage.draw();
      
      if (Gdx.input.isKeyJustPressed(Keys.L)) {
         debug = !debug;
      }
   }

   @Override
   public void dispose() {
      debugDrawer.dispose();
      for (GameObject obj : instances)
         obj.dispose();
      instances.clear();
      for (GameObject.Constructor ctor : constructors.values())
         ctor.dispose();
      constructors.clear();
      dynamicsWorld.dispose();
      constraintSolver.dispose();
      broadphase.dispose();
      dispatcher.dispose();
      collisionConfig.dispose();
      contactListener.dispose();
      modelBatch.dispose();
      model.dispose();
      assets.dispose();
   }

   @Override
   public void pause() {
   }

   @Override
   public void resume() {
   }

   @Override
   public void resize(int width, int height) {
      stage.getViewport().update(width, height, true);
   }

   @Override
   public void show() {
   }

   @Override
   public void hide() {
   }
   
   class MyContactListener extends ContactListener {
      @Override
      public boolean onContactAdded(int userValue0, int partId0, int index0,
            boolean match0, int userValue1, int partId1, int index1,
            boolean match1) {
//         if (match0)
//            ((ColorAttribute) instances.get(userValue0).materials.get(0)
//                  .get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
//         if (match1)
//            ((ColorAttribute) instances.get(userValue1).materials.get(0)
//                  .get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
         return true;
      }
   }

   static class MyMotionState extends btMotionState {
      Matrix4 transform;

      @Override
      public void getWorldTransform(Matrix4 worldTrans) {
         worldTrans.set(transform);
      }

      @Override
      public void setWorldTransform(Matrix4 worldTrans) {
         transform.set(worldTrans);
      }
   }

   static class GameObject extends ModelInstance implements Disposable {
      
      public Vector3 center = new Vector3();
      public Vector3 dimensions = new Vector3();
      public float radius;
      private  BoundingBox bounds = new BoundingBox();
      
      public final btRigidBody body;
      public final MyMotionState motionState;

      public GameObject(Model model1, String node, btRigidBody.btRigidBodyConstructionInfo constructionInfo) {
         super(model1, node);
         
         calculateBoundingBox(bounds);
         center.set(bounds.getCenter());
         dimensions.set(bounds.getDimensions());
         radius = dimensions.len() / 2f;
         
         motionState = new MyMotionState();
         motionState.transform = transform;
         body = new btRigidBody(constructionInfo);
         body.setMotionState(motionState);
      }

      @Override
      public void dispose() {
         body.dispose();
         motionState.dispose();
      }
      
      static class Constructor implements Disposable {
         public final Model model;
         public final String node;
         public final btCollisionShape shape;
         public final btRigidBody.btRigidBodyConstructionInfo constructionInfo;
         private static Vector3 localInertia = new Vector3();

         public Constructor(Model model, String node, btCollisionShape shape, float mass) {
            this.model = model;
            this.node = node;
            this.shape = shape;
            if (mass > 0f)
               shape.calculateLocalInertia(mass, localInertia);
            else
               localInertia.set(0, 0, 0);
            this.constructionInfo = new btRigidBody.btRigidBodyConstructionInfo(
                  mass, null, shape, localInertia);
         }

         public GameObject construct() {
            return new GameObject(model, node, constructionInfo);
         }

         @Override
         public void dispose() {
            shape.dispose();
            constructionInfo.dispose();
         }
      }
   }
}

The g3db terrain file :
test.zip
The g3db terrain file
(1.51 KiB) Downloaded 93 times


It looks like a fundamental bug.
How have you solved this problem ?
Clark_Kent
 
Posts: 4
Joined: Wed Sep 24, 2014 4:02 am

Re: Boxes tunneling like Neutrinos

Postby Clark_Kent » Wed Sep 24, 2014 1:34 pm

As suggested here is a more stripped test code and a d3dj file of the terrain.

Main:
http://pastebin.com/n9ChcDyY

the test scene;
http://pastebin.com/AnaADg3Q

the d3dj terrain file;
http://pastebin.com/eQcKUqKw
test.zip
Test terrain file
(1.86 KiB) Downloaded 92 times


:|
Clark_Kent
 
Posts: 4
Joined: Wed Sep 24, 2014 4:02 am

Re: Boxes tunneling like Neutrinos

Postby xoppa » Wed Sep 24, 2014 6:42 pm

I can confirm that this is an issue with Bullet and that it is resolved in the Bullet repo. As for the currect version (2.82) a work-around would be calling btGjkPairDetector#setFixContactNormalDirection(0);, although that isn't a really practical solution. I will look into a more practical work-around or perhaps an interim update/patch.
xoppa
 
Posts: 689
Joined: Thu Aug 23, 2012 11:27 pm

Re: Boxes tunneling like Neutrinos

Postby Clark_Kent » Sat Sep 27, 2014 12:38 pm

Yes that was it.
Recompiling the Bullet project with the new btGjkPairDetector solved it.

Boxes are not tunneling like Neutrinos anymore :D
Clark_Kent
 
Posts: 4
Joined: Wed Sep 24, 2014 4:02 am


Return to Libgdx

Who is online

Users browsing this forum: Google [Bot], MSN [Bot] and 1 guest