jrouwe / JoltPhysics.js

Port of JoltPhysics to JavaScript using emscripten
MIT License
246 stars 19 forks source link

GetScale() on ScaledShape throwing error #176

Closed DennisSmolek closed 3 months ago

DennisSmolek commented 3 months ago

I have a shape that gets returned from ScaleShape() that I double check actually is a ScaledShape. I then try to get the scale from it using GetScale()

I get an error thrown that GetScale() is not a function.

Code:

const joltScale = new Jolt.Vec3(1,2,3);
const newShape = baseShape.ScaleShape(joltScale).Get();

// check if the new shape is a scaled shape
if (newShape.GetSubType() === Jolt.EShapeSubType_Scaled) {
    console.log(
        "this is a scaled shape",
        newShape.GetSubType(),
        Jolt.EShapeSubType_Scaled
    );
    actualScale = vec3.three(newShape.GetScale());
}

In the console I get:

this is a scaled shape, 10, 10;
Uncaught:
TypeError: newShape.GetScale is not a function

I AM scaling a compound shape, however the subShapes aren't scaled or rotated. And if I test for a static compound it fails, so I know it's a Jolt.ScaledShape

Sidenote, in exploring the source for ScaleShape() I noticed that it automatically returns a StaticCompoundShape regardless of if the shape is a staticCompoundShape or MutableCompoundShape Not sure if that will be an issue for me later but is something I noticed..

DennisSmolek commented 3 months ago

GetInnerShape() is also failing...

DennisSmolek commented 3 months ago

Even hardcoding the shape to a ScaledShape fails:

    const newShape = new Jolt.ScaledShape(baseShape, joltScale);

So something's not wired up correctly for ScaledShapes

LeXXik commented 3 months ago

Are you sure you are using a scaled shape? Try wrapping it:

const scaledShape = Jolt.castObject(newShape, Jolt.ScaledShape);

Edit: ah, I meant castObject, of course, not wrap pointer

jrouwe commented 3 months ago

The correct code is:

const joltScale = new Jolt.Vec3(1,2,3);
const newShape = baseShape.ScaleShape(joltScale).Get();

// check if the new shape is a scaled shape
if (newShape.GetSubType() === Jolt.EShapeSubType_Scaled) {
    console.log(
        "this is a scaled shape",
        newShape.GetSubType(),
        Jolt.EShapeSubType_Scaled
    );
    const scaledShape = Jolt.castObject(newShape, Jolt.ScaledShape);
    actualScale = vec3.three(scaledShape.GetScale());
}

ScaleShape returns a ShapeResult which contains a pointer to a Shape which Get() returns. The GetScale function exists on ScaledShape so you need to cast your object from Shape to ScaledShape before you can access any of its member functions.

jrouwe commented 3 months ago

Sidenote, in exploring the source for ScaleShape() I noticed that it automatically returns a StaticCompoundShape regardless of if the shape is a staticCompoundShape or MutableCompoundShape Not sure if that will be an issue for me later but is something I noticed..

A StaticCompoundShape is generally faster, and I think you should not rely on the internal shape structure once you've called ScaleShape as it will flatten the entire shape (e.g. if you created a compound of compounds you will also get a single compound back). If you're using mutable compounds and want to keep adding/removing shapes then you should probably implement your own logic to push the scale towards the leaves so that your bookkeeping stays in sync.

DennisSmolek commented 3 months ago

ScaleShape returns a ShapeResult which contains a pointer to a Shape which Get() returns. The GetScale function exists on ScaledShape so you need to cast your object from Shape to ScaledShape before you can access any of its member functions.

So castObject cleared this issue.

Perhaps it's because I'm mostly a JS dev but wouldn't (newShape.GetSubType() === Jolt.EShapeSubType_Scaled) only return true if it is a ScaledShape and not a Shape?

In javascript we have both typeof and instanceOf that can let us do class comparisons. So when I test for that value I assume it has the full class structure.

In Jolt, is the object just a wrapper around a data structure? like, Shape.GetSubType() and ScaledShape.GetSubType() are accessing some internal data structure and not properties of the class themselves?

Please forgive my ignorance...

jrouwe commented 3 months ago

The way I think it works (this is something that's done by emscripten and not by me) is that there is a ScaledShape object somewhere on the C++ heap. Whenever an object is returned to JS, a wrapper object is created that contains the address on the heap and exposes the functions of that particular object based on the return type of the function (Shape in this case). I'm not sure if typeof or instanceOf does anything in the case of this wrapper object. I don't think JS is aware of the actual underlying C++ object, so it also doesn't know its exact type. That's why you have to cast it to a particular JS object type using the Jolt.castObject function (which is also automatically generated by emscripten). The reason why GetSubType() works is that it is a function that is defined on Shape which calls into the C++ code to ask the actual C++ type of the object (and not what JS happened to wrap around it).