diff --git a/extensions/2.0/OMI_physics_body/README.trigger.md b/extensions/2.0/OMI_physics_body/README.trigger.md index d13be34..702ec63 100644 --- a/extensions/2.0/OMI_physics_body/README.trigger.md +++ b/extensions/2.0/OMI_physics_body/README.trigger.md @@ -1,18 +1,29 @@ # OMI_physics_body Trigger Property -If a node has the `"trigger"` property defined, it has a non-solid trigger shape that can detect when objects enter it. +A useful construct in a physics engine is a non-solid volume of space which does not generate impulses when overlapping with other volumes. These objects are typically called "triggers", "sensors", "phantoms", or "overlap volumes" in physics simulation engines. Triggers allow specifying such volumes either as a single shape or combination of nodes with shapes. -Triggers are not solid and do not "collide" with other objects, but can generate events when another physics body "enters" them. For example, a "goal" area which triggers whenever a ball gets thrown into it. +A trigger is added to a glTF node by specifying the `"trigger"` property inside of a node's `"OMI_physics_body"` extension. + +A `"trigger"` may specify a `"shape"` property which references a geometric shape defined by the `OMI_physics_shape` extension. Alternatively, a `"trigger"` may have a `"nodes"` property, which is an array of glTF nodes which make up a compound trigger on this glTF node. The nodes in this array must be descendent nodes which must have `"trigger"` properties. At least one of `"shape"` or `"nodes"` must be set to a valid value. + +As the name "trigger" suggests, implementations may use these shapes as sensors that generate overlap events, which can be used to trigger things. What behavior gets triggered is outside the scope of this extension, but may be defined in other glTF extensions or application-specific logic. ## Trigger Properties -| | Type | Description | Default value | -| --------- | --------- | --------------------------------------------------- | ------------- | -| **shape** | `integer` | The index of the shape to use as the trigger shape. | -1 | +| | Type | Description | Default value | +| --------- | ----------- | ------------------------------------------------------------------------------------------------------------------- | ------------- | +| **shape** | `integer` | The index of the shape to use as the trigger shape. | -1 | +| **nodes** | `integer[]` | For compound triggers, the set of descendant glTF nodes with a trigger property that make up this compound trigger. | [] | ### Shape -The `"shape"` property is an integer index that references a shape in the document-level shapes array as defined by the `OMI_physics_shape` extension. If not specified or -1, this node has no trigger shape, but may be the parent of other nodes that do have trigger shapes, and should combine those nodes into one trigger (this may be a body or compound trigger depending on the engine). +The `"shape"` property is an integer index that references a shape in the document-level shapes array as defined by the `OMI_physics_shape` extension. If not specified or -1, this node has no trigger shape, but may have `"nodes"` defined to create a compound trigger. + +### Nodes + +The `"nodes"` property is an array of integer indices that reference descendant glTF nodes with a trigger property, which make up a compound trigger on this glTF node. If not specified or empty, this node is not a compound trigger. + +When this property is set and contains valid items, this indicates that this glTF node is a compound trigger. Each item is the index of a glTF node that must have its own OMI_physics_body trigger property, and must be a descendant of this node. ## JSON Schema diff --git a/extensions/2.0/OMI_physics_body/examples/basic/compound_trigger.gltf b/extensions/2.0/OMI_physics_body/examples/basic/compound_trigger.gltf new file mode 100644 index 0000000..589e503 --- /dev/null +++ b/extensions/2.0/OMI_physics_body/examples/basic/compound_trigger.gltf @@ -0,0 +1,72 @@ +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": ["OMI_physics_body", "OMI_physics_shape"], + "extensions": { + "OMI_physics_shape": { + "shapes": [ + { + "type": "box", + "box": { + "size": [3, 1, 1] + } + }, + { + "type": "box", + "box": { + "size": [1, 3, 1] + } + } + ] + } + }, + "nodes": [ + { + "children": [1, 2, 3], + "extensions": { + "OMI_physics_body": { + "trigger": { + "nodes": [1, 2] + } + } + }, + "name": "CompoundTriggerL" + }, + { + "extensions": { + "OMI_physics_body": { + "trigger": { + "shape": 0 + } + } + }, + "name": "BottomOfL", + "translation": [1, 0, 0] + }, + { + "extensions": { + "OMI_physics_body": { + "trigger": { + "shape": 1 + } + } + }, + "name": "TopOfL", + "translation": [0, 2, 0] + }, + { + "extensions": { + "OMI_physics_body": { + "trigger": { + "shape": 0 + } + } + }, + "name": "SeparateTrigger", + "translation": [0, 0, 4] + } + ], + "scene": 0, + "scenes": [{ "nodes": [0] }] +} diff --git a/extensions/2.0/OMI_physics_body/examples/triggers/sloped_floor_color.png b/extensions/2.0/OMI_physics_body/examples/triggers/sloped_floor_color.png new file mode 100644 index 0000000..3c3107a Binary files /dev/null and b/extensions/2.0/OMI_physics_body/examples/triggers/sloped_floor_color.png differ diff --git a/extensions/2.0/OMI_physics_body/examples/triggers/triggers.bin b/extensions/2.0/OMI_physics_body/examples/triggers/triggers.bin new file mode 100644 index 0000000..de92c26 Binary files /dev/null and b/extensions/2.0/OMI_physics_body/examples/triggers/triggers.bin differ diff --git a/extensions/2.0/OMI_physics_body/examples/triggers/triggers.gltf b/extensions/2.0/OMI_physics_body/examples/triggers/triggers.gltf new file mode 100644 index 0000000..6315195 --- /dev/null +++ b/extensions/2.0/OMI_physics_body/examples/triggers/triggers.gltf @@ -0,0 +1,535 @@ +{ + "asset": { + "generator": "Khronos glTF Blender I/O v4.0.44", + "version": "2.0" + }, + "extensionsUsed": ["KHR_lights_punctual", "OMI_physics_shape", "OMI_physics_body"], + "extensionsRequired": ["KHR_lights_punctual"], + "extensions": { + "KHR_lights_punctual": { + "lights": [ + { + "color": [1, 1, 1], + "intensity": 54.35141306588226, + "type": "point", + "name": "Light" + } + ] + }, + "OMI_physics_shape": { + "shapes": [ + { + "type": "box", + "box": { + "size": [10.376665115356445, 0.3404197692871094, 10.376665115356445] + } + }, + { + "type": "convex", + "convex": { + "mesh": 1 + } + }, + { + "type": "convex", + "convex": { + "mesh": 2 + } + }, + { + "type": "convex", + "convex": { + "mesh": 3 + } + }, + { + "type": "convex", + "convex": { + "mesh": 4 + } + } + ] + } + }, + "scene": 0, + "scenes": [ + { + "name": "Scene", + "nodes": [0, 1, 2, 4, 12] + } + ], + "nodes": [ + { + "extensions": { + "KHR_lights_punctual": { + "light": 0 + } + }, + "name": "Light", + "rotation": [-0.28416627645492554, 0.7269423007965088, 0.34203392267227173, 0.5232754945755005], + "translation": [4.076245307922363, 5.903861999511719, -1.0054539442062378] + }, + { + "camera": 0, + "name": "Camera", + "rotation": [-0.14519648253917694, 0, 0, 0.9894028902053833], + "translation": [-0.021041998639702797, 2.5271661281585693, 7.237770080566406] + }, + { + "children": [3], + "extensions": { + "OMI_physics_body": { + "collider": { + "shape": 0 + } + } + }, + "name": "Floor", + "scale": [0.16844403743743896, 0.16844403743743896, 0.16844403743743896] + }, + { + "mesh": 0, + "name": "FloorMesh" + }, + { + "children": [5], + "extensions": { + "OMI_physics_body": { + "motion": { + "mass": 1 + }, + "collider": { + "shape": 1 + } + } + }, + "name": "Cube", + "translation": [-0.0003802180290222168, 1.8371120691299438, 0.00196520215831697] + }, + { + "mesh": 1, + "name": "CubeMesh" + }, + { + "children": [7], + "extensions": { + "OMI_physics_body": { + "trigger": { + "shape": 2 + } + } + }, + "name": "ChildA", + "rotation": [0, 0, -0.7071068286895752, 0.7071068286895752], + "translation": [-0.2780584394931793, 0.6075316667556763, 0.28256291151046753] + }, + { + "mesh": 2, + "name": "ChildAMesh" + }, + { + "children": [9], + "extensions": { + "OMI_physics_body": { + "trigger": { + "shape": 3 + } + } + }, + "name": "ChildB", + "rotation": [-0.5000000596046448, 0.5, -0.5, 0.5], + "translation": [-0.2780584394931793, 0.6075316667556763, 0.28256291151046753] + }, + { + "mesh": 3, + "name": "ChildBMesh" + }, + { + "children": [11], + "extensions": { + "OMI_physics_body": { + "trigger": { + "shape": 4 + } + } + }, + "name": "Standalone", + "rotation": [-0.5000000596046448, 0.5, -0.5, 0.5], + "translation": [0.2828197777271271, 0.6075316667556763, -0.2794848382472992] + }, + { + "mesh": 4, + "name": "StandaloneMesh" + }, + { + "extensions": { + "OMI_physics_body": { + "trigger": { + "nodes": [6, 8] + } + } + }, + "children": [6, 8, 10], + "name": "Triggers" + } + ], + "cameras": [ + { + "name": "Camera", + "perspective": { + "aspectRatio": 1.7777777777777777, + "yfov": 0.39959652046304894, + "zfar": 100, + "znear": 0.10000000149011612 + }, + "type": "perspective" + } + ], + "materials": [ + { + "doubleSided": true, + "name": "FloorBaked", + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0, + "roughnessFactor": 0.5 + } + }, + { + "doubleSided": true, + "name": "Yellowish", + "pbrMetallicRoughness": { + "baseColorFactor": [0.8000000715255737, 0.7555356621742249, 0.0002703802892938256, 1], + "metallicFactor": 0.5, + "roughnessFactor": 0.800000011920929 + } + }, + { + "alphaMode": "BLEND", + "doubleSided": true, + "name": "TransparentGreen", + "pbrMetallicRoughness": { + "baseColorFactor": [0.11157119274139404, 0.8000000715255737, 0, 0.32684826850891113], + "metallicFactor": 0, + "roughnessFactor": 0.5 + } + } + ], + "meshes": [ + { + "name": "Cube.001", + "primitives": [ + { + "attributes": { + "POSITION": 0, + "NORMAL": 1, + "TEXCOORD_0": 2 + }, + "indices": 3, + "material": 0 + } + ] + }, + { + "name": "Cube", + "primitives": [ + { + "attributes": { + "POSITION": 4, + "NORMAL": 5, + "TEXCOORD_0": 6 + }, + "indices": 7, + "material": 1 + } + ] + }, + { + "name": "Cube.002", + "primitives": [ + { + "attributes": { + "POSITION": 8, + "NORMAL": 9, + "TEXCOORD_0": 10 + }, + "indices": 7, + "material": 2 + } + ] + }, + { + "name": "Cube.003", + "primitives": [ + { + "attributes": { + "POSITION": 11, + "NORMAL": 12, + "TEXCOORD_0": 13 + }, + "indices": 7, + "material": 2 + } + ] + }, + { + "name": "Cube.004", + "primitives": [ + { + "attributes": { + "POSITION": 14, + "NORMAL": 15, + "TEXCOORD_0": 16 + }, + "indices": 7, + "material": 2 + } + ] + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "mimeType": "image/png", + "name": "sloped_floor_color", + "uri": "sloped_floor_color.png" + } + ], + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 24, + "max": [5.188332557678223, 0.1702098846435547, 5.188332557678223], + "min": [-5.188332557678223, -0.1702098846435547, -5.188332557678223], + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 24, + "type": "VEC3" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 24, + "type": "VEC2" + }, + { + "bufferView": 3, + "componentType": 5123, + "count": 36, + "type": "SCALAR" + }, + { + "bufferView": 4, + "componentType": 5126, + "count": 24, + "max": [0.10373210906982422, 0.10373210906982422, 0.10373210906982422], + "min": [-0.10373210906982422, -0.10373210906982422, -0.10373210906982422], + "type": "VEC3" + }, + { + "bufferView": 5, + "componentType": 5126, + "count": 24, + "type": "VEC3" + }, + { + "bufferView": 6, + "componentType": 5126, + "count": 24, + "type": "VEC2" + }, + { + "bufferView": 7, + "componentType": 5123, + "count": 36, + "type": "SCALAR" + }, + { + "bufferView": 8, + "componentType": 5126, + "count": 24, + "max": [0.277789443731308, 0.8446961641311646, 0.277789443731308], + "min": [-0.277789443731308, -0.277789443731308, -0.277789443731308], + "type": "VEC3" + }, + { + "bufferView": 9, + "componentType": 5126, + "count": 24, + "type": "VEC3" + }, + { + "bufferView": 10, + "componentType": 5126, + "count": 24, + "type": "VEC2" + }, + { + "bufferView": 11, + "componentType": 5126, + "count": 24, + "max": [0.277789443731308, 0.8446961641311646, 0.277789443731308], + "min": [-0.277789443731308, -0.277789443731308, -0.277789443731308], + "type": "VEC3" + }, + { + "bufferView": 12, + "componentType": 5126, + "count": 24, + "type": "VEC3" + }, + { + "bufferView": 13, + "componentType": 5126, + "count": 24, + "type": "VEC2" + }, + { + "bufferView": 14, + "componentType": 5126, + "count": 24, + "max": [0.277789443731308, 0.276752769947052, 0.277789443731308], + "min": [-0.277789443731308, -0.277789443731308, -0.277789443731308], + "type": "VEC3" + }, + { + "bufferView": 15, + "componentType": 5126, + "count": 24, + "type": "VEC3" + }, + { + "bufferView": 16, + "componentType": 5126, + "count": 24, + "type": "VEC2" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 0, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 288, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 192, + "byteOffset": 576, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 72, + "byteOffset": 768, + "target": 34963 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 840, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 1128, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 192, + "byteOffset": 1416, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 72, + "byteOffset": 1608, + "target": 34963 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 1680, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 1968, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 192, + "byteOffset": 2256, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 2448, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 2736, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 192, + "byteOffset": 3024, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 3216, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 288, + "byteOffset": 3504, + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 192, + "byteOffset": 3792, + "target": 34962 + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9987 + } + ], + "buffers": [ + { + "byteLength": 3984, + "uri": "triggers.bin" + } + ] +} diff --git a/extensions/2.0/OMI_physics_body/schema/node.OMI_physics_body.trigger.schema.json b/extensions/2.0/OMI_physics_body/schema/node.OMI_physics_body.trigger.schema.json index 1d250d3..57bb2b9 100644 --- a/extensions/2.0/OMI_physics_body/schema/node.OMI_physics_body.trigger.schema.json +++ b/extensions/2.0/OMI_physics_body/schema/node.OMI_physics_body.trigger.schema.json @@ -17,7 +17,31 @@ ], "default": -1 }, + "nodes": { + "type": "array", + "description": "For compound triggers, the set of descendant glTF nodes with a trigger property that make up this compound trigger.", + "items": { + "$ref": "glTFid.schema.json" + }, + "uniqueItems": true, + "minItems": 1 + }, "extensions": { }, "extras": { } - } + }, + "anyOf": [ + { + "allOf": [ + { "required": ["shape"] }, + { "not": { "required": ["nodes"] } } + ] + }, + { + "allOf": [ + { "required": ["nodes"] }, + { "not": { "required": ["shape"] } }, + { "not": { "required": ["collisionFilter"] } } + ] + } + ] }