bullet icon indicating copy to clipboard operation
bullet copied to clipboard

Collisions do not work

Open Martmists-GH opened this issue 8 months ago • 1 comments

For my test case, I made a 3x1x3 floor with mass 0 centered on (0, 0, 0), and a 1x1x1 cube with mass 1 at (0, 2, 0). I created a PhysicsWorld and added both with addRigidBody, but if I keep calling world.stepSimulation(), I can see the cube phase through the floor.

// MotionState implementation:
class GameMotionState(private val go: GameObject) : MotionState {
    override fun getWorldTransform(worldTransform: Transform) {
        worldTransform.basis put Mat3(go.transform.rotation.bullet())  // transforms between my vec/quat/mat and bullet types
        worldTransform.origin put go.transform.translation.bullet()
    }

    override fun setWorldTransform(worldTransform: Transform) {
        go.transform.translation = Vector3(worldTransform.origin)
        go.transform.rotation = Quaternion(worldTransform.basis)
    }
}

// RigidBody creation:
internal fun makeRigidBody(): RigidBody {
    val btShape = shape.getShape(gameObject.transform.scale)  // creates a CollisionShape stretched with the scale from transform
    var inertia = Vec3(0f)
    if (mass == 0f) {
        // apply inertia if needed
        inertia = Vec3().also { btShape.calculateLocalInertia(mass, it) }
    }
    val body = RigidBody(RigidBody.RigidBodyConstructionInfo(
        mass,
        GameMotionState(gameObject),
        btShape,
        inertia
    ))
    return body
}

// World creation and object handling:
class PhysicsSystem {
    val world: DiscreteDynamicsWorld

    init {
        val config = DefaultCollisionConfiguration()
        val dispatcher = CollisionDispatcher(config)
        val pairCache = DbvtBroadphase()
        val solver = SequentialImpulseConstraintSolver()
        world = DiscreteDynamicsWorld(dispatcher, pairCache, solver, config)

        world.gravity = Vec3(0f, -1f, 0f)  // Slow enough to get clear video; see link at the bottom
    }

    fun update(delta: Float) {
        world.stepSimulation(delta, 10)
    }

    private val map = mutableMapOf<PhysicsObject, RigidBody>()

    fun addObject(physicsObject: PhysicsObject) {
        val body = map.getOrPut(physicsObject) { physicsObject.makeRigidBody() }
        world.addRigidBody(body)
    }
}

val floor = addObject("floor") {
    transform.scale = Vector3(3f, 1f, 3f)  // make floor big

    addComponent<PhysicsObject> {
        mass = 0f  // no mass, it's static
        physics.addObject(this)
    }
}

val cube = addObject("cube") {
    transform.rotation = Quaternion.IDENTITY.rotate(Vector3(PI / 4))  // apply some rotation; seems to be lost after physics tick?
    transform.translation = Vector3(0f, 2f, 0f)  // place 2 units above floor

    addComponent<PhysicsObject> {
        mass = 1f
        physics.addObject(this)
    }
}

Clip: https://github.com/user-attachments/assets/62a68cbd-c69e-446e-97ba-3bc95b067638

Martmists-GH avatar Apr 03 '25 23:04 Martmists-GH

Update: After switching to worldTransform.set/getRotation, it seems to actually collide, but now collisions behave a bit strange:

video.mp4

A cube without rotation will go into space, and a cube with rotation sort of seems to slide/bounce off (depending on number of substeps), instead of simply rotating to be flat on the surface.

While not in the video, it seems lowering the gravity makes the cube bounce off the floor before even making contact. Also, if I instead extend the floor to 30x1x30, it seems the angled cube simply phases through it.

Martmists-GH avatar Apr 04 '25 13:04 Martmists-GH