bullet icon indicating copy to clipboard operation
bullet copied to clipboard

Collisions do not work

Open Martmists-GH opened this issue 7 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