mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 11:32:13 +00:00
Merge pull request #94165 from aaronfranke/gltf-khr-anim-ptr
GLTF: Implement `KHR_animation_pointer` for animating custom properties
This commit is contained in:
commit
ef8aafc2df
@ -1389,7 +1389,7 @@ Error FBXDocument::_parse_animations(Ref<FBXState> p_state) {
|
||||
|
||||
for (const ufbx_baked_node &fbx_baked_node : fbx_baked_anim->nodes) {
|
||||
const GLTFNodeIndex node = fbx_baked_node.typed_id;
|
||||
GLTFAnimation::Track &track = animation->get_tracks()[node];
|
||||
GLTFAnimation::NodeTrack &track = animation->get_node_tracks()[node];
|
||||
|
||||
for (const ufbx_baked_vec3 &key : fbx_baked_node.translation_keys) {
|
||||
track.position_track.times.push_back(float(key.time));
|
||||
@ -1779,8 +1779,8 @@ void FBXDocument::_import_animation(Ref<FBXState> p_state, AnimationPlayer *p_an
|
||||
|
||||
double anim_start_offset = p_trimming ? double(additional_animation_data["time_begin"]) : 0.0;
|
||||
|
||||
for (const KeyValue<int, GLTFAnimation::Track> &track_i : anim->get_tracks()) {
|
||||
const GLTFAnimation::Track &track = track_i.value;
|
||||
for (const KeyValue<int, GLTFAnimation::NodeTrack> &track_i : anim->get_node_tracks()) {
|
||||
const GLTFAnimation::NodeTrack &track = track_i.value;
|
||||
//need to find the path: for skeletons, weight tracks will affect the mesh
|
||||
NodePath node_path;
|
||||
//for skeletons, transform tracks always affect bones
|
||||
|
@ -20,6 +20,7 @@ def get_doc_classes():
|
||||
"GLTFLight",
|
||||
"GLTFMesh",
|
||||
"GLTFNode",
|
||||
"GLTFObjectModelProperty",
|
||||
"GLTFPhysicsBody",
|
||||
"GLTFPhysicsShape",
|
||||
"GLTFSkeleton",
|
||||
|
@ -22,7 +22,7 @@
|
||||
The offset relative to the start of the buffer view in bytes.
|
||||
</member>
|
||||
<member name="component_type" type="int" setter="set_component_type" getter="get_component_type" default="0">
|
||||
The glTF component type as an enum. Possible values are 5120 for "BYTE", 5121 for "UNSIGNED_BYTE", 5122 for "SHORT", 5123 for "UNSIGNED_SHORT", 5125 for "UNSIGNED_INT", and 5126 for "FLOAT". A value of 5125 or "UNSIGNED_INT" must not be used for any accessor that is not referenced by mesh.primitive.indices.
|
||||
The glTF component type as an enum. See [enum GLTFComponentType] for possible values. Within the core glTF specification, a value of 5125 or "UNSIGNED_INT" must not be used for any accessor that is not referenced by mesh.primitive.indices.
|
||||
</member>
|
||||
<member name="count" type="int" setter="set_count" getter="get_count" default="0">
|
||||
The number of elements referenced by this accessor.
|
||||
@ -80,5 +80,41 @@
|
||||
<constant name="TYPE_MAT4" value="6" enum="GLTFAccessorType">
|
||||
Accessor type "MAT4". For the glTF object model, this maps to "float4x4", represented in the glTF JSON as an array of sixteen floats.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_NONE" value="0" enum="GLTFComponentType">
|
||||
Component type "NONE". This is not a valid component type, and is used to indicate that the component type is not set.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_SIGNED_BYTE" value="5120" enum="GLTFComponentType">
|
||||
Component type "BYTE". The value is [code]0x1400[/code] which comes from OpenGL. This indicates data is stored in 1-byte or 8-bit signed integers. This is a core part of the glTF specification.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_UNSIGNED_BYTE" value="5121" enum="GLTFComponentType">
|
||||
Component type "UNSIGNED_BYTE". The value is [code]0x1401[/code] which comes from OpenGL. This indicates data is stored in 1-byte or 8-bit unsigned integers. This is a core part of the glTF specification.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_SIGNED_SHORT" value="5122" enum="GLTFComponentType">
|
||||
Component type "SHORT". The value is [code]0x1402[/code] which comes from OpenGL. This indicates data is stored in 2-byte or 16-bit signed integers. This is a core part of the glTF specification.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_UNSIGNED_SHORT" value="5123" enum="GLTFComponentType">
|
||||
Component type "UNSIGNED_SHORT". The value is [code]0x1403[/code] which comes from OpenGL. This indicates data is stored in 2-byte or 16-bit unsigned integers. This is a core part of the glTF specification.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_SIGNED_INT" value="5124" enum="GLTFComponentType">
|
||||
Component type "INT". The value is [code]0x1404[/code] which comes from OpenGL. This indicates data is stored in 4-byte or 32-bit signed integers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_UNSIGNED_INT" value="5125" enum="GLTFComponentType">
|
||||
Component type "UNSIGNED_INT". The value is [code]0x1405[/code] which comes from OpenGL. This indicates data is stored in 4-byte or 32-bit unsigned integers. This is a core part of the glTF specification.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_SINGLE_FLOAT" value="5126" enum="GLTFComponentType">
|
||||
Component type "FLOAT". The value is [code]0x1406[/code] which comes from OpenGL. This indicates data is stored in 4-byte or 32-bit floating point numbers. This is a core part of the glTF specification.
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_DOUBLE_FLOAT" value="5130" enum="GLTFComponentType">
|
||||
Component type "DOUBLE". The value is [code]0x140A[/code] which comes from OpenGL. This indicates data is stored in 8-byte or 64-bit floating point numbers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_HALF_FLOAT" value="5131" enum="GLTFComponentType">
|
||||
Component type "HALF_FLOAT". The value is [code]0x140B[/code] which comes from OpenGL. This indicates data is stored in 2-byte or 16-bit floating point numbers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_SIGNED_LONG" value="5134" enum="GLTFComponentType">
|
||||
Component type "LONG". The value is [code]0x140E[/code] which comes from OpenGL. This indicates data is stored in 8-byte or 64-bit signed integers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
|
||||
</constant>
|
||||
<constant name="COMPONENT_TYPE_UNSIGNED_LONG" value="5135" enum="GLTFComponentType">
|
||||
Component type "UNSIGNED_LONG". The value is [code]0x140F[/code] which comes from OpenGL. This indicates data is stored in 8-byte or 64-bit unsigned integers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
@ -45,6 +45,16 @@
|
||||
Takes a Godot Engine scene node and exports it and its descendants to the given [GLTFState] object through the [param state] parameter.
|
||||
</description>
|
||||
</method>
|
||||
<method name="export_object_model_property" qualifiers="static">
|
||||
<return type="GLTFObjectModelProperty" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<param index="1" name="node_path" type="NodePath" />
|
||||
<param index="2" name="godot_node" type="Node" />
|
||||
<param index="3" name="gltf_node_index" type="int" />
|
||||
<description>
|
||||
Determines a mapping between the given Godot [param node_path] and the corresponding glTF Object Model JSON pointer(s) in the generated glTF file. The details of this mapping are returned in a [GLTFObjectModelProperty] object. Additional mappings can be supplied via the [method GLTFDocumentExtension._import_object_model_property] callback method.
|
||||
</description>
|
||||
</method>
|
||||
<method name="generate_buffer">
|
||||
<return type="PackedByteArray" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
@ -70,6 +80,14 @@
|
||||
[b]Note:[/b] If this method is run before a GLTFDocumentExtension is registered, its extensions won't be included in the list. Be sure to only run this method after all extensions are registered. If you run this when the engine starts, consider waiting a frame before calling this method to ensure all extensions are registered.
|
||||
</description>
|
||||
</method>
|
||||
<method name="import_object_model_property" qualifiers="static">
|
||||
<return type="GLTFObjectModelProperty" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<param index="1" name="json_pointer" type="String" />
|
||||
<description>
|
||||
Determines a mapping between the given glTF Object Model [param json_pointer] and the corresponding Godot node path(s) in the generated Godot scene. The details of this mapping are returned in a [GLTFObjectModelProperty] object. Additional mappings can be supplied via the [method GLTFDocumentExtension._export_object_model_property] callback method.
|
||||
</description>
|
||||
</method>
|
||||
<method name="register_gltf_document_extension" qualifiers="static">
|
||||
<return type="void" />
|
||||
<param index="0" name="extension" type="GLTFDocumentExtension" />
|
||||
|
@ -33,6 +33,20 @@
|
||||
This method can be used to modify the final JSON of each node. Data should be primarily stored in [param gltf_node] prior to serializing the JSON, but the original Godot [param node] is also provided if available. The node may be null if not available, such as when exporting glTF data not generated from a Godot scene.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_object_model_property" qualifiers="virtual">
|
||||
<return type="GLTFObjectModelProperty" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<param index="1" name="node_path" type="NodePath" />
|
||||
<param index="2" name="godot_node" type="Node" />
|
||||
<param index="3" name="gltf_node_index" type="int" />
|
||||
<param index="4" name="target_object" type="Object" />
|
||||
<param index="5" name="target_depth" type="int" />
|
||||
<description>
|
||||
Part of the export process. Allows GLTFDocumentExtension classes to provide mappings for properties of nodes in the Godot scene tree, to JSON pointers to glTF properties, as defined by the glTF object model.
|
||||
Returns a [GLTFObjectModelProperty] instance that defines how the property should be mapped. If your extension can't handle the property, return null, or an instance without any JSON pointers (see [method GLTFObjectModelProperty.has_json_pointers]). You should use [method GLTFObjectModelProperty.set_types] to set the types, and set the JSON pointer(s) using the [member GLTFObjectModelProperty.json_pointers] property.
|
||||
The parameters provide context for the property, including the NodePath, the Godot node, the GLTF node index, and the target object. The [param target_object] will be equal to [param godot_node] if no sub-object can be found, otherwise it will point to a sub-object. For example, if the path is [code]^"A/B/C/MeshInstance3D:mesh:surface_0/material:emission_intensity"[/code], it will get the node, then the mesh, and then the material, so [param target_object] will be the [Material] resource, and [param target_depth] will be 2 because 2 levels were traversed to get to the target.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_post" qualifiers="virtual">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
@ -109,6 +123,17 @@
|
||||
This method can be used to make modifications to each of the generated Godot scene nodes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_import_object_model_property" qualifiers="virtual">
|
||||
<return type="GLTFObjectModelProperty" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<param index="1" name="split_json_pointer" type="PackedStringArray" />
|
||||
<param index="2" name="partial_paths" type="NodePath[]" />
|
||||
<description>
|
||||
Part of the import process. Allows GLTFDocumentExtension classes to provide mappings for JSON pointers to glTF properties, as defined by the glTF object model, to properties of nodes in the Godot scene tree.
|
||||
Returns a [GLTFObjectModelProperty] instance that defines how the property should be mapped. If your extension can't handle the property, return null, or an instance without any NodePaths (see [method GLTFObjectModelProperty.has_node_paths]). You should use [method GLTFObjectModelProperty.set_types] to set the types, and [method GLTFObjectModelProperty.append_path_to_property] function is useful for most simple cases.
|
||||
In many cases, [param partial_paths] will contain the start of a path, allowing the extension to complete the path. For example, for [code]/nodes/3/extensions/MY_ext/prop[/code], Godot will pass you a NodePath that leads to node 3, so the GLTFDocumentExtension class only needs to resolve the last [code]MY_ext/prop[/code] part of the path. In this example, the extension should check [code]split.size() > 4 and split[0] == "nodes" and split[2] == "extensions" and split[3] == "MY_ext"[/code] at the start of the function to check if this JSON pointer applies to it, then it can use [param partial_paths] and handle [code]split[4][/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="_import_post" qualifiers="virtual">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
|
@ -27,6 +27,15 @@
|
||||
The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is null.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_scene_node_path">
|
||||
<return type="NodePath" />
|
||||
<param index="0" name="gltf_state" type="GLTFState" />
|
||||
<param index="1" name="handle_skeletons" type="bool" default="true" />
|
||||
<description>
|
||||
Returns the [NodePath] that this GLTF node will have in the Godot scene tree after being imported. This is useful when importing glTF object model pointers with [GLTFObjectModelProperty], for handling extensions such as [code]KHR_animation_pointer[/code] or [code]KHR_interactivity[/code].
|
||||
If [param handle_skeletons] is true, paths to skeleton bone glTF nodes will be resolved properly. For example, a path that would be [code]^"A/B/C/Bone1/Bone2/Bone3"[/code] if false will become [code]^"A/B/C/Skeleton3D:Bone3"[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_additional_data">
|
||||
<return type="void" />
|
||||
<param index="0" name="extension_name" type="StringName" />
|
||||
|
114
modules/gltf/doc_classes/GLTFObjectModelProperty.xml
Normal file
114
modules/gltf/doc_classes/GLTFObjectModelProperty.xml
Normal file
@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFObjectModelProperty" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Describes how to access a property as defined in the glTF object model.
|
||||
</brief_description>
|
||||
<description>
|
||||
GLTFObjectModelProperty defines a mapping between a property in the glTF object model and a NodePath in the Godot scene tree. This can be used to animate properties in a glTF file using the [code]KHR_animation_pointer[/code] extension, or to access them through an engine-agnostic script such as a behavior graph as defined by the [code]KHR_interactivity[/code] extension.
|
||||
The glTF property is identified by JSON pointer(s) stored in [member json_pointers], while the Godot property it maps to is defined by [member node_paths]. In most cases [member json_pointers] and [member node_paths] will each only have one item, but in some cases a single glTF JSON pointer will map to multiple Godot properties, or a single Godot property will be mapped to multiple glTF JSON pointers, or it might be a many-to-many relationship.
|
||||
[Expression] objects can be used to define conversions between the data, such as when glTF defines an angle in radians and Godot uses degrees. The [member object_model_type] property defines the type of data stored in the glTF file as defined by the object model, see [enum GLTFObjectModelType] for possible values.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="GLTF Object Model">https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/ObjectModel.adoc</link>
|
||||
<link title="KHR_animation_pointer GLTF extension">https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="append_node_path">
|
||||
<return type="void" />
|
||||
<param index="0" name="node_path" type="NodePath" />
|
||||
<description>
|
||||
Appends a [NodePath] to [member node_paths]. This can be used by [GLTFDocumentExtension] classes to define how a glTF object model property maps to a Godot property, or multiple Godot properties. Prefer using [method append_path_to_property] for simple cases. Be sure to also call [method set_types] once (the order does not matter).
|
||||
</description>
|
||||
</method>
|
||||
<method name="append_path_to_property">
|
||||
<return type="void" />
|
||||
<param index="0" name="node_path" type="NodePath" />
|
||||
<param index="1" name="prop_name" type="StringName" />
|
||||
<description>
|
||||
High-level wrapper over [method append_node_path] that handles the most common cases. It constructs a new [NodePath] using [param node_path] as a base and appends [param prop_name] to the subpath. Be sure to also call [method set_types] once (the order does not matter).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_accessor_type" qualifiers="const">
|
||||
<return type="int" enum="GLTFAccessor.GLTFAccessorType" />
|
||||
<description>
|
||||
The GLTF accessor type associated with this property's [member object_model_type]. See [member GLTFAccessor.accessor_type] for possible values, and see [enum GLTFObjectModelType] for how the object model type maps to accessor types.
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_json_pointers" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if [member json_pointers] is not empty. This is used during export to determine if a [GLTFObjectModelProperty] can handle converting a Godot property to a glTF object model property.
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_node_paths" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if [member node_paths] is not empty. This is used during import to determine if a [GLTFObjectModelProperty] can handle converting a glTF object model property to a Godot property.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_types">
|
||||
<return type="void" />
|
||||
<param index="0" name="variant_type" type="int" enum="Variant.Type" />
|
||||
<param index="1" name="obj_model_type" type="int" enum="GLTFObjectModelProperty.GLTFObjectModelType" />
|
||||
<description>
|
||||
Sets the [member variant_type] and [member object_model_type] properties. This is a convenience method to set both properties at once, since they are almost always known at the same time. This method should be called once. Calling it again with the same values will have no effect.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="gltf_to_godot_expression" type="Expression" setter="set_gltf_to_godot_expression" getter="get_gltf_to_godot_expression">
|
||||
If set, this [Expression] will be used to convert the property value from the glTF object model to the value expected by the Godot property. This is useful when the glTF object model uses a different unit system, or when the data needs to be transformed in some way. If [code]null[/code], the value will be copied as-is.
|
||||
</member>
|
||||
<member name="godot_to_gltf_expression" type="Expression" setter="set_godot_to_gltf_expression" getter="get_godot_to_gltf_expression">
|
||||
If set, this [Expression] will be used to convert the property value from the Godot property to the value expected by the glTF object model. This is useful when the glTF object model uses a different unit system, or when the data needs to be transformed in some way. If [code]null[/code], the value will be copied as-is.
|
||||
</member>
|
||||
<member name="json_pointers" type="PackedStringArray[]" setter="set_json_pointers" getter="get_json_pointers" default="[]">
|
||||
The glTF object model JSON pointers used to identify the property in the glTF object model. In most cases, there will be only one item in this array, but niche cases may require multiple pointers. The items are themselves arrays which represent the JSON pointer split into its components.
|
||||
</member>
|
||||
<member name="node_paths" type="NodePath[]" setter="set_node_paths" getter="get_node_paths" default="[]">
|
||||
An array of [NodePath]s that point to a property, or multiple properties, in the Godot scene tree. On import, this will either be set by [GLTFDocument], or by a [GLTFDocumentExtension] class. For simple cases, use [method append_path_to_property] to add properties to this array.
|
||||
In most cases [member node_paths] will only have one item, but in some cases a single glTF JSON pointer will map to multiple Godot properties. For example, a [GLTFCamera] or [GLTFLight] used on multiple glTF nodes will be represented by multiple Godot nodes.
|
||||
</member>
|
||||
<member name="object_model_type" type="int" setter="set_object_model_type" getter="get_object_model_type" enum="GLTFObjectModelProperty.GLTFObjectModelType" default="0">
|
||||
The type of data stored in the glTF file as defined by the object model. This is a superset of the available accessor types, and determines the accessor type. See [enum GLTFObjectModelType] for possible values.
|
||||
</member>
|
||||
<member name="variant_type" type="int" setter="set_variant_type" getter="get_variant_type" enum="Variant.Type" default="0">
|
||||
The type of data stored in the Godot property. This is the type of the property that the [member node_paths] point to.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_UNKNOWN" value="0" enum="GLTFObjectModelType">
|
||||
Unknown or not set object model type. If the object model type is set to this value, the real type still needs to be determined.
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_BOOL" value="1" enum="GLTFObjectModelType">
|
||||
Object model type "bool". Represented in the glTF JSON as a boolean, and encoded in a [GLTFAccessor] as "SCALAR". When encoded in an accessor, a value of 0 is false, and any other value is true.
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT" value="2" enum="GLTFObjectModelType">
|
||||
Object model type "float". Represented in the glTF JSON as a number, and encoded in a [GLTFAccessor] as "SCALAR".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT_ARRAY" value="3" enum="GLTFObjectModelType">
|
||||
Object model type "float[lb][rb]". Represented in the glTF JSON as an array of numbers, and encoded in a [GLTFAccessor] as "SCALAR".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT2" value="4" enum="GLTFObjectModelType">
|
||||
Object model type "float2". Represented in the glTF JSON as an array of two numbers, and encoded in a [GLTFAccessor] as "VEC2".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT3" value="5" enum="GLTFObjectModelType">
|
||||
Object model type "float3". Represented in the glTF JSON as an array of three numbers, and encoded in a [GLTFAccessor] as "VEC3".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT4" value="6" enum="GLTFObjectModelType">
|
||||
Object model type "float4". Represented in the glTF JSON as an array of four numbers, and encoded in a [GLTFAccessor] as "VEC4".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT2X2" value="7" enum="GLTFObjectModelType">
|
||||
Object model type "float2x2". Represented in the glTF JSON as an array of four numbers, and encoded in a [GLTFAccessor] as "MAT2".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT3X3" value="8" enum="GLTFObjectModelType">
|
||||
Object model type "float3x3". Represented in the glTF JSON as an array of nine numbers, and encoded in a [GLTFAccessor] as "MAT3".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_FLOAT4X4" value="9" enum="GLTFObjectModelType">
|
||||
Object model type "float4x4". Represented in the glTF JSON as an array of sixteen numbers, and encoded in a [GLTFAccessor] as "MAT4".
|
||||
</constant>
|
||||
<constant name="GLTF_OBJECT_MODEL_TYPE_INT" value="10" enum="GLTFObjectModelType">
|
||||
Object model type "int". Represented in the glTF JSON as a number, and encoded in a [GLTFAccessor] as "SCALAR". The range of values is limited to signed integers. For [code]KHR_interactivity[/code], only 32-bit integers are supported.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
@ -38,6 +38,7 @@ void GLTFDocumentExtension::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_parse_image_data, "state", "image_data", "mime_type", "ret_image");
|
||||
GDVIRTUAL_BIND(_get_image_file_extension);
|
||||
GDVIRTUAL_BIND(_parse_texture_json, "state", "texture_json", "ret_gltf_texture");
|
||||
GDVIRTUAL_BIND(_import_object_model_property, "state", "split_json_pointer", "partial_paths");
|
||||
GDVIRTUAL_BIND(_import_post_parse, "state");
|
||||
GDVIRTUAL_BIND(_import_pre_generate, "state");
|
||||
GDVIRTUAL_BIND(_generate_scene_node, "state", "gltf_node", "scene_parent");
|
||||
@ -48,6 +49,7 @@ void GLTFDocumentExtension::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node");
|
||||
GDVIRTUAL_BIND(_export_post_convert, "state", "root");
|
||||
GDVIRTUAL_BIND(_export_preserialize, "state");
|
||||
GDVIRTUAL_BIND(_export_object_model_property, "state", "node_path", "godot_node", "gltf_node_index", "target_object", "target_depth");
|
||||
GDVIRTUAL_BIND(_get_saveable_image_formats);
|
||||
GDVIRTUAL_BIND(_serialize_image_to_bytes, "state", "image", "image_dict", "image_format", "lossy_quality");
|
||||
GDVIRTUAL_BIND(_save_image_at_path, "state", "image", "file_path", "image_format", "lossy_quality");
|
||||
@ -100,6 +102,13 @@ Error GLTFDocumentExtension::parse_texture_json(Ref<GLTFState> p_state, const Di
|
||||
return err;
|
||||
}
|
||||
|
||||
Ref<GLTFObjectModelProperty> GLTFDocumentExtension::import_object_model_property(Ref<GLTFState> p_state, const PackedStringArray &p_split_json_pointer, const TypedArray<NodePath> &p_partial_paths) {
|
||||
Ref<GLTFObjectModelProperty> ret;
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ret);
|
||||
GDVIRTUAL_CALL(_import_object_model_property, p_state, p_split_json_pointer, p_partial_paths, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) {
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
@ -169,6 +178,15 @@ Error GLTFDocumentExtension::export_preserialize(Ref<GLTFState> p_state) {
|
||||
return err;
|
||||
}
|
||||
|
||||
Ref<GLTFObjectModelProperty> GLTFDocumentExtension::export_object_model_property(Ref<GLTFState> p_state, const NodePath &p_node_path, const Node *p_godot_node, GLTFNodeIndex p_gltf_node_index, const Object *p_target_object, int p_target_depth) {
|
||||
Ref<GLTFObjectModelProperty> ret;
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ret);
|
||||
ERR_FAIL_NULL_V(p_godot_node, ret);
|
||||
ERR_FAIL_NULL_V(p_target_object, ret);
|
||||
GDVIRTUAL_CALL(_export_object_model_property, p_state, p_node_path, p_godot_node, p_gltf_node_index, p_target_object, p_target_depth, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector<String> GLTFDocumentExtension::get_saveable_image_formats() {
|
||||
Vector<String> ret;
|
||||
GDVIRTUAL_CALL(_get_saveable_image_formats, ret);
|
||||
|
@ -49,6 +49,7 @@ public:
|
||||
virtual Error parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> r_image);
|
||||
virtual String get_image_file_extension();
|
||||
virtual Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture);
|
||||
virtual Ref<GLTFObjectModelProperty> import_object_model_property(Ref<GLTFState> p_state, const PackedStringArray &p_split_json_pointer, const TypedArray<NodePath> &p_partial_paths);
|
||||
virtual Error import_post_parse(Ref<GLTFState> p_state);
|
||||
virtual Error import_pre_generate(Ref<GLTFState> p_state);
|
||||
virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
|
||||
@ -59,6 +60,7 @@ public:
|
||||
virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node);
|
||||
virtual Error export_post_convert(Ref<GLTFState> p_state, Node *p_root);
|
||||
virtual Error export_preserialize(Ref<GLTFState> p_state);
|
||||
virtual Ref<GLTFObjectModelProperty> export_object_model_property(Ref<GLTFState> p_state, const NodePath &p_node_path, const Node *p_godot_node, GLTFNodeIndex p_gltf_node_index, const Object *p_target_object, int p_target_depth);
|
||||
virtual Vector<String> get_saveable_image_formats();
|
||||
virtual PackedByteArray serialize_image_to_bytes(Ref<GLTFState> p_state, Ref<Image> p_image, Dictionary p_image_dict, const String &p_image_format, float p_lossy_quality);
|
||||
virtual Error save_image_at_path(Ref<GLTFState> p_state, Ref<Image> p_image, const String &p_file_path, const String &p_image_format, float p_lossy_quality);
|
||||
@ -73,6 +75,7 @@ public:
|
||||
GDVIRTUAL4R(Error, _parse_image_data, Ref<GLTFState>, PackedByteArray, String, Ref<Image>);
|
||||
GDVIRTUAL0R(String, _get_image_file_extension);
|
||||
GDVIRTUAL3R(Error, _parse_texture_json, Ref<GLTFState>, Dictionary, Ref<GLTFTexture>);
|
||||
GDVIRTUAL3R(Ref<GLTFObjectModelProperty>, _import_object_model_property, Ref<GLTFState>, PackedStringArray, TypedArray<NodePath>);
|
||||
GDVIRTUAL1R(Error, _import_post_parse, Ref<GLTFState>);
|
||||
GDVIRTUAL1R(Error, _import_pre_generate, Ref<GLTFState>);
|
||||
GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
|
||||
@ -83,6 +86,7 @@ public:
|
||||
GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
|
||||
GDVIRTUAL2R(Error, _export_post_convert, Ref<GLTFState>, Node *);
|
||||
GDVIRTUAL1R(Error, _export_preserialize, Ref<GLTFState>);
|
||||
GDVIRTUAL6R(Ref<GLTFObjectModelProperty>, _export_object_model_property, Ref<GLTFState>, NodePath, const Node *, GLTFNodeIndex, const Object *, int);
|
||||
GDVIRTUAL0R(Vector<String>, _get_saveable_image_formats);
|
||||
GDVIRTUAL5R(PackedByteArray, _serialize_image_to_bytes, Ref<GLTFState>, Ref<Image>, Dictionary, String, float);
|
||||
GDVIRTUAL5R(Error, _save_image_at_path, Ref<GLTFState>, Ref<Image>, String, String, float);
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "gltf_light.h"
|
||||
|
||||
#include "../structures/gltf_object_model_property.h"
|
||||
#include "scene/3d/light_3d.h"
|
||||
|
||||
void GLTFLight::_bind_methods() {
|
||||
@ -62,6 +63,21 @@ void GLTFLight::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_cone_angle"), "set_outer_cone_angle", "get_outer_cone_angle"); // float
|
||||
}
|
||||
|
||||
void GLTFLight::set_cone_inner_attenuation_conversion_expressions(Ref<GLTFObjectModelProperty> &r_obj_model_prop) {
|
||||
// Expression to convert glTF innerConeAngle to Godot spot_angle_attenuation.
|
||||
Ref<Expression> gltf_to_godot_expr;
|
||||
gltf_to_godot_expr.instantiate();
|
||||
PackedStringArray gltf_to_godot_args = { "inner_cone_angle" };
|
||||
gltf_to_godot_expr->parse("0.2 / (1.0 - inner_cone_angle / spot_angle) - 0.1", gltf_to_godot_args);
|
||||
r_obj_model_prop->set_gltf_to_godot_expression(gltf_to_godot_expr);
|
||||
// Expression to convert Godot spot_angle_attenuation to glTF innerConeAngle.
|
||||
Ref<Expression> godot_to_gltf_expr;
|
||||
godot_to_gltf_expr.instantiate();
|
||||
PackedStringArray godot_to_gltf_args = { "godot_spot_angle_att" };
|
||||
godot_to_gltf_expr->parse("spot_angle * maxf(0.0, 1.0 - (0.2 / (0.1 + godot_spot_angle_att)))", godot_to_gltf_args);
|
||||
r_obj_model_prop->set_godot_to_gltf_expression(godot_to_gltf_expr);
|
||||
}
|
||||
|
||||
Color GLTFLight::get_color() {
|
||||
return color;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
class GLTFObjectModelProperty;
|
||||
class Light3D;
|
||||
|
||||
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual
|
||||
@ -54,6 +55,8 @@ private:
|
||||
Dictionary additional_data;
|
||||
|
||||
public:
|
||||
static void set_cone_inner_attenuation_conversion_expressions(Ref<GLTFObjectModelProperty> &r_obj_model_prop);
|
||||
|
||||
Color get_color();
|
||||
void set_color(Color p_color);
|
||||
|
||||
|
@ -31,8 +31,11 @@
|
||||
#include "gltf_document_extension_physics.h"
|
||||
|
||||
#include "scene/3d/physics/area_3d.h"
|
||||
#include "scene/3d/physics/rigid_body_3d.h"
|
||||
#include "scene/3d/physics/static_body_3d.h"
|
||||
|
||||
using GLTFShapeIndex = int64_t;
|
||||
|
||||
// Import process.
|
||||
Error GLTFDocumentExtensionPhysics::import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) {
|
||||
if (!p_extensions.has("OMI_collider") && !p_extensions.has("OMI_physics_body") && !p_extensions.has("OMI_physics_shape")) {
|
||||
@ -105,6 +108,7 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
|
||||
Array state_shapes = p_state->get_additional_data(StringName("GLTFPhysicsShapes"));
|
||||
ERR_FAIL_INDEX_V_MSG(node_shape_index, state_shapes.size(), Error::ERR_FILE_CORRUPT, "glTF Physics: On node " + p_gltf_node->get_name() + ", the shape index " + itos(node_shape_index) + " is not in the state shapes (size: " + itos(state_shapes.size()) + ").");
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsColliderShape"), state_shapes[node_shape_index]);
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsColliderShapeIndex"), node_shape_index);
|
||||
} else {
|
||||
// If this node is a collider but does not have a collider
|
||||
// shape, then it only serves to combine together shapes.
|
||||
@ -119,6 +123,7 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
|
||||
Array state_shapes = p_state->get_additional_data(StringName("GLTFPhysicsShapes"));
|
||||
ERR_FAIL_INDEX_V_MSG(node_shape_index, state_shapes.size(), Error::ERR_FILE_CORRUPT, "glTF Physics: On node " + p_gltf_node->get_name() + ", the shape index " + itos(node_shape_index) + " is not in the state shapes (size: " + itos(state_shapes.size()) + ").");
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsTriggerShape"), state_shapes[node_shape_index]);
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsTriggerShapeIndex"), node_shape_index);
|
||||
} else {
|
||||
// If this node is a trigger but does not have a trigger shape,
|
||||
// then it's a trigger body, what Godot calls an Area3D node.
|
||||
@ -129,8 +134,8 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
|
||||
}
|
||||
// If this node defines explicit member shape nodes, save this information.
|
||||
if (node_trigger.has("nodes")) {
|
||||
Array node_trigger_nodes = node_trigger["nodes"];
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsCompoundTriggerNodes"), node_trigger_nodes);
|
||||
Array compound_trigger_nodes = node_trigger["nodes"];
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsCompoundTriggerNodes"), compound_trigger_nodes);
|
||||
}
|
||||
}
|
||||
if (physics_body_ext.has("motion") || physics_body_ext.has("type")) {
|
||||
@ -140,6 +145,144 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool _will_gltf_shape_become_subnode(Ref<GLTFState> p_state, const Ref<GLTFNode> p_gltf_node, GLTFNodeIndex p_gltf_node_index) {
|
||||
if (p_gltf_node->has_additional_data(StringName("GLTFPhysicsBody"))) {
|
||||
return true;
|
||||
}
|
||||
const TypedArray<GLTFNode> state_gltf_nodes = p_state->get_nodes();
|
||||
const GLTFNodeIndex parent_index = p_gltf_node->get_parent();
|
||||
if (parent_index == -1 || parent_index >= state_gltf_nodes.size()) {
|
||||
return true;
|
||||
}
|
||||
const Ref<GLTFNode> parent_gltf_node = state_gltf_nodes[parent_index];
|
||||
const Variant parent_body_maybe = parent_gltf_node->get_additional_data(StringName("GLTFPhysicsBody"));
|
||||
if (parent_body_maybe.get_type() != Variant::NIL) {
|
||||
Ref<GLTFPhysicsBody> parent_body = parent_body_maybe;
|
||||
// If the parent matches the triggerness, then this node will be generated as a shape (CollisionShape3D).
|
||||
// Otherwise, if there is a mismatch, a body will be generated for this node, and a subnode will also be generated for the shape.
|
||||
if (parent_body->get_body_type() == "trigger") {
|
||||
return p_gltf_node->has_additional_data(StringName("GLTFPhysicsColliderShape"));
|
||||
} else {
|
||||
return p_gltf_node->has_additional_data(StringName("GLTFPhysicsTriggerShape"));
|
||||
}
|
||||
}
|
||||
if (parent_gltf_node->has_additional_data(StringName("GLTFPhysicsColliderShape"))) {
|
||||
return false;
|
||||
}
|
||||
if (parent_gltf_node->has_additional_data(StringName("GLTFPhysicsTriggerShape"))) {
|
||||
return false;
|
||||
}
|
||||
Variant compound_trigger_maybe = parent_gltf_node->has_additional_data(StringName("GLTFPhysicsCompoundTriggerNodes"));
|
||||
if (compound_trigger_maybe.get_type() != Variant::NIL) {
|
||||
Array compound_trigger_nodes = compound_trigger_maybe;
|
||||
// Remember, JSON only has numbers, not integers, so must cast to double.
|
||||
return !compound_trigger_nodes.has((double)p_gltf_node_index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NodePath _get_scene_node_path_for_shape_index(Ref<GLTFState> p_state, const GLTFNodeIndex p_shape_index) {
|
||||
TypedArray<GLTFNode> state_gltf_nodes = p_state->get_nodes();
|
||||
for (GLTFNodeIndex node_index = 0; node_index < state_gltf_nodes.size(); node_index++) {
|
||||
const Ref<GLTFNode> gltf_node = state_gltf_nodes[node_index];
|
||||
ERR_CONTINUE(gltf_node.is_null());
|
||||
// Check if this node has a shape index and if it matches the one we are looking for.
|
||||
Variant shape_index_maybe = gltf_node->get_additional_data(StringName("GLTFPhysicsColliderShapeIndex"));
|
||||
if (shape_index_maybe.get_type() != Variant::INT) {
|
||||
shape_index_maybe = gltf_node->get_additional_data(StringName("GLTFPhysicsTriggerShapeIndex"));
|
||||
if (shape_index_maybe.get_type() != Variant::INT) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const GLTFShapeIndex shape_index = shape_index_maybe;
|
||||
if (shape_index != p_shape_index) {
|
||||
continue;
|
||||
}
|
||||
NodePath node_path = gltf_node->get_scene_node_path(p_state);
|
||||
// At this point, we have found a node with the shape index we were looking for.
|
||||
if (_will_gltf_shape_become_subnode(p_state, gltf_node, node_index)) {
|
||||
Vector<StringName> sname_path = node_path.get_names();
|
||||
sname_path.append(gltf_node->get_name() + "Shape");
|
||||
node_path = NodePath(sname_path, false);
|
||||
}
|
||||
return node_path;
|
||||
}
|
||||
return NodePath();
|
||||
}
|
||||
|
||||
Ref<GLTFObjectModelProperty> GLTFDocumentExtensionPhysics::import_object_model_property(Ref<GLTFState> p_state, const PackedStringArray &p_split_json_pointer, const TypedArray<NodePath> &p_partial_paths) {
|
||||
Ref<GLTFObjectModelProperty> ret;
|
||||
if (p_split_json_pointer.size() != 6) {
|
||||
// The only properties this class cares about are exactly 6 levels deep.
|
||||
return ret;
|
||||
}
|
||||
ret.instantiate();
|
||||
const String &prop_name = p_split_json_pointer[5];
|
||||
if (p_split_json_pointer[0] == "extensions" && p_split_json_pointer[2] == "shapes") {
|
||||
if (p_split_json_pointer[1] == "OMI_physics_shape" || p_split_json_pointer[1] == "KHR_collision_shapes") {
|
||||
const GLTFNodeIndex shape_index = p_split_json_pointer[3].to_int();
|
||||
NodePath node_path = _get_scene_node_path_for_shape_index(p_state, shape_index);
|
||||
if (node_path.is_empty()) {
|
||||
return ret;
|
||||
}
|
||||
String godot_prop_name = prop_name;
|
||||
if (prop_name == "size") {
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (prop_name == "height" || prop_name == "radius") {
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (prop_name == "radiusBottom" || prop_name == "radiusTop") {
|
||||
godot_prop_name = "radius";
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else {
|
||||
// Not something we handle, return without appending a NodePath.
|
||||
return ret;
|
||||
}
|
||||
// Example: `A/B/C/CollisionShape3D:shape:radius`.
|
||||
Vector<StringName> subnames;
|
||||
subnames.append("shape");
|
||||
subnames.append(godot_prop_name);
|
||||
node_path = NodePath(node_path.get_names(), subnames, false);
|
||||
ret->append_node_path(node_path);
|
||||
}
|
||||
} else if (p_split_json_pointer[0] == "nodes" && p_split_json_pointer[2] == "extensions" && p_split_json_pointer[4] == "motion") {
|
||||
if (p_split_json_pointer[3] == "OMI_physics_body" || p_split_json_pointer[3] == "KHR_physics_rigid_bodies") {
|
||||
const GLTFNodeIndex node_index = p_split_json_pointer[1].to_int();
|
||||
const TypedArray<GLTFNode> all_gltf_nodes = p_state->get_nodes();
|
||||
ERR_FAIL_INDEX_V_MSG(node_index, all_gltf_nodes.size(), ret, "GLTF Physics: The node index " + itos(node_index) + " is not in the state nodes (size: " + itos(all_gltf_nodes.size()) + ").");
|
||||
const Ref<GLTFNode> gltf_node = all_gltf_nodes[node_index];
|
||||
NodePath node_path;
|
||||
if (p_partial_paths.is_empty()) {
|
||||
node_path = gltf_node->get_scene_node_path(p_state);
|
||||
} else {
|
||||
// The path is already computed for us, just grab it.
|
||||
node_path = p_partial_paths[0];
|
||||
}
|
||||
if (prop_name == "mass") {
|
||||
ret->append_path_to_property(node_path, "mass");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (prop_name == "linearVelocity") {
|
||||
ret->append_path_to_property(node_path, "linear_velocity");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (prop_name == "angularVelocity") {
|
||||
ret->append_path_to_property(node_path, "angular_velocity");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (prop_name == "centerOfMass") {
|
||||
ret->append_path_to_property(node_path, "center_of_mass");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (prop_name == "inertiaDiagonal") {
|
||||
ret->append_path_to_property(node_path, "inertia");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (prop_name == "inertiaOrientation") {
|
||||
WARN_PRINT("GLTF Physics: The 'inertiaOrientation' property is not supported by Godot.");
|
||||
} else {
|
||||
// Not something we handle, return without appending a NodePath.
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void _setup_shape_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state, Ref<GLTFPhysicsShape> p_gltf_shape) {
|
||||
GLTFMeshIndex shape_mesh_index = p_gltf_shape->get_mesh_index();
|
||||
if (shape_mesh_index == -1) {
|
||||
@ -434,24 +577,126 @@ Array _get_or_create_state_shapes_in_state(Ref<GLTFState> p_state) {
|
||||
return state_shapes;
|
||||
}
|
||||
|
||||
Dictionary _export_node_shape(Ref<GLTFState> p_state, Ref<GLTFPhysicsShape> p_physics_shape) {
|
||||
GLTFShapeIndex _export_node_shape(Ref<GLTFState> p_state, Ref<GLTFPhysicsShape> p_physics_shape) {
|
||||
Array state_shapes = _get_or_create_state_shapes_in_state(p_state);
|
||||
int size = state_shapes.size();
|
||||
GLTFShapeIndex size = state_shapes.size();
|
||||
Dictionary shape_property;
|
||||
Dictionary shape_dict = p_physics_shape->to_dictionary();
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (GLTFShapeIndex i = 0; i < size; i++) {
|
||||
Dictionary other = state_shapes[i];
|
||||
if (other == shape_dict) {
|
||||
// De-duplication: If we already have an identical shape,
|
||||
// set the shape index to the existing one and return.
|
||||
shape_property["shape"] = i;
|
||||
return shape_property;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// If we don't have an identical shape, add it to the array.
|
||||
state_shapes.push_back(shape_dict);
|
||||
shape_property["shape"] = size;
|
||||
return shape_property;
|
||||
return size;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtensionPhysics::export_preserialize(Ref<GLTFState> p_state) {
|
||||
// Note: Need to do _export_node_shape before exporting animations, so export_node is too late.
|
||||
TypedArray<GLTFNode> state_gltf_nodes = p_state->get_nodes();
|
||||
for (Ref<GLTFNode> gltf_node : state_gltf_nodes) {
|
||||
Ref<GLTFPhysicsShape> collider_shape = gltf_node->get_additional_data(StringName("GLTFPhysicsColliderShape"));
|
||||
if (collider_shape.is_valid()) {
|
||||
GLTFShapeIndex collider_shape_index = _export_node_shape(p_state, collider_shape);
|
||||
gltf_node->set_additional_data(StringName("GLTFPhysicsColliderShapeIndex"), collider_shape_index);
|
||||
}
|
||||
Ref<GLTFPhysicsShape> trigger_shape = gltf_node->get_additional_data(StringName("GLTFPhysicsTriggerShape"));
|
||||
if (trigger_shape.is_valid()) {
|
||||
GLTFShapeIndex trigger_shape_index = _export_node_shape(p_state, trigger_shape);
|
||||
gltf_node->set_additional_data(StringName("GLTFPhysicsTriggerShapeIndex"), trigger_shape_index);
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Ref<GLTFObjectModelProperty> GLTFDocumentExtensionPhysics::export_object_model_property(Ref<GLTFState> p_state, const NodePath &p_node_path, const Node *p_godot_node, GLTFNodeIndex p_gltf_node_index, const Object *p_target_object, int p_target_depth) {
|
||||
Ref<GLTFObjectModelProperty> ret;
|
||||
const Vector<StringName> &path_subnames = p_node_path.get_subnames();
|
||||
if (path_subnames.is_empty()) {
|
||||
return ret;
|
||||
}
|
||||
ret.instantiate();
|
||||
const StringName &node_prop = path_subnames[0];
|
||||
if (Object::cast_to<RigidBody3D>(p_target_object)) {
|
||||
if (path_subnames.size() != 1) {
|
||||
return ret;
|
||||
}
|
||||
// Example: `/nodes/0/extensions/OMI_physics_body/motion/mass`
|
||||
PackedStringArray split_json_pointer;
|
||||
split_json_pointer.append("nodes");
|
||||
split_json_pointer.append(itos(p_gltf_node_index));
|
||||
split_json_pointer.append("extensions");
|
||||
split_json_pointer.append("OMI_physics_body");
|
||||
split_json_pointer.append("motion");
|
||||
if (node_prop == StringName("mass")) {
|
||||
split_json_pointer.append("mass");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (node_prop == StringName("linear_velocity")) {
|
||||
split_json_pointer.append("linearVelocity");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (node_prop == StringName("angular_velocity")) {
|
||||
split_json_pointer.append("angularVelocity");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (node_prop == StringName("center_of_mass")) {
|
||||
split_json_pointer.append("centerOfMass");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (node_prop == StringName("inertia")) {
|
||||
split_json_pointer.append("inertiaDiagonal");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else {
|
||||
// Not something we handle, return without setting the JSON pointer.
|
||||
return ret;
|
||||
}
|
||||
ret->set_json_pointers({ split_json_pointer });
|
||||
} else if (Object::cast_to<CollisionShape3D>(p_godot_node)) {
|
||||
if (path_subnames.size() != 2) {
|
||||
return ret;
|
||||
}
|
||||
// Example: `/extensions/OMI_physics_shape/shapes/0/box/size`
|
||||
PackedStringArray split_json_pointer;
|
||||
split_json_pointer.append("extensions");
|
||||
split_json_pointer.append("OMI_physics_shape");
|
||||
split_json_pointer.append("shapes");
|
||||
TypedArray<GLTFNode> state_gltf_nodes = p_state->get_nodes();
|
||||
ERR_FAIL_INDEX_V(p_gltf_node_index, state_gltf_nodes.size(), ret);
|
||||
Ref<GLTFNode> gltf_node = state_gltf_nodes[p_gltf_node_index];
|
||||
Variant shape_index_maybe = gltf_node->get_additional_data(StringName("GLTFPhysicsColliderShapeIndex"));
|
||||
String shape_type;
|
||||
if (shape_index_maybe.get_type() == Variant::INT) {
|
||||
Ref<GLTFPhysicsShape> collider_shape = gltf_node->get_additional_data(StringName("GLTFPhysicsColliderShape"));
|
||||
shape_type = collider_shape->get_shape_type();
|
||||
} else {
|
||||
shape_index_maybe = gltf_node->get_additional_data(StringName("GLTFPhysicsTriggerShapeIndex"));
|
||||
if (shape_index_maybe.get_type() == Variant::INT) {
|
||||
Ref<GLTFPhysicsShape> trigger_shape = gltf_node->get_additional_data(StringName("GLTFPhysicsTriggerShape"));
|
||||
shape_type = trigger_shape->get_shape_type();
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_V(shape_index_maybe.get_type() != Variant::INT, ret);
|
||||
GLTFShapeIndex shape_index = shape_index_maybe;
|
||||
split_json_pointer.append(itos(shape_index));
|
||||
split_json_pointer.append(shape_type);
|
||||
const StringName &shape_prop = path_subnames[1];
|
||||
if (shape_prop == StringName("size")) {
|
||||
split_json_pointer.append("size");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (shape_prop == StringName("radius")) {
|
||||
split_json_pointer.append("radius");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (shape_prop == StringName("height")) {
|
||||
split_json_pointer.append("height");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else {
|
||||
// Not something we handle, return without setting the JSON pointer.
|
||||
return ret;
|
||||
}
|
||||
ret->set_json_pointers({ split_json_pointer });
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtensionPhysics::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_node_json, Node *p_node) {
|
||||
@ -465,13 +710,16 @@ Error GLTFDocumentExtensionPhysics::export_node(Ref<GLTFState> p_state, Ref<GLTF
|
||||
trigger_property["nodes"] = compound_trigger_nodes;
|
||||
}
|
||||
}
|
||||
Ref<GLTFPhysicsShape> collider_shape = p_gltf_node->get_additional_data(StringName("GLTFPhysicsColliderShape"));
|
||||
if (collider_shape.is_valid()) {
|
||||
physics_body_ext["collider"] = _export_node_shape(p_state, collider_shape);
|
||||
Variant collider_shape_index = p_gltf_node->get_additional_data(StringName("GLTFPhysicsColliderShapeIndex"));
|
||||
if (collider_shape_index.get_type() == Variant::INT) {
|
||||
Dictionary collider_dict;
|
||||
collider_dict["shape"] = collider_shape_index;
|
||||
physics_body_ext["collider"] = collider_dict;
|
||||
}
|
||||
Ref<GLTFPhysicsShape> trigger_shape = p_gltf_node->get_additional_data(StringName("GLTFPhysicsTriggerShape"));
|
||||
if (trigger_shape.is_valid()) {
|
||||
physics_body_ext["trigger"] = _export_node_shape(p_state, trigger_shape);
|
||||
Variant trigger_shape_index = p_gltf_node->get_additional_data(StringName("GLTFPhysicsTriggerShapeIndex"));
|
||||
if (trigger_shape_index.get_type() == Variant::INT) {
|
||||
Dictionary trigger_dict = physics_body_ext.get_or_add("trigger", {});
|
||||
trigger_dict["shape"] = trigger_shape_index;
|
||||
}
|
||||
if (!physics_body_ext.is_empty()) {
|
||||
Dictionary node_extensions = r_node_json["extensions"];
|
||||
|
@ -43,9 +43,12 @@ public:
|
||||
Error import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) override;
|
||||
Vector<String> get_supported_extensions() override;
|
||||
Error parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions) override;
|
||||
Ref<GLTFObjectModelProperty> import_object_model_property(Ref<GLTFState> p_state, const PackedStringArray &p_split_json_pointer, const TypedArray<NodePath> &p_partial_paths) override;
|
||||
Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) override;
|
||||
// Export process.
|
||||
void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node) override;
|
||||
Error export_preserialize(Ref<GLTFState> p_state) override;
|
||||
Ref<GLTFObjectModelProperty> export_object_model_property(Ref<GLTFState> p_state, const NodePath &p_node_path, const Node *p_godot_node, GLTFNodeIndex p_gltf_node_index, const Object *p_target_object, int p_target_depth) override;
|
||||
Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_node_json, Node *p_scene_node) override;
|
||||
};
|
||||
|
||||
|
@ -193,9 +193,6 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_node(const CollisionObject3D *p_body_
|
||||
physics_body->angular_velocity = body->get_angular_velocity();
|
||||
physics_body->center_of_mass = body->get_center_of_mass();
|
||||
physics_body->inertia_diagonal = body->get_inertia();
|
||||
if (body->get_center_of_mass() != Vector3()) {
|
||||
WARN_PRINT("GLTFPhysicsBody: This rigid body has a center of mass offset from the origin, which will be ignored when exporting to glTF.");
|
||||
}
|
||||
if (cast_to<VehicleBody3D>(p_body_node)) {
|
||||
physics_body->body_type = PhysicsBodyType::VEHICLE;
|
||||
} else {
|
||||
|
@ -43,6 +43,7 @@ class GLTFDocumentExtension;
|
||||
class GLTFLight;
|
||||
class GLTFMesh;
|
||||
class GLTFNode;
|
||||
class GLTFObjectModelProperty;
|
||||
class GLTFSkeleton;
|
||||
class GLTFSkin;
|
||||
class GLTFSpecGloss;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -56,13 +56,6 @@ public:
|
||||
enum {
|
||||
ARRAY_BUFFER = 34962,
|
||||
ELEMENT_ARRAY_BUFFER = 34963,
|
||||
|
||||
COMPONENT_TYPE_BYTE = 5120,
|
||||
COMPONENT_TYPE_UNSIGNED_BYTE = 5121,
|
||||
COMPONENT_TYPE_SHORT = 5122,
|
||||
COMPONENT_TYPE_UNSIGNED_SHORT = 5123,
|
||||
COMPONENT_TYPE_INT = 5125,
|
||||
COMPONENT_TYPE_FLOAT = 5126,
|
||||
};
|
||||
enum {
|
||||
TEXTURE_TYPE_GENERIC = 0,
|
||||
@ -95,6 +88,10 @@ public:
|
||||
static Vector<String> get_supported_gltf_extensions();
|
||||
static HashSet<String> get_supported_gltf_extensions_hashset();
|
||||
|
||||
static NodePath _find_material_node_path(Ref<GLTFState> p_state, Ref<Material> p_material);
|
||||
static Ref<GLTFObjectModelProperty> import_object_model_property(Ref<GLTFState> p_state, const String &p_json_pointer);
|
||||
static Ref<GLTFObjectModelProperty> export_object_model_property(Ref<GLTFState> p_state, const NodePath &p_node_path, const Node *p_godot_node, GLTFNodeIndex p_gltf_node_index);
|
||||
|
||||
void set_naming_version(int p_version);
|
||||
int get_naming_version() const;
|
||||
void set_image_format(const String &p_image_format);
|
||||
@ -109,8 +106,8 @@ private:
|
||||
void _build_parent_hierachy(Ref<GLTFState> p_state);
|
||||
double _filter_number(double p_float);
|
||||
void _round_min_max_components(Vector<double> &r_type_min, Vector<double> &r_type_max);
|
||||
String _get_component_type_name(const uint32_t p_component);
|
||||
int _get_component_type_size(const int p_component_type);
|
||||
String _get_component_type_name(const GLTFAccessor::GLTFComponentType p_component_type);
|
||||
int _get_component_type_size(const GLTFAccessor::GLTFComponentType p_component_type);
|
||||
Error _parse_scenes(Ref<GLTFState> p_state);
|
||||
Error _parse_nodes(Ref<GLTFState> p_state);
|
||||
String _get_accessor_type_name(const GLTFAccessor::GLTFAccessorType p_accessor_type);
|
||||
@ -140,7 +137,7 @@ private:
|
||||
const int p_skip_every, const int p_skip_bytes,
|
||||
const int p_element_size, const int p_count,
|
||||
const GLTFAccessor::GLTFAccessorType p_accessor_type, const int p_component_count,
|
||||
const int p_component_type, const int p_component_size,
|
||||
const GLTFAccessor::GLTFComponentType p_component_type, const int p_component_size,
|
||||
const bool p_normalized, const int p_byte_offset,
|
||||
const bool p_for_vertex);
|
||||
Vector<double> _decode_accessor(Ref<GLTFState> p_state,
|
||||
@ -178,6 +175,15 @@ private:
|
||||
Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> p_state,
|
||||
const GLTFAccessorIndex p_accessor,
|
||||
const bool p_for_vertex);
|
||||
Vector<Variant> _decode_accessor_as_variant(Ref<GLTFState> p_state,
|
||||
const GLTFAccessorIndex p_accessor,
|
||||
Variant::Type p_variant_type,
|
||||
GLTFAccessor::GLTFAccessorType p_accessor_type);
|
||||
GLTFAccessorIndex _encode_accessor_as_variant(Ref<GLTFState> p_state,
|
||||
Vector<Variant> p_attribs,
|
||||
Variant::Type p_variant_type,
|
||||
GLTFAccessor::GLTFAccessorType p_accessor_type,
|
||||
GLTFAccessor::GLTFComponentType p_component_type = GLTFAccessor::COMPONENT_TYPE_SINGLE_FLOAT);
|
||||
Error _parse_meshes(Ref<GLTFState> p_state);
|
||||
Error _serialize_textures(Ref<GLTFState> p_state);
|
||||
Error _serialize_texture_samplers(Ref<GLTFState> p_state);
|
||||
@ -205,6 +211,7 @@ private:
|
||||
Error _parse_cameras(Ref<GLTFState> p_state);
|
||||
Error _parse_lights(Ref<GLTFState> p_state);
|
||||
Error _parse_animations(Ref<GLTFState> p_state);
|
||||
void _parse_animation_pointer(Ref<GLTFState> p_state, const String &p_animation_json_pointer, const Ref<GLTFAnimation> p_gltf_animation, const GLTFAnimation::Interpolation p_interp, const Vector<double> &p_times, const int p_output_value_accessor_index);
|
||||
Error _serialize_animations(Ref<GLTFState> p_state);
|
||||
BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> p_state,
|
||||
Skeleton3D *p_skeleton,
|
||||
@ -216,7 +223,7 @@ private:
|
||||
Node3D *_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index);
|
||||
void _assign_node_names(Ref<GLTFState> p_state);
|
||||
template <typename T>
|
||||
T _interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values,
|
||||
T _interpolate_track(const Vector<double> &p_times, const Vector<T> &p_values,
|
||||
const float p_time,
|
||||
const GLTFAnimation::Interpolation p_interp);
|
||||
GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> p_state,
|
||||
@ -229,7 +236,7 @@ private:
|
||||
const Vector<Color> p_attribs,
|
||||
const bool p_for_vertex);
|
||||
GLTFAccessorIndex _encode_accessor_as_floats(Ref<GLTFState> p_state,
|
||||
const Vector<real_t> p_attribs,
|
||||
const Vector<double> p_attribs,
|
||||
const bool p_for_vertex);
|
||||
GLTFAccessorIndex _encode_accessor_as_vec2(Ref<GLTFState> p_state,
|
||||
const Vector<Vector2> p_attribs,
|
||||
@ -269,7 +276,7 @@ private:
|
||||
const bool p_for_vertex);
|
||||
Error _encode_buffer_view(Ref<GLTFState> p_state, const double *p_src,
|
||||
const int p_count, const GLTFAccessor::GLTFAccessorType p_accessor_type,
|
||||
const int p_component_type, const bool p_normalized,
|
||||
const GLTFAccessor::GLTFComponentType p_component_type, const bool p_normalized,
|
||||
const int p_byte_offset, const bool p_for_vertex,
|
||||
GLTFBufferViewIndex &r_accessor, const bool p_for_indices = false);
|
||||
|
||||
@ -280,11 +287,6 @@ private:
|
||||
Error _serialize_nodes(Ref<GLTFState> p_state);
|
||||
Error _serialize_scenes(Ref<GLTFState> p_state);
|
||||
String interpolation_to_string(const GLTFAnimation::Interpolation p_interp);
|
||||
GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> p_state,
|
||||
GLTFAnimation::Track p_track,
|
||||
Ref<Animation> p_animation,
|
||||
int32_t p_track_i,
|
||||
GLTFNodeIndex p_node_i);
|
||||
Error _encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path);
|
||||
Error _encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path);
|
||||
PackedByteArray _serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err);
|
||||
@ -342,11 +344,6 @@ public:
|
||||
void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state);
|
||||
#endif // MODULE_CSG_ENABLED
|
||||
|
||||
void _convert_animation_player_to_gltf(
|
||||
AnimationPlayer *p_animation_player, Ref<GLTFState> p_state,
|
||||
GLTFNodeIndex p_gltf_current,
|
||||
GLTFNodeIndex p_gltf_root_index,
|
||||
Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
|
||||
void _check_visibility(Node *p_node, bool &r_retflag);
|
||||
void _convert_camera_to_gltf(Camera3D *p_camera, Ref<GLTFState> p_state,
|
||||
Ref<GLTFNode> p_gltf_node);
|
||||
@ -377,7 +374,15 @@ public:
|
||||
Ref<GLTFNode> p_gltf_node);
|
||||
GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> p_state,
|
||||
MeshInstance3D *p_mesh_instance);
|
||||
void _convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, String p_animation_track_name);
|
||||
|
||||
GLTFNodeIndex _node_and_or_bone_to_gltf_node_index(Ref<GLTFState> p_state, const Vector<StringName> &p_node_subpath, const Node *p_godot_node);
|
||||
bool _convert_animation_node_track(Ref<GLTFState> p_state,
|
||||
GLTFAnimation::NodeTrack &p_gltf_node_track,
|
||||
const Ref<Animation> &p_godot_animation,
|
||||
int32_t p_godot_anim_track_index,
|
||||
Vector<double> &p_times);
|
||||
void _convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, const String &p_animation_track_name);
|
||||
|
||||
Error _serialize(Ref<GLTFState> p_state);
|
||||
Error _parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file);
|
||||
};
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "structures/gltf_camera.h"
|
||||
#include "structures/gltf_mesh.h"
|
||||
#include "structures/gltf_node.h"
|
||||
#include "structures/gltf_object_model_property.h"
|
||||
#include "structures/gltf_skeleton.h"
|
||||
#include "structures/gltf_skin.h"
|
||||
#include "structures/gltf_texture.h"
|
||||
@ -48,6 +49,7 @@
|
||||
class GLTFState : public Resource {
|
||||
GDCLASS(GLTFState, Resource);
|
||||
friend class GLTFDocument;
|
||||
friend class GLTFNode;
|
||||
|
||||
protected:
|
||||
String base_path;
|
||||
@ -102,6 +104,7 @@ protected:
|
||||
Vector<Ref<GLTFAnimation>> animations;
|
||||
HashMap<GLTFNodeIndex, Node *> scene_nodes;
|
||||
HashMap<GLTFNodeIndex, ImporterMeshInstance3D *> scene_mesh_instances;
|
||||
HashMap<String, Ref<GLTFObjectModelProperty>> object_model_properties;
|
||||
|
||||
HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton;
|
||||
HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "extensions/physics/gltf_document_extension_physics.h"
|
||||
#include "gltf_document.h"
|
||||
#include "gltf_state.h"
|
||||
#include "structures/gltf_object_model_property.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/editor_import_blend_runner.h"
|
||||
@ -112,6 +113,7 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) {
|
||||
GDREGISTER_CLASS(GLTFLight);
|
||||
GDREGISTER_CLASS(GLTFMesh);
|
||||
GDREGISTER_CLASS(GLTFNode);
|
||||
GDREGISTER_CLASS(GLTFObjectModelProperty);
|
||||
GDREGISTER_CLASS(GLTFPhysicsBody);
|
||||
GDREGISTER_CLASS(GLTFPhysicsShape);
|
||||
GDREGISTER_CLASS(GLTFSkeleton);
|
||||
|
@ -39,6 +39,19 @@ void GLTFAccessor::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(TYPE_MAT3);
|
||||
BIND_ENUM_CONSTANT(TYPE_MAT4);
|
||||
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_NONE);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_SIGNED_BYTE);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_UNSIGNED_BYTE);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_SIGNED_SHORT);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_UNSIGNED_SHORT);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_SIGNED_INT);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_UNSIGNED_INT);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_SINGLE_FLOAT);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_DOUBLE_FLOAT);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_HALF_FLOAT);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_SIGNED_LONG);
|
||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_UNSIGNED_LONG);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view);
|
||||
ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view);
|
||||
ClassDB::bind_method(D_METHOD("get_byte_offset"), &GLTFAccessor::get_byte_offset);
|
||||
@ -108,7 +121,7 @@ int GLTFAccessor::get_component_type() {
|
||||
}
|
||||
|
||||
void GLTFAccessor::set_component_type(int p_component_type) {
|
||||
component_type = p_component_type;
|
||||
component_type = (GLTFComponentType)p_component_type;
|
||||
}
|
||||
|
||||
bool GLTFAccessor::get_normalized() {
|
||||
@ -188,7 +201,7 @@ int GLTFAccessor::get_sparse_indices_component_type() {
|
||||
}
|
||||
|
||||
void GLTFAccessor::set_sparse_indices_component_type(int p_sparse_indices_component_type) {
|
||||
sparse_indices_component_type = p_sparse_indices_component_type;
|
||||
sparse_indices_component_type = (GLTFComponentType)p_sparse_indices_component_type;
|
||||
}
|
||||
|
||||
int GLTFAccessor::get_sparse_values_buffer_view() {
|
||||
|
@ -50,10 +50,25 @@ public:
|
||||
TYPE_MAT4,
|
||||
};
|
||||
|
||||
enum GLTFComponentType {
|
||||
COMPONENT_TYPE_NONE = 0,
|
||||
COMPONENT_TYPE_SIGNED_BYTE = 5120,
|
||||
COMPONENT_TYPE_UNSIGNED_BYTE = 5121,
|
||||
COMPONENT_TYPE_SIGNED_SHORT = 5122,
|
||||
COMPONENT_TYPE_UNSIGNED_SHORT = 5123,
|
||||
COMPONENT_TYPE_SIGNED_INT = 5124,
|
||||
COMPONENT_TYPE_UNSIGNED_INT = 5125,
|
||||
COMPONENT_TYPE_SINGLE_FLOAT = 5126,
|
||||
COMPONENT_TYPE_DOUBLE_FLOAT = 5130,
|
||||
COMPONENT_TYPE_HALF_FLOAT = 5131,
|
||||
COMPONENT_TYPE_SIGNED_LONG = 5134,
|
||||
COMPONENT_TYPE_UNSIGNED_LONG = 5135,
|
||||
};
|
||||
|
||||
private:
|
||||
GLTFBufferViewIndex buffer_view = -1;
|
||||
int byte_offset = 0;
|
||||
int component_type = 0;
|
||||
GLTFComponentType component_type = COMPONENT_TYPE_NONE;
|
||||
bool normalized = false;
|
||||
int count = 0;
|
||||
GLTFAccessorType accessor_type = GLTFAccessorType::TYPE_SCALAR;
|
||||
@ -62,7 +77,7 @@ private:
|
||||
int sparse_count = 0;
|
||||
int sparse_indices_buffer_view = 0;
|
||||
int sparse_indices_byte_offset = 0;
|
||||
int sparse_indices_component_type = 0;
|
||||
GLTFComponentType sparse_indices_component_type = COMPONENT_TYPE_NONE;
|
||||
int sparse_values_buffer_view = 0;
|
||||
int sparse_values_byte_offset = 0;
|
||||
|
||||
@ -117,5 +132,6 @@ public:
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(GLTFAccessor::GLTFAccessorType);
|
||||
VARIANT_ENUM_CAST(GLTFAccessor::GLTFComponentType);
|
||||
|
||||
#endif // GLTF_ACCESSOR_H
|
||||
|
@ -42,6 +42,34 @@ void GLTFAnimation::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "get_loop"); // bool
|
||||
}
|
||||
|
||||
GLTFAnimation::Interpolation GLTFAnimation::godot_to_gltf_interpolation(const Ref<Animation> &p_godot_animation, int32_t p_godot_anim_track_index) {
|
||||
Animation::InterpolationType interpolation = p_godot_animation->track_get_interpolation_type(p_godot_anim_track_index);
|
||||
switch (interpolation) {
|
||||
case Animation::INTERPOLATION_LINEAR:
|
||||
case Animation::INTERPOLATION_LINEAR_ANGLE:
|
||||
return INTERP_LINEAR;
|
||||
case Animation::INTERPOLATION_NEAREST:
|
||||
return INTERP_STEP;
|
||||
case Animation::INTERPOLATION_CUBIC:
|
||||
case Animation::INTERPOLATION_CUBIC_ANGLE:
|
||||
return INTERP_CUBIC_SPLINE;
|
||||
}
|
||||
return INTERP_LINEAR;
|
||||
}
|
||||
|
||||
Animation::InterpolationType GLTFAnimation::gltf_to_godot_interpolation(Interpolation p_gltf_interpolation) {
|
||||
switch (p_gltf_interpolation) {
|
||||
case INTERP_LINEAR:
|
||||
return Animation::INTERPOLATION_LINEAR;
|
||||
case INTERP_STEP:
|
||||
return Animation::INTERPOLATION_NEAREST;
|
||||
case INTERP_CATMULLROMSPLINE:
|
||||
case INTERP_CUBIC_SPLINE:
|
||||
return Animation::INTERPOLATION_CUBIC;
|
||||
}
|
||||
return Animation::INTERPOLATION_LINEAR;
|
||||
}
|
||||
|
||||
String GLTFAnimation::get_original_name() {
|
||||
return original_name;
|
||||
}
|
||||
@ -58,8 +86,16 @@ void GLTFAnimation::set_loop(bool p_val) {
|
||||
loop = p_val;
|
||||
}
|
||||
|
||||
HashMap<int, GLTFAnimation::Track> &GLTFAnimation::get_tracks() {
|
||||
return tracks;
|
||||
HashMap<int, GLTFAnimation::NodeTrack> &GLTFAnimation::get_node_tracks() {
|
||||
return node_tracks;
|
||||
}
|
||||
|
||||
HashMap<String, GLTFAnimation::Channel<Variant>> &GLTFAnimation::get_pointer_tracks() {
|
||||
return pointer_tracks;
|
||||
}
|
||||
|
||||
bool GLTFAnimation::is_empty_of_tracks() const {
|
||||
return node_tracks.is_empty() && pointer_tracks.is_empty();
|
||||
}
|
||||
|
||||
GLTFAnimation::GLTFAnimation() {
|
||||
|
@ -50,33 +50,41 @@ public:
|
||||
template <typename T>
|
||||
struct Channel {
|
||||
Interpolation interpolation = INTERP_LINEAR;
|
||||
Vector<real_t> times;
|
||||
Vector<double> times;
|
||||
Vector<T> values;
|
||||
};
|
||||
|
||||
struct Track {
|
||||
struct NodeTrack {
|
||||
Channel<Vector3> position_track;
|
||||
Channel<Quaternion> rotation_track;
|
||||
Channel<Vector3> scale_track;
|
||||
Vector<Channel<real_t>> weight_tracks;
|
||||
};
|
||||
|
||||
String original_name;
|
||||
bool loop = false;
|
||||
HashMap<int, NodeTrack> node_tracks;
|
||||
HashMap<String, Channel<Variant>> pointer_tracks;
|
||||
Dictionary additional_data;
|
||||
|
||||
public:
|
||||
static Interpolation godot_to_gltf_interpolation(const Ref<Animation> &p_godot_animation, int32_t p_godot_anim_track_index);
|
||||
static Animation::InterpolationType gltf_to_godot_interpolation(Interpolation p_gltf_interpolation);
|
||||
|
||||
String get_original_name();
|
||||
void set_original_name(String p_name);
|
||||
|
||||
bool get_loop() const;
|
||||
void set_loop(bool p_val);
|
||||
HashMap<int, GLTFAnimation::Track> &get_tracks();
|
||||
|
||||
HashMap<int, GLTFAnimation::NodeTrack> &get_node_tracks();
|
||||
HashMap<String, GLTFAnimation::Channel<Variant>> &get_pointer_tracks();
|
||||
bool is_empty_of_tracks() const;
|
||||
|
||||
Variant get_additional_data(const StringName &p_extension_name);
|
||||
void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
|
||||
GLTFAnimation();
|
||||
|
||||
private:
|
||||
String original_name;
|
||||
bool loop = false;
|
||||
HashMap<int, Track> tracks;
|
||||
Dictionary additional_data;
|
||||
GLTFAnimation();
|
||||
};
|
||||
|
||||
#endif // GLTF_ANIMATION_H
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "gltf_camera.h"
|
||||
|
||||
#include "gltf_object_model_property.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
|
||||
void GLTFCamera::_bind_methods() {
|
||||
@ -57,6 +58,21 @@ void GLTFCamera::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_near"), "set_depth_near", "get_depth_near");
|
||||
}
|
||||
|
||||
void GLTFCamera::set_fov_conversion_expressions(Ref<GLTFObjectModelProperty> &r_obj_model_prop) {
|
||||
// Expression to convert glTF yfov in radians to Godot fov in degrees.
|
||||
Ref<Expression> gltf_to_godot_expr;
|
||||
gltf_to_godot_expr.instantiate();
|
||||
PackedStringArray gltf_to_godot_args = { "yfov_rad" };
|
||||
gltf_to_godot_expr->parse("rad_to_deg(yfov_rad)", gltf_to_godot_args);
|
||||
r_obj_model_prop->set_gltf_to_godot_expression(gltf_to_godot_expr);
|
||||
// Expression to convert Godot fov in degrees to glTF yfov in radians.
|
||||
Ref<Expression> godot_to_gltf_expr;
|
||||
godot_to_gltf_expr.instantiate();
|
||||
PackedStringArray godot_to_gltf_args = { "fov_deg" };
|
||||
godot_to_gltf_expr->parse("deg_to_rad(fov_deg)", godot_to_gltf_args);
|
||||
r_obj_model_prop->set_godot_to_gltf_expression(godot_to_gltf_expr);
|
||||
}
|
||||
|
||||
Ref<GLTFCamera> GLTFCamera::from_node(const Camera3D *p_camera) {
|
||||
Ref<GLTFCamera> c;
|
||||
c.instantiate();
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "core/io/resource.h"
|
||||
|
||||
class Camera3D;
|
||||
class GLTFObjectModelProperty;
|
||||
|
||||
// Reference and test file:
|
||||
// https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md
|
||||
@ -54,6 +55,8 @@ protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static void set_fov_conversion_expressions(Ref<GLTFObjectModelProperty> &r_obj_model_prop);
|
||||
|
||||
bool get_perspective() const { return perspective; }
|
||||
void set_perspective(bool p_val) { perspective = p_val; }
|
||||
real_t get_fov() const { return fov; }
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
#include "gltf_node.h"
|
||||
|
||||
#include "../gltf_state.h"
|
||||
|
||||
void GLTFNode::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_original_name"), &GLTFNode::get_original_name);
|
||||
ClassDB::bind_method(D_METHOD("set_original_name", "original_name"), &GLTFNode::set_original_name);
|
||||
@ -60,6 +62,7 @@ void GLTFNode::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light);
|
||||
ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFNode::get_additional_data);
|
||||
ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFNode::set_additional_data);
|
||||
ClassDB::bind_method(D_METHOD("get_scene_node_path", "gltf_state", "handle_skeletons"), &GLTFNode::get_scene_node_path, DEFVAL(true));
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "original_name"), "set_original_name", "get_original_name"); // String
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex
|
||||
@ -187,6 +190,48 @@ Variant GLTFNode::get_additional_data(const StringName &p_extension_name) {
|
||||
return additional_data[p_extension_name];
|
||||
}
|
||||
|
||||
bool GLTFNode::has_additional_data(const StringName &p_extension_name) {
|
||||
return additional_data.has(p_extension_name);
|
||||
}
|
||||
|
||||
void GLTFNode::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) {
|
||||
additional_data[p_extension_name] = p_additional_data;
|
||||
}
|
||||
|
||||
NodePath GLTFNode::get_scene_node_path(Ref<GLTFState> p_state, bool p_handle_skeletons) {
|
||||
Vector<StringName> path;
|
||||
Vector<StringName> subpath;
|
||||
Ref<GLTFNode> current_gltf_node = this;
|
||||
const int gltf_node_count = p_state->nodes.size();
|
||||
if (p_handle_skeletons && skeleton != -1) {
|
||||
// Special case for skeleton nodes, skip all bones so that the path is to the Skeleton3D node.
|
||||
// A path that would otherwise be `A/B/C/Bone1/Bone2/Bone3` becomes `A/B/C/Skeleton3D:Bone3`.
|
||||
subpath.append(get_name());
|
||||
// The generated Skeleton3D node will be named Skeleton3D, so add it to the path.
|
||||
path.append("Skeleton3D");
|
||||
do {
|
||||
const int parent_index = current_gltf_node->get_parent();
|
||||
ERR_FAIL_INDEX_V(parent_index, gltf_node_count, NodePath());
|
||||
current_gltf_node = p_state->nodes[parent_index];
|
||||
} while (current_gltf_node->skeleton != -1);
|
||||
}
|
||||
const bool is_godot_single_root = p_state->extensions_used.has("GODOT_single_root");
|
||||
while (true) {
|
||||
const int parent_index = current_gltf_node->get_parent();
|
||||
if (is_godot_single_root && parent_index == -1) {
|
||||
// For GODOT_single_root scenes, the root glTF node becomes the Godot scene root, so it
|
||||
// should not be included in the path. Ex: A/B/C, A is single root, we want B/C only.
|
||||
break;
|
||||
}
|
||||
path.insert(0, current_gltf_node->get_name());
|
||||
if (!is_godot_single_root && parent_index == -1) {
|
||||
break;
|
||||
}
|
||||
ERR_FAIL_INDEX_V(parent_index, gltf_node_count, NodePath());
|
||||
current_gltf_node = p_state->nodes[parent_index];
|
||||
}
|
||||
if (unlikely(path.is_empty())) {
|
||||
path.append(".");
|
||||
}
|
||||
return NodePath(path, subpath, false);
|
||||
}
|
||||
|
@ -103,7 +103,10 @@ public:
|
||||
void set_light(GLTFLightIndex p_light);
|
||||
|
||||
Variant get_additional_data(const StringName &p_extension_name);
|
||||
bool has_additional_data(const StringName &p_extension_name);
|
||||
void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
|
||||
|
||||
NodePath get_scene_node_path(Ref<GLTFState> p_state, bool p_handle_skeletons = true);
|
||||
};
|
||||
|
||||
#endif // GLTF_NODE_H
|
||||
|
173
modules/gltf/structures/gltf_object_model_property.cpp
Normal file
173
modules/gltf/structures/gltf_object_model_property.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/**************************************************************************/
|
||||
/* gltf_object_model_property.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "gltf_object_model_property.h"
|
||||
|
||||
#include "../gltf_template_convert.h"
|
||||
|
||||
void GLTFObjectModelProperty::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_UNKNOWN);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_BOOL);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT_ARRAY);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT2);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT4);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT2X2);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT3X3);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_FLOAT4X4);
|
||||
BIND_ENUM_CONSTANT(GLTF_OBJECT_MODEL_TYPE_INT);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("append_node_path", "node_path"), &GLTFObjectModelProperty::append_node_path);
|
||||
ClassDB::bind_method(D_METHOD("append_path_to_property", "node_path", "prop_name"), &GLTFObjectModelProperty::append_path_to_property);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_accessor_type"), &GLTFObjectModelProperty::get_accessor_type);
|
||||
ClassDB::bind_method(D_METHOD("get_gltf_to_godot_expression"), &GLTFObjectModelProperty::get_gltf_to_godot_expression);
|
||||
ClassDB::bind_method(D_METHOD("set_gltf_to_godot_expression", "gltf_to_godot_expr"), &GLTFObjectModelProperty::set_gltf_to_godot_expression);
|
||||
ClassDB::bind_method(D_METHOD("get_godot_to_gltf_expression"), &GLTFObjectModelProperty::get_godot_to_gltf_expression);
|
||||
ClassDB::bind_method(D_METHOD("set_godot_to_gltf_expression", "godot_to_gltf_expr"), &GLTFObjectModelProperty::set_godot_to_gltf_expression);
|
||||
ClassDB::bind_method(D_METHOD("get_node_paths"), &GLTFObjectModelProperty::get_node_paths);
|
||||
ClassDB::bind_method(D_METHOD("has_node_paths"), &GLTFObjectModelProperty::has_node_paths);
|
||||
ClassDB::bind_method(D_METHOD("set_node_paths", "node_paths"), &GLTFObjectModelProperty::set_node_paths);
|
||||
ClassDB::bind_method(D_METHOD("get_object_model_type"), &GLTFObjectModelProperty::get_object_model_type);
|
||||
ClassDB::bind_method(D_METHOD("set_object_model_type", "type"), &GLTFObjectModelProperty::set_object_model_type);
|
||||
ClassDB::bind_method(D_METHOD("get_json_pointers"), &GLTFObjectModelProperty::get_json_pointers_bind);
|
||||
ClassDB::bind_method(D_METHOD("has_json_pointers"), &GLTFObjectModelProperty::has_json_pointers);
|
||||
ClassDB::bind_method(D_METHOD("set_json_pointers", "json_pointers"), &GLTFObjectModelProperty::set_json_pointers_bind);
|
||||
ClassDB::bind_method(D_METHOD("get_variant_type"), &GLTFObjectModelProperty::get_variant_type);
|
||||
ClassDB::bind_method(D_METHOD("set_variant_type", "variant_type"), &GLTFObjectModelProperty::set_variant_type);
|
||||
ClassDB::bind_method(D_METHOD("set_types", "variant_type", "obj_model_type"), &GLTFObjectModelProperty::set_types);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gltf_to_godot_expression", PROPERTY_HINT_RESOURCE_TYPE, "Expression"), "set_gltf_to_godot_expression", "get_gltf_to_godot_expression"); // Ref<Expression>
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "godot_to_gltf_expression", PROPERTY_HINT_RESOURCE_TYPE, "Expression"), "set_godot_to_gltf_expression", "get_godot_to_gltf_expression"); // Ref<Expression>
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "node_paths", PROPERTY_HINT_TYPE_STRING, "NodePath"), "set_node_paths", "get_node_paths"); // TypedArray<NodePath>
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "object_model_type"), "set_object_model_type", "get_object_model_type"); // GLTFObjectModelType
|
||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "json_pointers"), "set_json_pointers", "get_json_pointers"); // TypedArray<PackedStringArray>
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "variant_type"), "set_variant_type", "get_variant_type"); // Variant::Type
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::append_node_path(const NodePath &p_node_path) {
|
||||
node_paths.push_back(p_node_path);
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::append_path_to_property(const NodePath &p_node_path, const StringName &p_prop_name) {
|
||||
Vector<StringName> node_names = p_node_path.get_names();
|
||||
Vector<StringName> subpath = p_node_path.get_subnames();
|
||||
subpath.append(p_prop_name);
|
||||
node_paths.push_back(NodePath(node_names, subpath, false));
|
||||
}
|
||||
|
||||
GLTFAccessor::GLTFAccessorType GLTFObjectModelProperty::get_accessor_type() const {
|
||||
switch (object_model_type) {
|
||||
case GLTF_OBJECT_MODEL_TYPE_FLOAT2:
|
||||
return GLTFAccessor::TYPE_VEC2;
|
||||
case GLTF_OBJECT_MODEL_TYPE_FLOAT3:
|
||||
return GLTFAccessor::TYPE_VEC3;
|
||||
case GLTF_OBJECT_MODEL_TYPE_FLOAT4:
|
||||
return GLTFAccessor::TYPE_VEC4;
|
||||
case GLTF_OBJECT_MODEL_TYPE_FLOAT2X2:
|
||||
return GLTFAccessor::TYPE_MAT2;
|
||||
case GLTF_OBJECT_MODEL_TYPE_FLOAT3X3:
|
||||
return GLTFAccessor::TYPE_MAT3;
|
||||
case GLTF_OBJECT_MODEL_TYPE_FLOAT4X4:
|
||||
return GLTFAccessor::TYPE_MAT4;
|
||||
default:
|
||||
return GLTFAccessor::TYPE_SCALAR;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Expression> GLTFObjectModelProperty::get_gltf_to_godot_expression() const {
|
||||
return gltf_to_godot_expr;
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_gltf_to_godot_expression(Ref<Expression> p_gltf_to_godot_expr) {
|
||||
gltf_to_godot_expr = p_gltf_to_godot_expr;
|
||||
}
|
||||
|
||||
Ref<Expression> GLTFObjectModelProperty::get_godot_to_gltf_expression() const {
|
||||
return godot_to_gltf_expr;
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_godot_to_gltf_expression(Ref<Expression> p_godot_to_gltf_expr) {
|
||||
godot_to_gltf_expr = p_godot_to_gltf_expr;
|
||||
}
|
||||
|
||||
TypedArray<NodePath> GLTFObjectModelProperty::get_node_paths() const {
|
||||
return node_paths;
|
||||
}
|
||||
|
||||
bool GLTFObjectModelProperty::has_node_paths() const {
|
||||
return !node_paths.is_empty();
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_node_paths(TypedArray<NodePath> p_node_paths) {
|
||||
node_paths = p_node_paths;
|
||||
}
|
||||
|
||||
GLTFObjectModelProperty::GLTFObjectModelType GLTFObjectModelProperty::get_object_model_type() const {
|
||||
return object_model_type;
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_object_model_type(GLTFObjectModelType p_type) {
|
||||
object_model_type = p_type;
|
||||
}
|
||||
|
||||
Vector<PackedStringArray> GLTFObjectModelProperty::get_json_pointers() const {
|
||||
return json_pointers;
|
||||
}
|
||||
|
||||
bool GLTFObjectModelProperty::has_json_pointers() const {
|
||||
return !json_pointers.is_empty();
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_json_pointers(const Vector<PackedStringArray> &p_json_pointers) {
|
||||
json_pointers = p_json_pointers;
|
||||
}
|
||||
|
||||
TypedArray<PackedStringArray> GLTFObjectModelProperty::get_json_pointers_bind() const {
|
||||
return GLTFTemplateConvert::to_array(json_pointers);
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_json_pointers_bind(const TypedArray<PackedStringArray> &p_json_pointers) {
|
||||
GLTFTemplateConvert::set_from_array(json_pointers, p_json_pointers);
|
||||
}
|
||||
|
||||
Variant::Type GLTFObjectModelProperty::get_variant_type() const {
|
||||
return variant_type;
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_variant_type(Variant::Type p_variant_type) {
|
||||
variant_type = p_variant_type;
|
||||
}
|
||||
|
||||
void GLTFObjectModelProperty::set_types(Variant::Type p_variant_type, GLTFObjectModelType p_obj_model_type) {
|
||||
variant_type = p_variant_type;
|
||||
object_model_type = p_obj_model_type;
|
||||
}
|
104
modules/gltf/structures/gltf_object_model_property.h
Normal file
104
modules/gltf/structures/gltf_object_model_property.h
Normal file
@ -0,0 +1,104 @@
|
||||
/**************************************************************************/
|
||||
/* gltf_object_model_property.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef GLTF_OBJECT_MODEL_PROPERTY_H
|
||||
#define GLTF_OBJECT_MODEL_PROPERTY_H
|
||||
|
||||
#include "core/math/expression.h"
|
||||
#include "core/variant/typed_array.h"
|
||||
#include "gltf_accessor.h"
|
||||
|
||||
// Object model: https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/ObjectModel.adoc
|
||||
// KHR_animation_pointer: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer
|
||||
|
||||
class GLTFObjectModelProperty : public RefCounted {
|
||||
GDCLASS(GLTFObjectModelProperty, RefCounted);
|
||||
|
||||
public:
|
||||
enum GLTFObjectModelType {
|
||||
GLTF_OBJECT_MODEL_TYPE_UNKNOWN,
|
||||
GLTF_OBJECT_MODEL_TYPE_BOOL,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT_ARRAY,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT2,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT3,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT4,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT2X2,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT3X3,
|
||||
GLTF_OBJECT_MODEL_TYPE_FLOAT4X4,
|
||||
GLTF_OBJECT_MODEL_TYPE_INT,
|
||||
};
|
||||
|
||||
private:
|
||||
Ref<Expression> gltf_to_godot_expr;
|
||||
Ref<Expression> godot_to_gltf_expr;
|
||||
TypedArray<NodePath> node_paths;
|
||||
GLTFObjectModelType object_model_type = GLTF_OBJECT_MODEL_TYPE_UNKNOWN;
|
||||
Vector<PackedStringArray> json_pointers;
|
||||
Variant::Type variant_type = Variant::NIL;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void append_node_path(const NodePath &p_node_path);
|
||||
void append_path_to_property(const NodePath &p_node_path, const StringName &p_prop_name);
|
||||
|
||||
GLTFAccessor::GLTFAccessorType get_accessor_type() const;
|
||||
|
||||
Ref<Expression> get_gltf_to_godot_expression() const;
|
||||
void set_gltf_to_godot_expression(Ref<Expression> p_gltf_to_godot_expr);
|
||||
|
||||
Ref<Expression> get_godot_to_gltf_expression() const;
|
||||
void set_godot_to_gltf_expression(Ref<Expression> p_godot_to_gltf_expr);
|
||||
|
||||
TypedArray<NodePath> get_node_paths() const;
|
||||
bool has_node_paths() const;
|
||||
void set_node_paths(TypedArray<NodePath> p_node_paths);
|
||||
|
||||
GLTFObjectModelType get_object_model_type() const;
|
||||
void set_object_model_type(GLTFObjectModelType p_type);
|
||||
|
||||
Vector<PackedStringArray> get_json_pointers() const;
|
||||
bool has_json_pointers() const;
|
||||
void set_json_pointers(const Vector<PackedStringArray> &p_json_pointers);
|
||||
|
||||
TypedArray<PackedStringArray> get_json_pointers_bind() const;
|
||||
void set_json_pointers_bind(const TypedArray<PackedStringArray> &p_json_pointers);
|
||||
|
||||
Variant::Type get_variant_type() const;
|
||||
void set_variant_type(Variant::Type p_variant_type);
|
||||
|
||||
void set_types(Variant::Type p_variant_type, GLTFObjectModelType p_obj_model_type);
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(GLTFObjectModelProperty::GLTFObjectModelType);
|
||||
|
||||
#endif // GLTF_OBJECT_MODEL_PROPERTY_H
|
Loading…
Reference in New Issue
Block a user