eoineoineoin / glTF_Physics

Proposal for adding rigid body dynamics extension to glTF
39 stars 1 forks source link

Separate out KHR_collision from KHR_rigid_bodies (and remove triggers) #1

Closed bhouston closed 6 months ago

bhouston commented 1 year ago

I think that an extension that just specifies collision bodies would be useful outside of KHR_rigid_bodies (which is what I would name this proposal.)

I think that KHR_collisions can be useful for a lot of different things. Just as VR controller hits, mouse clicks on objects, and touches on objects. I also think they can be useful in KHR_behavior for detecting overlaps between objects.

I do not think we need the trigger part of this KHR_rigid_bodies, instead KHR_behavior will have overlap detection and it can act on that. I suggest not having it in trigger in this extension because it doesn't really do anything here by itself. Instead it is use using KHR_collision to trigger events.

javagl commented 1 year ago

Going one step further (and I know, this is a long shot): I think that splitting the geometry definition and its usage could make sense. There already are proposals for "defining geometric objects", and this is related to a comment that I left on one of these proposals.

The current proposal adds the extension object to a node. There may be a mesh attached to that node. And the extension object itself defines the collider. The collider may be again a mesh, or one of the special collider types (like shere).

For example, the following node renders a mesh:0, and uses a mesh:1 as its collider:

  "nodes" : [
    {
      "mesh" : 0,
      ...
      "extensions" : {
        "MSFT_physics" : {
          "collider" : {
            ...
            "convex" : {
              "mesh" : 1
            }
          }
        }
      },
    },

The mesh:1 can be imagined as an approximation of the rendered mesh. This approximation is supposed to be used for the collision detection. In this case, it is a convex hull, but for other meshes, it may be an even simpler representation, like a sphere.

(The fact that the convex refers to a mesh raises the question: How to ensure that this mesh actually is a convex hull, and not a "real", arbitrarily-shaped, complex mesh?)


Pulling out the definition of "geometric objects" would allow to define the same things that are currently supported via the colliders, but regardless of their intended usage. These "geometric objects" could then be a special "incarnation" of meshes, so to speak.

Meshes could then be defined as such "geometric objects", roughly like this:

    meshes: {
        extensions {
            TODO_geometric_object {
                sphere: {
                    radius: 123
                }
            }
        }
    }

These "geometric/parametric meshes" could then be used for rendering and as "collider meshes" - roughly like this:

    meshes: [
      /* 0 : The high-detail mesh that will be rendered, as a standard glTF mesh */
      /* 1 : A convex hull of mesh 0 (may also be a standard glTF mesh) */
      /* 3 : A geometric object, e.g. a sphere, defined as above */
    ]
    nodes : [

      // A node that renders the high-res mesh and uses 
      // the convex hull as its collider
      {
        mesh : 0,
        ...
          collider : { mesh : 1 }
      }

      // A node that renders the high-res mesh and uses 
      // the sphere as its collider
      {
        mesh : 0,
        ...
          collider : { mesh : 2 }
      }

      // A node that renders the sphere (!) and also uses
      // the sphere as its collider
      {
        mesh : 2,
        ...
          collider : { mesh : 2 }
      }
   ]
eoineoineoin commented 1 year ago

Not opposed to any kinds of renames at all - "rigid bodies" would certainly be better than "physics" in that regard.

However, I'm giving a bunch of thought to what a split would look like. I'm not sure my opinion is fully formed here, but here's sort of a brain-dump of my current thinking.

It was very useful to hear that there was interest in use-cases for simply specifying collision volumes. From our perspective, I'd be reluctant to specify our new primitives (sphere, capsule, hull, etc.) as a type which could be rendered - the existing glTF specification is focussed on triangles; allowing the ability to render spheres would add some complexity, which I think we'd see some push back on? I imagine that those primitives would need to mandate a specific tesselation algorithm (I'd worry about assigning UVs, for example) and things like how those primitives would work with morph targets, skinning, etc. my own background is much more in physics than in graphics, so I don't feel I have sufficient authority to weigh in here. Not sure if you have strong opinions here, Marco?

But, suppose we split it up into a "KHR_collision" and "KHR_rigidbody" spec. It really would be super to enable these additional use-cases (say, for 3D UI) which didn't need simulation. For a single application, you could load a set of assets which contained only KHR_collision nodes and get appropriate behaviour. However, for a more complex application which contained both a rigid body simuation as well as a 3D UI, we'd need some method to distinguish the intended usage of a KHR_collision node. Ben's suggestion that KHR_collision nodes would generate "trigger-like" events is certainly interesting and something I could get behind, but I wonder if there's any use-cases for which that might be undesirable? Can't think of any at the moment, so I think it's a good idea.

To support that, I think that the KHR_collision probably wouldn't have any concrete use (outside of applications with a very narrow scope) and the KHR_rigidbody specification would need to refer to KHR_collision and add some additional fields for physics colliision response which wouldn't be applicable to other use-cases. e.g., the schema would read something like:

KHR_rigidbody.physics.collider.schema.json

{
    "title" : "KHR_physics glTF extension",
    "type" : "object",
    "$ref" : "node.HKR_collision.collider.schema.json"
    "description" : "Parameters describing a physics collision geometry."
    "properties" : {
        "material": {
        "rigidbodyMaterial" : {
            "allOf": [ { "$ref": "glTFid.schema.json" } ],
            "description": "The index of the physics material in the top level rigidbodyMaterials array."
        },
...

i.e., the KHR_rigidbody declares a type of "collider" object which inherits the properties of KHR_collider and adds some additional ones specific to physics simulation.

The other alternative would be to add a "collider" field of type KHR_collision.collider to "rigid_body," but I'd be reluctant to do that, as I really do like the "implicit static" behaviour we get with the spec as-is. It reduces the amount of parameters and types required to describe the scene; otherwise, we'd need an object to distinguish a static body from a dynamic one.

A 3D UI "collision" volume would need something similar, inheriting from KHR_collider. This feels a little clunky, but I don't see any other way we could distinguish the intended usage of those colliders. Maybe this is acceptable? When designing "MSFT_Physics", we worked really hard to minimize the amount of types and parameters they had, which is why capsules, colliders and joints use an additional node in the tree to specify a basis for those types.

(The fact that the convex refers to a mesh raises the question: How to ensure that this mesh actually is a convex hull, and not a "real", arbitrarily-shaped, complex mesh?)

I don't think this is a technical issue (maybe just documentation) - I don't think we should make such a requirement that the mesh be convex. It would be very hard to enforce, and probably just frustrate content creators. We used a reference to a mesh in order to minimize the amount of additional types that were required in the specification and the collision geometry that you get out should be a convex hull which encloses the mesh, which I think is alright; a convex hull with vertices {a, b, c, d} is by definition equivalent to a hull {a, b, c, d, (a+b+c+d) * 0.25} in terms of the volume they represent.

In the demo I showed, the two highlighted objects refer to the same (concave) mesh, and it's the responsibility of the physics simulation to generate the hull and again, I don't want to mandate a particular algorithm here, but physics engines will typically use a well-known algorithm (e.g. quickhull) to calculate a minimal convex hull from an arbitrary set of vertices.

2022-11-25 13_11_46-Havok-Hulls

bhouston commented 1 year ago

@eoineoineoin wrote:

Not opposed to any kinds of renames at all - "rigid bodies" would certainly be better than "physics" in that regard.

Given there are a lot of types of physics, this makes a lot of sense.

@javagl wrote:

I think that splitting the geometry definition and its usage could make sense.

@eoineoineoin wrote:

From our perspective, I'd be reluctant to specify our new primitives (sphere, capsule, hull, etc.) as a type which could be rendered

I am not completely sold on having uniform primitives for rendering and also using them as collision geometry. I understand the reasoning, but they are so rarely used and it would require a bunch of work to do adaptive tessellation based on view that I am not sure it is worth it. Personally I am not in favour of this split to have renderable geometry primitives.

@eoineoineoin wrote:

To support that, I think that the KHR_collision probably wouldn't have any concrete use (outside of applications with a very narrow scope)

I think it would be useful in KHR_behavior in allowing people to specify collision geometry for when you can click on a node or interactive with it in many different ways.

Here is an example of KHR_behavior's behavior graph in action - click on the node to see things start to move - KHR_collision could make this more efficient:

https://interx.on.fleek.co

The reason why I do not want to say use KHR_rigid_body/physics is because maybe you don't actually have a physics engine and thus you can not support all of that extension, but you do support clicking on nodes.

On the web, people click on things constantly. There is a lot less things to do with physics.

@eoineoineoin wrote:

the KHR_rigidbody declares a type of "collider" object which inherits the properties of KHR_collider and adds some additional ones specific to physics simulation.

I am not sure it has to derive from it, because that would mean things that could use the KHR_collider objects would have to look for KHR_rigid_bodies as well. Instead you could have KHR_rigid_body require KHR_collider. Basically KHR_rigid_body uses KHR_collidier information in its simulation.

BTW this isn't new. Another group came up with this idea independently: https://github.com/omigroup/gltf-extensions/blob/15e397a24c93bff3448d797eecacb9fde6b0177d/extensions/2.0/OMI_collider/README.md. Although I think that whether or not a collider is a trigger is something that is defined externally to the collider specification.

eoineoineoin commented 1 year ago

Hey Ben,

Don't get me wrong - I'm very much willing to seperate the collision from rigid bodies, but I think there's a few details which would need to be worked out. To me, it feels like having a "collider" node by itself isn't sufficient for a content creator to describe the intended usage; there probably needs to be another object to describe the semantics of what that collider represents.

I have two issues in-mind:

Right now, for dynamic bodies, we say "their collision geometry is the union of all child colliders" (consider a car, which would be a dynamic body, with cylindrical colliders for wheels and convex colliders to represent the chassis) - this is also the same strategy that your linked OMI_collider uses. However, it's concievable that if colliders were used for UI nodes as well, you might want to parent a UI node underneath a rigid body, so that the UI moves with the object that it's associated with. I don't know how in this scenario, we can distinguish between a collider which is used for collision detection versus UI. One approach might be to make a new collider definition for a "compound" which has an array of child node indices, explicitly declaring a compound collision geometry - I don't really like this, as it feels like it's a poor-man's implementation of the existing scene tree.

Secondly, there's the "physics material" properties; obviously, we want to be able to specify a different material for wheels versus a chassis; these properties would not belong in the KHR_colliders spec, since they're not applicable to non-physics use-cases. To me, that implies that KHR_rigidbody would add an object which sits alongside the collider; the existance of which would imply that the geometry should generate a physical response (and therefore, the collider be incorporated into the physics simulation) - this would still need some careful consideration; I'd really like to be able to specify a material in such a way that it was still inherited by child colliders. e.g.:

WineGlass {RigidBody, Material(Glass)}
     Base {Collider}
     Stem {Collider}
     Bowl {Collider}

But a scenario like that would imply that nodes intended for UI would go into the physics sim, which, due to the first issue, I think is undesirable. I imagine a content creator concerned with UI and physics would want to describe something which is semantically:

WineGlass {RigidBody, Material(Glass)}
     Base {PhysicsCollider}
     Stem {PhysicsCollider}
     Bowl {PhysicsCollider}
     FillGlassButton {UICollider}
     EmptyGlassButton {UICollider}

Now, in this kind of scenario, the material could be moved to sit beside the individual physics-collision nodes:

WineGlass {RigidBody}
     Base {Collider, Material(Glass)}
     Stem {Collider, Material(Glass)}
     Bowl {Collider, Material(Glass)}
     FillGlassButton {Collider}
     EmptyGlassButton {Collider}

It does feel like there's some unnecessary redundancy in there and potential for confusion due to unexpected behaviour due to a missing Material node, but maybe this would be a tooling UX issue. If the scene was laid out in this way, the Material node effectively becomes the "you should put this collider into your physics sim" tag, which might be an acceptable way to describe that semantic difference? I imagine a UI node would probably want some analogous properties to describe how it behaves, anyway?

Eoin

eoineoineoin commented 1 year ago

I'll also note that the USD Physics specification doesn't have any "free" colliders which aren't associated with physics collision detection. Personally, I'd really like to be able to keep the "USD Physics" as similar as possible to the "glTF Physics," so will mention this to the USD group and see if I can get some additional viewpoints here.

javagl commented 1 year ago

(@eoineoineoin) Not sure if you have strong opinions here, Marco?

(@bhouston) I am not completely sold on having uniform primitives for rendering and also using them as collision geometry.

What I wrote there was not intended as a "proposal" of any sorts.

I just noticed the overlap:

I don't know enough about rendering, simulation, or collision detection to propose any "solution" here. And I am aware of many of the specifics that come into play in each area. One example is the point that you just discussed, namely "How to organize material information (and associate it with the objects)". In the area of rendering, different questions arise - mainly that of tesselation or UV mapping.

I think that at the core, having a specification for the description of geometric objects could make sense. And one could handwavingly come up with ideas of how to "augment" these objects with the required information:

meshes: [
    { 
        "geometricObject:" { "sphere" { "radius": 123 }}},
        "tesselation" { "detail" : 100 }
        "uvMapping" { ... }
    }
],
colliders: [
    { 
        "geometricObject:" { "sphere" { "radius": 123 }}},
        "material" { "elasticity" : 0.8 }
    }
],
rigidBody: [
    { 
        "geometricObject:" { "sphere" { "radius": 123 }}},
        "bodyProperties" { "mass" : 12.34 }
    }
]

But as you see, this is only a very high-level idea, based on my experience: I hardly ever thought: "These two pieces should have been one piece". But I occasionally thought "This one piece should have been split into two pieces". Small, self-contained, client-specific 'things' (specifications, interfaces, structures) tend to be more versatile, easier to maintain, and longer-lasting.

But... ... I say all this with the huge disclaimer: Even though my gut feeling is that not defining such a fundamental core like a "parametric object description" extension will bite back at some point, I cannot profoundly propose that it should be done that way. It might well be that the requirements or caveats in the areas of rendering/simulation/collision detection are so specific for the respective field that trying to unify them does not make sense.

That's up for you (and the group) to decide.

aaronfranke commented 1 year ago

EDIT: I misunderstood this before, I did not realize that the bodies extension was defining both the shapes and the motion. With recent updates to the spec, I agree that this best, and I have updated OMI's physics to match.

For some inspiration of how this split would work, I'd recommend taking a look at the OMI_collider and OMI_physics_body extensions, which are already split as this proposal describes. OMI_collider has already been mentioned in this thread, but I figured it would be helpful to link to the latest iterations of the specs.

@eoineoineoin: i.e., the KHR_rigidbody declares a type of "collider" object which inherits the properties of KHR_collider and adds some additional ones specific to physics simulation.

The other alternative would be to add a "collider" field of type KHR_collision.collider to "rigid_body,"

Instead of either of these things, I would recommend instead having KHR_collision be defined on child glTF nodes. This is a simple solution that also automatically gives us the ability to move the shape relative to the body's origin. This is already how OMI physics works, OMI_physics_body must have OMI_collider children to function.

It was very useful to hear that there was interest in use-cases for simply specifying collision volumes.

For the shapes as generic volumes use case, note that OMI allows specifying being a trigger on either the collider or on the physics body. This is for primarily to enhance compatibility with different game engines, but it also helps with this use case. A volume can be specified as a trigger to indicate you want to use it for non-collision purposes. For example, if you want a specific volume of space to detect things, or to have different audio reverberation properties, or custom gravity (think Super Mario Galaxy), you can specify that shape as a trigger.

@eoineoineoin mentioned that KHR_collision wouldn't have a concrete use, but at least with OMI_collider, there are definitely concrete uses. A non-trigger OMI_collider without a body can be used for static level geometry, which simplifies the implementation in tools that don't want to support a full physics system but do want to support editing level geometry. The other use case is as a generic trigger volume as mentioned in the above paragraph.

I would not worry about rendering these shapes. If somebody wants to do that, they can add another extension that would take a collider shape and render it - there's no need for discussing putting it in this spec.

eoineoineoin commented 1 year ago

Hey all,

So, I was experimenting with this a little on a branch (https://github.com/eoineoineoin/glTF_Physics/tree/splitextension) - just wondering what people's thoughts on possible ways to link the "collider" spec to the "rigid bodies" spec would be. I think it's a choice of three options, each with positives/negatives. Without paying attention to the naming of the members (yet), I think they are:

Option 1

Let the collider and rigidbody sit beside each other like so:

image

Idea here is that you can add colliders to individual nodes. By themselves, they wouldn't do anything, but if that same node had a "KHR_RigidBodies" object, we could use the existence of some property (in this example, it's "physicsMaterial") to indicate that the extension responsible for importing RigidBodies should look for the KHR_CollisionGeometry object on the same node. Feels like triggers would tie nicely into this.

This has the nice property that you can add a "MyUIControl" extension to the same node and it would pick up the same collider, without duplication. However, it implies that two (otherwise independent) extensions which require collision geometry need to use the same collision geometry for their disparate representations, which I think is not always desirable (e.g., I think UIs would probably want to use boxes, rather than convex hulls)

Option 2

The node.KHR_RigidBodies.rigidBody.collider field would have a type of node.KHR_CollisionGeometry (i.e., it would just cross-reference the colliders schema:

image

This does allow you to use different colliders for different extensions, which I think makes sense, as each extension might have slightly different use-cases. It does lead to potential duplication, if you do want the same representation, but I think I'd err on the side of more flexibility, at the cost of some extra bytes.

Option 3

Follow the OMI_Physics approach (https://github.com/aaronfranke/gltf-extensions/tree/OMI_physics_body/extensions/2.0/OMI_physics_body) where the scene can have an array of colliders, which RigidBodies/UI/etc. could index into. This could potentially minimize duplication in theory, but in practice, I think it adds a horizontal dependency between extensions which should otherwise be distinct -- i.e., you have multiple extensions writing to that array and the "UI extension" would need to know how the "rigid body extension" exported the collider and would need to check for equivalence - I don't know how an extension could do this portably without knowing all the details of all the other extensions in use. Of course, if the duplication isn't a problem, I'm sure we could handle multiple extensions writing to the scene's colliders array (have not tried to write an exporter for this strategy yet.) This does have the advantage that you can share the same collider between different nodes if you're worried about memory (but this scenario gets quite complex (possibly totally intractable?) when you consider animations).

Right now, I'm leaning towards option 2, but wonder if there's any additional insights here?

aaronfranke commented 1 year ago

EDIT: I misunderstood this before, I did not realize that the bodies extension was defining both the shapes and the motion. With recent updates to the spec, I agree that this best, and I have updated OMI's physics to match.

@eoineoineoin With options 1 and 2, how are you supposed to add multiple primitive collision shapes to one body? I would recommend the way it be done is that colliders be put on child nodes. Child nodes also allow a shape to be offset and/or rotated relative to the parent body. In fact, there is a strong argument to make that be the only option, this is what we have done in OMI_collider. Especially with option 2 where the data is shoved inside the body JSON, there's not really a clear benefit to allowing this in addition to child nodes.

would need to know how the "rigid body extension" exported the collider and would need to check for equivalence - I don't know how an extension could do this portably without knowing all the details of all the other extensions in use.

This is not a problem in OMI_collider. Only the collider extension directly deals with the document-level list of colliders, and the OMI_physics_body extension uses child colliders.

The de-duplication aspect is useful for any engine that has shape resources (such as Godot) so that you don't create more resources than needed. However, this de-duplication could also be done by an importer at runtime, so technically this is not important to have in the file level.

eoineoineoin commented 1 year ago

With options 1 and 2, how are you supposed to add multiple primitive collision shapes to one body?

Haven't changed the mechanism around how this works - I agree that instancing and transforming colliders should be done via child nodes. There was a desire to allow multiple primitives per collider (for trimesh and convex types) here, but again, I don't think that'll fundamentally change how the document is structured https://github.com/eoineoineoin/glTF_Physics/issues/11#issue-1508718129

Only the collider extension directly deals with the document-level list of colliders, and the OMI_physics_body extension uses child colliders.

I actually think this is a defect and that it would prevent usage of the extension outside of simple examples. If you did go down this route, the OMI_Collider exporter extension would need to know how to inspect any possible editor object to extract the collider details. That means, a user can't add an editor object which contains a collider, as the OMI_Collider object won't know where to look for it. The responsibility for exporting colliders must be left with the extension which actually makes use of that collider (i.e. the RigidBody extension needs to be able to write into the Collider extension objects.)

aaronfranke commented 1 year ago

EDIT: I misunderstood this before, I did not realize that the bodies extension was defining both the shapes and the motion. With recent updates to the spec, I agree that this best, and I have updated OMI's physics to match.

@eoineoineoin I don't understand why a RigidBody extension would need to write into the collider extension directly. A RigidBody must have a collider shape to have any function, and that shape would be written by the exporter. I also don't know what you mean by editor object.

eoineoineoin commented 1 year ago

Sorry, let me be more clear with an example. Suppose you had two seperate exporters for OMI_Collision and OMI_RigidBody. OMI_Collision will write colliders, while OMI_RigidBody will write rigid body data.

In Blender, the Blender object has a field "rigid_body", which has a pointer to a collider that Blender uses for collision geometry. The "OMI_Collision" exporter would have to inspect the (Blender) rigid_body. If a user added a field[0] to the Blender object, say "my_3d_button_widget" which also had a pointer to a collider, "OMI_Collision" would have to know look inside that, too! Now, "OMI_Collision" has a hidden dependency on the "OMI_RigidBody" and "OMI_My_3D_Widget" extension, when, in fact, the dependency should be the other way around. This obviously doesn't scale when you consider that users can have arbitrary numbers of niche/unpublished extensions.

The only way I can see a clean design around exporters like this is if "OMI_RigidBody" would write the rigidbody colliders, "OMI_My_3D_Widget" would write 3d-widget colliders and there wouldn't even be an exporter for "OMI_Collision." This isn't necessarily a bad thing (don't get me wrong!) but it feels like there might be complications from two exporters attempting to write to a shared, scene-level node.

A RigidBody must have a collider shape to have any function

I know it's not the main topic of discussion, but this is actually not quite right; a rigid body only needs mass properties. This is useful when you have constrained systems of joints - you can simulate (e.g.) swinging lights and don't need to add any additional geometry to the simulation.

[0] This is what I meant by "editor object" - any sort of object in the editor, whether that's an arbitrary field in Blender, a component in Unity, a node with a particular class in Godot, just the concept that the user has added something in the editor which they can assign a collider to.

aaronfranke commented 1 year ago

EDIT: I misunderstood this before, I did not realize that the bodies extension was defining both the shapes and the motion. With recent updates to the spec, I agree that this best, and I have updated OMI's physics to match.

The dependency is the other way around, "OMI_RigidBody" and "OMI_My_3D_Widget" depend on the collision.

The best way I can see to go about this is to make the exporters for "OMI_RigidBody" and "OMI_My_3D_Widget" pass along the collision pointer to the part that exports "OMI_Collision". Then there's only one part of the code that handles the responsibility of writing collision shapes to the glTF file. And the part of the code that deals with particular editor objects with collision fields only deals with the existence of them and passing that data to the other part.

(btw, the extensions OMI has are called OMI_collider and OMI_physics_body, but I used the same names as you)

javagl commented 1 year ago

I'm not deeply involved in the details of the recent discussion here. But looking at "Option 2", which defines

"collider": {
    "pyhsicsMaterial": 1,
    `"box": { "size": [2,2,2] }
}

I have to ask a question that is similar to the gist of my fist comment here: Why is the box inlined, and not an index? Whatever the answer is, there's the follow-up question: Why is the physicsMaterial defined with an index, but the shape (box) is not defined with an index?

One aspect that may be relevant here is that using an index could reduce redundancy. Consider

"collider": {
    "pyhsicsMaterial": 0,
    "box": { "size": [2,2,2] }
}
...
"collider": {
    "pyhsicsMaterial": 1,
    "box": { "size": [2,2,2] }
}
...
"collider": {
    "pyhsicsMaterial": 2,
    "box": { "size": [2,2,2] }
}
...

versus

"shapes": [ {
    `"box": { "size": [2,2,2] }
} ],
...
"collider": {
    "pyhsicsMaterial": 0,
    "shape": 0
}
...
"collider": {
    "pyhsicsMaterial": 1,
    "shape": 0
}
...
"collider": {
    "pyhsicsMaterial": 2,
    "shape": 0
}
...

It would allow modeling the concept of identity cleanly (which might be related to some of the recent discussion - again, I have to read that more thoroughly)

An aside: This is unrelated to the question of whether "shapes" should be extracted into their own TODO_geometric_shapes extension. The question of whether something is repeatedly inlined or referred to via an index also applies to the elements within one extension, with the same implications (of being able to avoid redundancy and model identity).

eoineoineoin commented 1 year ago

From the discussion we had in the 3D formats meeting last week, there's divided opinions on this, but I think Marco is correct - while it's true that it adds complexity to the importers/exporters and in practice, I rarely see the same shapes re-used on different nodes (at least in the AAA games industry,) it's important for people who do need that functionality. I'll re-shuffle the extension appropriately.

aidinabedi commented 1 year ago

Hello @eoineoineoin! Having thought significantly more about this, I completely agree. Reusable colliders opens up much more interesting possibilities and is extremely valuable for those that need it.

In fact, having discussed internally - a natural need is reuse of compound colliders like that in bullet, physx, and Unreal :). Unlike a node tree, a compound collider would just be simple array of transforms and shapes - and importantly it would be possible to reuse complex collision volumes made out of simple primitives that are naturally configured to not collide internally (without the need for masks). It would mirror the array of primitives in gltf's mesh object and also fit perfectly with the APIs I've reviewed in physx and bullet. In Unreal, we actually tie the compound collider to the mesh so it would be a big use there as well.

aaronfranke commented 1 year ago

@aidinabedi I am against compound colliders, it would make things more complicated for little benefit.

I would prefer that if you need multiple collider shapes, you add each as a collider node, with each node only having one shape. Then these can be combined under the body, and physics engines can optionally treat multiple shapes in one body as a compound shape if that's supported. This is also why I'm in favor of a static bodies (via a string enum instead of this repo's isKinematic flag), so you can combine multiple shapes under one body and avoid them colliding internally etc.

Basically, my preference is: make collider shape nodes, and the only thing that can combine them is a body.

eoineoineoin commented 1 year ago

I'm inclined to make joints a document-level property, too, just to make the whole spec consistent with respect to component re-use. i.e., instead of specifying the limits in the node, it indexes into the document:

        {
            "name" : "jointSpaceA",
            "rotation" : [....],
            "translation": [...]
            "extensions" : {
                "MSFT_RigidBodies" : {
                    "joint" : {
                        "connectedNode" : 0,
                        "enableCollision" : false,
                        "constraintLimits:" 0               <- indexes into an array in the document
                    }
                }
            },
        },

Where the document would have extension data like:

"extensions" : {
        "MSFT_RigidBodies" : {
               "physicsJoints": [
                     [ 
                            { "linearAxes" : [0, 1, 2 ] }
                            { "angularAxes" : [1], min: -0.78, max: 0.78 }
                     ]                                                 <- A door hinge
               ]
      }
}

Any objections?