question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Inaccurate Collisions when using Bullet.obtainStaticNodeShape()

See original GitHub issue

Ok, so I’ve recently been trying to create collision shapes using models that I’ve exported from Blender. I am using the Bullet Physics engine and libGDX 1.9.2. Whenever I run this test with a collision shape that is created as a btBoxShape, everything works as it should. Whenever I use the Bullet.obtainStaticNodeShape() with the nodes of my model, which is a cube, I can see that the shape is generated properly through the Debug Drawer. The physics of the object only seem to work in a small area located in the center of the shape, everywhere else, objects simply fall through. The model is Blender’s default cube with a scale of 24 on the X and Y axes, and a scale of 0.3 on the Z axis. I export as a fbx with a scale of .01 and -Z being Forward and Y Being Up in the export settings. I then use fbx-conv to generate a .g3db file.

Here is the class for the simple test that I’ve created that shows the issue.

package com.imackshun.tests.customcollisionshape;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.loader.G3dModelLoader;
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.bullet.Bullet;
import com.badlogic.gdx.physics.bullet.DebugDrawer;
import com.badlogic.gdx.physics.bullet.collision.btBoxShape;
import com.badlogic.gdx.physics.bullet.collision.btBroadphaseInterface;
import com.badlogic.gdx.physics.bullet.collision.btCollisionConfiguration;
import com.badlogic.gdx.physics.bullet.collision.btCollisionDispatcher;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
import com.badlogic.gdx.physics.bullet.collision.btCollisionShape;
import com.badlogic.gdx.physics.bullet.collision.btDbvtBroadphase;
import com.badlogic.gdx.physics.bullet.collision.btDefaultCollisionConfiguration;
import com.badlogic.gdx.physics.bullet.collision.btDispatcher;
import com.badlogic.gdx.physics.bullet.dynamics.btConstraintSolver;
import com.badlogic.gdx.physics.bullet.dynamics.btDiscreteDynamicsWorld;
import com.badlogic.gdx.physics.bullet.dynamics.btDynamicsWorld;
import com.badlogic.gdx.physics.bullet.dynamics.btSequentialImpulseConstraintSolver;
import com.badlogic.gdx.physics.bullet.linearmath.btIDebugDraw;
import com.badlogic.gdx.utils.UBJsonReader;

public class CustomCollisionShape extends ApplicationAdapter {
	public PerspectiveCamera cam;
	// For the ground collision... The player shouldn't fall through the ground.
	private btCollisionShape groundShape;
	private btCollisionObject groundCollision;
	private Model collisionModel;
	//Objects to fall
	private btCollisionShape boxShape;
	private Object boxCollision1;
	private Object boxCollision2;
	private Object boxCollision3;
	private Object boxCollision4;
	private Object boxCollision5;
	// Used for collisions.
	private btCollisionConfiguration collisionConfig;
	private btDispatcher dispatcher;
	private btBroadphaseInterface broadphase;
	private btDynamicsWorld dynamicsWorld;
	private btConstraintSolver constraintSolver;
	private DebugDrawer debugDrawer;
	//For controlling the camera.
	public CameraInputController camController;
	@Override
	public void create() {
		//Initialize the camera...
		cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		cam.position.set(0f, 25f, 30f);
		cam.lookAt(0, 0, 0);
		cam.near = 1f;
		cam.far = 300f;
		cam.update();
		//Camera controller.
		camController = new CameraInputController(cam);
        Gdx.input.setInputProcessor(camController);
		// Initialize the physics engine!
		Bullet.init();
		//Physics Stuff
		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, -30f, 0));
		debugDrawer = new DebugDrawer();
		debugDrawer.setDebugMode(btIDebugDraw.DebugDrawModes.DBG_MAX_DEBUG_DRAW_MODE);
		dynamicsWorld.setDebugDrawer(debugDrawer);
		//Load the model.
        UBJsonReader jsonReader = new UBJsonReader();
        G3dModelLoader modelLoader = new G3dModelLoader(jsonReader);
        //collisionModel = modelLoader.loadModel(Gdx.files.internal("ArenaCollisionCube.g3db"));
        //This works just fine.
        groundShape = new btBoxShape(new Vector3(20f, 1f, 20f));
        //This is inaccurate everywhere but the center.
		//groundShape = Bullet.obtainStaticNodeShape(collisionModel.nodes);
		groundCollision = new btCollisionObject();
		groundCollision.setCollisionShape(groundShape);
		groundCollision.setUserValue(0);
		groundCollision.setCollisionFlags(groundCollision.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
		dynamicsWorld.addCollisionObject(groundCollision);
		//Boxes
		boxShape = new btBoxShape(new Vector3(2f, 2f, 2f));
		// Initialize the Rigidbodies.
		boxCollision1 = new Object(new Vector3(0f, 10f, 0f), boxShape, dynamicsWorld, 1);
		boxCollision2 = new Object(new Vector3(-18f, 10f, 0f), boxShape, dynamicsWorld, 2);
		boxCollision3 = new Object(new Vector3(18f, 10f, 0f), boxShape, dynamicsWorld, 3);
		boxCollision4 = new Object(new Vector3(0f, 10f, -18f), boxShape, dynamicsWorld, 4);
		boxCollision5 = new Object(new Vector3(0f, 10f, 18f), boxShape, dynamicsWorld, 5);
	}

	@Override
	public void render() {
		Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
		//Update the camera controller!
        camController.update();
		// Update the physics engine!
		final float delta2 = Math.min(1f / 30f, Gdx.graphics.getDeltaTime());
		dynamicsWorld.stepSimulation(delta2, 5, 1f / 60f);
		// Physics debugging.
		debugDrawer.begin(cam);
		dynamicsWorld.debugDrawWorld();
		debugDrawer.end();
	}
}

Here is the Object.class file. Just to make it easier to create the rigidbodies.

package com.imackshun.tests.customcollisionshape;

import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
import com.badlogic.gdx.physics.bullet.collision.btCollisionShape;
import com.badlogic.gdx.physics.bullet.dynamics.btDynamicsWorld;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody;

public class Object {
	private float Mass;
	// The actual collision objects...
	public btRigidBody rbody;
	// Used to construct a rigidbody.
	public btRigidBody.btRigidBodyConstructionInfo constructionInfo;
	// Uh...Hmmm. IDK lol? Takes in mass... Like...Resistance?
	private static Vector3 localInertia = new Vector3();

	// Constructor
	public Object(Vector3 Position, btCollisionShape CollisionShape, btDynamicsWorld dynamicsWorld, int userValue) {
		Mass = 10;
		if (Mass > 0f) {
			CollisionShape.calculateLocalInertia(Mass, localInertia);
		} else {
			localInertia.set(0, 0, 0);
		}
		this.constructionInfo = new btRigidBody.btRigidBodyConstructionInfo(Mass, null, CollisionShape, localInertia);
		constructionInfo.setFriction(10f);
		rbody = new btRigidBody(constructionInfo);
		rbody.setCollisionShape(CollisionShape);
		rbody.setLinearFactor(new Vector3(1f, 1f, 0f));
		rbody.setUserValue(userValue);
		// Determines how this object ineracts with other objects.
		rbody.setCollisionFlags(rbody.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
		// Add the collision objects to za warudo.
		rbody.translate(new Vector3(Position.x, Position.y, Position.z));
		dynamicsWorld.addRigidBody(rbody);
	}
}

Here is a link to the exact model that I am using.

https://www.dropbox.com/s/696dk3gk2etge4t/ArenaCollisionCube.blend?dl=0

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:10

github_iconTop GitHub Comments

1reaction
cpfrcommented, Jan 28, 2018

I had a similar issue:

  • when using btCollisionShape mapShape = new btBvhTriangleMeshShape(model.meshParts); the mesh did collide, but it was too small and weirdly rotated
  • when using btCollisionShape mapShape = Bullet.obtainStaticNodeShape(model.nodes); the collision mesh looked right in debug draw, but the player fell through

Removing transforms and setting object scales in edit mode didn’t work for me. According to the following discussion: https://pybullet.org/Bullet/phpBB3/viewtopic.php?t=10104 there is a problem with too big polygons not being properly used by bullet. We solved the problem by applying a SubdivisionSurface modifier in Blender (simple mode) in order to get smaller polys.

0reactions
DimaL-cloudcommented, Mar 18, 2021

To solve this problem you should

  1. choose your object in Blender in Object Mode
  2. Click the button “Object” (near the “Object Mode”) -> “Apply” -> “Scale” (scale X 1.000, Y 1.000, Z 1.000).
  3. When you export your scene via .fbx you should mark checkboxes “Apply Transform” and “Tangent Space”. Also in transform set scale 0.01

In addition, you can export your object via .obj and then convert it via https://asneakyfox.github.io/libgdx-fbxconv-gui/ . There’re no problems with Scaling.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Incorrect collision detection? [Solved] - Real-Time Physics ...
Bullet reports a collision where actually no collision is happening. ... which isn't drawn correctly when using the bullet debug drawer).
Read more >
Bullet 2.80 Physics SDK Manual
the end of the last physics tick], use btRigidBody::getWorldTransform() and query the body directly. So how do I use one?
Read more >
Inconsistent Collision Detection - Unity Answers
I've encountered a simple problem with collision detection. I have a target (a spaceship in this case) and a bullet.
Read more >
Bullet Wrapper Using models - libGDX
For the case of a static model, the Bullet wrapper provides a convenient method to create a collision shape of it: btCollisionShape shape...
Read more >
Bullet Collision Shapes - Panda3D Manual
The most basic collision shape, a sphere with radius radius. ... from panda3d.bullet import BulletTriangleMesh mesh = BulletTriangleMesh() mesh.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found