eoineoineoin / glTF_Physics

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

Default values for frictionCombine and restitutionCombine #33

Open aaronfranke opened 1 month ago

aaronfranke commented 1 month ago

https://github.com/eoineoineoin/glTF_Physics/blob/master/extensions/2.0/Khronos/KHR_physics_rigid_bodies/schema/glTF.KHR_physics_rigid_bodies.material.schema.json#L27-L36

        "frictionCombine": {
            "type": "string",
            "description": "Determines how friction should be combined when two objects interact.",
            "enum": ["average", "minimum", "maximum", "multiply"]
        },
        "restitutionCombine": {
            "type": "string",
            "description": "Determines how restitution should be combined when two objects interact.",
            "enum": ["average", "minimum", "maximum", "multiply"]
        },

Currently, these values do not have any defaults in the JSON schema. As far as I can tell, they are also missing default values in the README.md file. However, the schemas do not list them as required fields, and the sample files including Materials_Friction.gltf and Materials_Restitution.gltf have several materials that do not define them. What are the expected values of frictionCombine and restitutionCombine when they are not present?

aaronfranke commented 1 month ago

The same problem exists for joint limit values. The schema does not specify default values for "min" or "max", and the schema does not list them as required either. I assume the default for these should be 0.0 representing a fixed joint, which is consistent with the JointTypes.gltf example file having 0.0 for most instances of "min" and "max".

There is also "stiffness", which the schema specifies in the description to have infinite stiffness if not present. Should it have a default value written? Since a stiffness of 0.0 is the same as not having a joint limit at all, perhaps stiffness could default to 0.0 and a value of zero should be treated as infinitely stiff. Or, perhaps a negative value should be treated as infinitely stiff, and -1.0 would be the default value.

eoineoineoin commented 1 month ago

I'm comfortable leaving this as implementation-defined when not specified. Surveying how existing engines combine materials, Bullet and Cannon use the product of the values, PhysX and Rapier use the average, Godot uses the sum for restitution and the minimum for friction, Havok uses the minimum for friction and the maximum for restitution, Jolt uses the geometric mean for friction and the maximum for restitution, while ODE and Newton are completely user-defined.

With the exception of Havok, I'm not privy to why those defaults were chosen, but it's presumably for good reason, and there's no reason to say why one method is better than the others.

eoineoineoin commented 1 month ago

The same problem exists for joint limit values. The schema does not specify default values for "min" or "max", and the schema does not list them as required either. I assume the default for these should be 0.0 representing a fixed joint, which is consistent with the JointTypes.gltf example file having 0.0 for most instances of "min" and "max".

No, a not-supplied value should be taken to mean unlimited along that direction. I'll update the documentation to make this explicit.

There is also "stiffness", which the schema specifies in the description to have infinite stiffness if not present. Should it have a default value written? Since a stiffness of 0.0 is the same as not having a joint limit at all, perhaps stiffness could default to 0.0 and a value of zero should be treated as infinitely stiff. Or, perhaps a negative value should be treated as infinitely stiff, and -1.0 would be the default value.

Neither of these options are great; 0 is a valid value for stiffness, while using a negative value maps multiple values onto Infinity, and in the wrong direction, which complicates validation and animation. I think the current formulation is fine; if an animation wants to transition from a disabled limit to an infinitely stiff one, the stiffness can be set to some arbitrarily high value, which effectively behaves identically to an infinite stiffness.

aaronfranke commented 1 month ago

Neither of these options are great

So, "default": "Infinity" then?

aaronfranke commented 1 month ago

No, a not-supplied value should be taken to mean unlimited along that direction.

I'm confused, what would be the difference between specifying a joint axis limit of unlimited, versus not specifying that limit for a joint axis?

        "KHR_physics_rigid_bodies": {
            "physicsJoints": [
                {
                    "limits": [
                        {
                            "linearAxes": [0]
                        },
                        // Limits that aren't for liner axis 0.
                    ]
                }
            ]
        }

Versus:

        "KHR_physics_rigid_bodies": {
            "physicsJoints": [
                {
                    "limits": [
                        // Limits that aren't for liner axis 0.
                    ]
                }
            ]
        }

The only other values in the joint limit are stiffness and damping, which are only used when beyond the limit. So an unlimited limit seems completely useless.

eoineoineoin commented 1 month ago

Neither of these options are great

So, "default": "Infinity" then?

That would require the field to be a union of numbers and strings, which is also not great. Not every field has to have a default value, so I'd keep the formulation as-is.

No, a not-supplied value should be taken to mean unlimited along that direction.

I'm confused, what would be the difference between specifying a joint axis limit of unlimited, versus not specifying that limit for a joint axis? ... The only other values in the joint limit are stiffness and damping, which are only used when beyond the limit. So an unlimited limit seems completely useless.

The two examples you have provided would behave the same, however, consider that in the former, another mechanism such as KHR_interactivity could modify those limits at runtime, which can't be done in the latter case. You might also consider the case where only one of min/max was provided:

        "KHR_physics_rigid_bodies": {
            "physicsJoints": [
                {
                    "limits": [
                        {
                            "linearAxes": [0],
                            "min": 0
                        },
                        // Limits that aren't for liner axis 0.
                    ]
                }
            ]
        }

or

        "KHR_physics_rigid_bodies": {
            "physicsJoints": [
                {
                    "limits": [
                        {
                            "linearAxes": [0],
                            "max:" 0
                        },
                        // Limits that aren't for liner axis 0.
                    ]
                }
            ]
        }