stephengold / Libbulletjme

A JNI interface to Bullet Physics and V-HACD
https://stephengold.github.io/Libbulletjme/lbj-en/English/overview.html
Other
84 stars 10 forks source link

[question] how to set a centre of mass #32

Closed CrazyWords1 closed 3 months ago

CrazyWords1 commented 3 months ago

Based on the previous issue, I wrote a simple code to turn a json model from Minecraft into a CompoundCollisionShape using boxes.

But I encountered three oddities,

  1. The model does not want to accept setScale normally.
  2. The center of mass at the corner
  3. In minecraft itself, the model does not want to converge with the visual representation, although when using obj and v-hacd4, everything is fine.

P.S(I think I made a mistake in model conversion function, but I don't realize what I made wrong)

public static CompoundCollisionShape createCollisionShapeFromFile(String filename) throws IOException {
        JsonObject rootNode = JsonParser.parseReader(new FileReader(filename)).getAsJsonObject();

        CompoundCollisionShape compoundShape = new CompoundCollisionShape();

        JsonArray elements = rootNode.getAsJsonArray("elements");
        for (JsonElement element : elements) {

            JsonObject elementObj = element.getAsJsonObject();

            Vector3f from = parseVector(elementObj.getAsJsonArray("from"));
            Vector3f to = parseVector(elementObj.getAsJsonArray("to"));
            Vector3f halfExtents = to.subtract(from).multLocal(0.5f);

            BoxCollisionShape boxShape = new BoxCollisionShape(halfExtents);

            Vector3f offset = from.add(halfExtents);

            if (elementObj.has("rotation")) {
                JsonObject rotationObj = elementObj.getAsJsonObject("rotation");
                float angle = (float) Math.toRadians(rotationObj.get("angle").getAsFloat());
                String axis = rotationObj.get("axis").getAsString();
                Vector3f origin = parseVector(rotationObj.getAsJsonArray("origin"));

                Quaternion quaternion = new Quaternion();
                if ("x".equals(axis)) {
                    quaternion.fromAngleNormalAxis(angle, Vector3f.UNIT_X);
                } else if ("y".equals(axis)) {
                    quaternion.fromAngleNormalAxis(angle, Vector3f.UNIT_Y);
                } else if ("z".equals(axis)) {
                    quaternion.fromAngleNormalAxis(angle, Vector3f.UNIT_Z);
                }

                Vector3f correctedOffset = offset.subtract(origin);
                Quaternion vectorQuat = new Quaternion(correctedOffset.x, correctedOffset.y, correctedOffset.z, 0);
                Quaternion resultQuat = quaternion.mult(vectorQuat).multLocal(quaternion.inverse());
                Vector3f rotatedOffset = new Vector3f(resultQuat.getX(), resultQuat.getY(), resultQuat.getZ());
                rotatedOffset.addLocal(origin);

                Transform transform = new Transform(rotatedOffset, quaternion);
                compoundShape.addChildShape(boxShape, transform);
            }
        }

        return compoundShape;
    }

    private static Vector3f parseVector(JsonArray jsonArray) {
        float x = jsonArray.get(0).getAsFloat();
        float y = jsonArray.get(1).getAsFloat();
        float z = jsonArray.get(2).getAsFloat();
        return new Vector3f(x, y, z);
    }

populateSpace

        CompoundCollisionShape shape;
        try {
            shape = createCollisionShapeFromFile("F:\\json_models\\christmas-hat.json");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        PhysicsRigidBody box = new PhysicsRigidBody(shape, 10F);

        physicsSpace.addCollisionObject(box);

        // Visualize the collision objects.
        visualizeShape(floor);
        visualizeShape(box);

Test model - christmas-hat.json изображение

If you can at least give me a hint as to what I'm doing wrong, I'd really appreciate it!

stephengold commented 3 months ago

The model does not want to accept setScale normally.

Applying setScale() to a compound shape is tricky, because it's not obvious how scaling should affect the child shapes. If possible, generate the collision shape at physics-space scale to begin with.

The center of mass at the corner

The center of mass is at (0,0,0) in the shape's coordinate system. You choose where to position the child shapes relative to that center.

Have you read the tutorial page that discusses collision shapes? In particular, the section on shapes for dynamic bodies? If you're unsure how to calculate the center of mass, principal axes, and moments of inertia for your entity by hand, you may want to use the principalAxes() and correctAxes() methods mentioned in the tutorial page.

the model does not want to converge with the visual representation

The open-source Minie and SPORT projects provide debug visualization tools for solving these sorts of issues. Perhaps you can adapt them for your Minecraft environment.

CrazyWords1 commented 3 months ago

Thank you so much, I figured out how to set the center of mass, I really appreciate your help. now I'm trying to figure out why the minecraft model doesn't visually match the physical model.

CrazyWords1 commented 3 months ago

With SPORT I was able to fix the visualization of the model, and I still have one last question, how i can mirror (flip) the CompoundCollisionShape on one of the axes?

P.S ( I mean the rotation of the model itself, not the PhysicsBody )

stephengold commented 3 months ago

That looks like a rendering question, not a Libbulletjme question. Mathematically, mirroring on, say, the X axis replaces (x, y, z) with (-x, y, z). In the context of 3-D graphics, reflection might also require reversing the winding order of the polygons.

CrazyWords1 commented 3 months ago

That looks like a rendering question, not a Libbulletjme question. Mathematically, mirroring on, say, the X axis replaces (x, y, z) with (-x, y, z). In the context of 3-D graphics, reflection might also require reversing the winding order of the polygons.

I really appreciate your help, thank you, you answered all my questions