mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 11:32:13 +00:00
GLTF: Implement the glTF Object Model to support JSON pointer properties
This commit is contained in:
parent
cd367b3da3
commit
4b66a25f52
@ -20,6 +20,7 @@ def get_doc_classes():
|
||||
"GLTFLight",
|
||||
"GLTFMesh",
|
||||
"GLTFNode",
|
||||
"GLTFObjectModelProperty",
|
||||
"GLTFPhysicsBody",
|
||||
"GLTFPhysicsShape",
|
||||
"GLTFSkeleton",
|
||||
|
@ -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" />
|
||||
|
@ -32,7 +32,7 @@
|
||||
<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.
|
||||
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>
|
||||
|
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);
|
||||
|
||||
|
@ -43,6 +43,7 @@ class GLTFDocumentExtension;
|
||||
class GLTFLight;
|
||||
class GLTFMesh;
|
||||
class GLTFNode;
|
||||
class GLTFObjectModelProperty;
|
||||
class GLTFSkeleton;
|
||||
class GLTFSkin;
|
||||
class GLTFSpecGloss;
|
||||
|
@ -6034,6 +6034,429 @@ T GLTFDocument::_interpolate_track(const Vector<double> &p_times, const Vector<T
|
||||
ERR_FAIL_V(p_values[0]);
|
||||
}
|
||||
|
||||
NodePath GLTFDocument::_find_material_node_path(Ref<GLTFState> p_state, Ref<Material> p_material) {
|
||||
int mesh_index = 0;
|
||||
for (Ref<GLTFMesh> gltf_mesh : p_state->meshes) {
|
||||
TypedArray<Material> materials = gltf_mesh->get_instance_materials();
|
||||
for (int mat_index = 0; mat_index < materials.size(); mat_index++) {
|
||||
if (materials[mat_index] == p_material) {
|
||||
for (Ref<GLTFNode> gltf_node : p_state->nodes) {
|
||||
if (gltf_node->mesh == mesh_index) {
|
||||
NodePath node_path = gltf_node->get_scene_node_path(p_state);
|
||||
// Example: MyNode:mesh:surface_0/material:albedo_color, so we want the mesh:surface_0/material part.
|
||||
Vector<StringName> subpath;
|
||||
subpath.append("mesh");
|
||||
subpath.append("surface_" + itos(mat_index) + "/material");
|
||||
return NodePath(node_path.get_names(), subpath, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mesh_index++;
|
||||
}
|
||||
return NodePath();
|
||||
}
|
||||
|
||||
Ref<GLTFObjectModelProperty> GLTFDocument::import_object_model_property(Ref<GLTFState> p_state, const String &p_json_pointer) {
|
||||
if (p_state->object_model_properties.has(p_json_pointer)) {
|
||||
return p_state->object_model_properties[p_json_pointer];
|
||||
}
|
||||
Ref<GLTFObjectModelProperty> ret;
|
||||
// Split the JSON pointer into its components.
|
||||
const PackedStringArray split = p_json_pointer.split("/", false);
|
||||
ERR_FAIL_COND_V_MSG(split.size() < 3, ret, "glTF: Cannot use JSON pointer '" + p_json_pointer + "' because it does not contain enough elements. The only animatable properties are at least 3 levels deep (ex: '/nodes/0/translation' or '/materials/0/emissiveFactor').");
|
||||
ret.instantiate();
|
||||
ret->set_json_pointers({ split });
|
||||
// Partial paths are passed to GLTFDocumentExtension classes if GLTFDocument cannot handle a given JSON pointer.
|
||||
TypedArray<NodePath> partial_paths;
|
||||
// Note: This might not be an integer, but in that case, we don't use this value anyway.
|
||||
const int top_level_index = split[1].to_int();
|
||||
// For JSON pointers present in the core glTF Object Model, hard-code them in GLTFDocument.
|
||||
// https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/ObjectModel.adoc
|
||||
if (split[0] == "nodes") {
|
||||
ERR_FAIL_INDEX_V_MSG(top_level_index, p_state->nodes.size(), ret, vformat("glTF: Unable to find node %d for JSON pointer '%s'.", top_level_index, p_json_pointer));
|
||||
Ref<GLTFNode> pointed_gltf_node = p_state->nodes[top_level_index];
|
||||
NodePath node_path = pointed_gltf_node->get_scene_node_path(p_state);
|
||||
partial_paths.append(node_path);
|
||||
// Check if it's something we should be able to handle.
|
||||
const String &node_prop = split[2];
|
||||
if (node_prop == "translation") {
|
||||
ret->append_path_to_property(node_path, "position");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (node_prop == "rotation") {
|
||||
ret->append_path_to_property(node_path, "quaternion");
|
||||
ret->set_types(Variant::QUATERNION, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4);
|
||||
} else if (node_prop == "scale") {
|
||||
ret->append_path_to_property(node_path, "scale");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (node_prop == "matrix") {
|
||||
ret->append_path_to_property(node_path, "transform");
|
||||
ret->set_types(Variant::TRANSFORM3D, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4X4);
|
||||
} else if (node_prop == "globalMatrix") {
|
||||
ret->append_path_to_property(node_path, "global_transform");
|
||||
ret->set_types(Variant::TRANSFORM3D, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4X4);
|
||||
} else if (node_prop == "weights") {
|
||||
if (split.size() > 3) {
|
||||
const String &weight_index_string = split[3];
|
||||
ret->append_path_to_property(node_path, "blend_shapes/morph_" + weight_index_string);
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
}
|
||||
// Else, Godot's MeshInstance3D does not expose the blend shape weights as one property.
|
||||
// But that's fine, we handle this case in _parse_animation_pointer instead.
|
||||
}
|
||||
} else if (split[0] == "cameras") {
|
||||
const String &camera_prop = split[2];
|
||||
for (Ref<GLTFNode> gltf_node : p_state->nodes) {
|
||||
if (gltf_node->camera == top_level_index) {
|
||||
NodePath node_path = gltf_node->get_scene_node_path(p_state);
|
||||
partial_paths.append(node_path);
|
||||
// Check if it's something we should be able to handle.
|
||||
if (camera_prop == "orthographic" || camera_prop == "perspective") {
|
||||
ERR_FAIL_COND_V(split.size() < 4, ret);
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
const String &sub_prop = split[3];
|
||||
if (sub_prop == "xmag" || sub_prop == "ymag") {
|
||||
ret->append_path_to_property(node_path, "size");
|
||||
} else if (sub_prop == "yfov") {
|
||||
ret->append_path_to_property(node_path, "fov");
|
||||
GLTFCamera::set_fov_conversion_expressions(ret);
|
||||
} else if (sub_prop == "zfar") {
|
||||
ret->append_path_to_property(node_path, "far");
|
||||
} else if (sub_prop == "znear") {
|
||||
ret->append_path_to_property(node_path, "near");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (split[0] == "materials") {
|
||||
ERR_FAIL_INDEX_V_MSG(top_level_index, p_state->materials.size(), ret, vformat("glTF: Unable to find material %d for JSON pointer '%s'.", top_level_index, p_json_pointer));
|
||||
Ref<Material> pointed_material = p_state->materials[top_level_index];
|
||||
NodePath mat_path = _find_material_node_path(p_state, pointed_material);
|
||||
if (mat_path.is_empty()) {
|
||||
WARN_PRINT(vformat("glTF: Unable to find a path to the material %d for JSON pointer '%s'. This is likely bad data but it's also possible this is intentional. Continuing anyway.", top_level_index, p_json_pointer));
|
||||
} else {
|
||||
partial_paths.append(mat_path);
|
||||
const String &mat_prop = split[2];
|
||||
if (mat_prop == "alphaCutoff") {
|
||||
ret->append_path_to_property(mat_path, "alpha_scissor_threshold");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (mat_prop == "emissiveFactor") {
|
||||
ret->append_path_to_property(mat_path, "emission");
|
||||
ret->set_types(Variant::COLOR, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (mat_prop == "extensions") {
|
||||
ERR_FAIL_COND_V(split.size() < 5, ret);
|
||||
const String &ext_name = split[3];
|
||||
const String &ext_prop = split[4];
|
||||
if (ext_name == "KHR_materials_emissive_strength" && ext_prop == "emissiveStrength") {
|
||||
ret->append_path_to_property(mat_path, "emission_energy_multiplier");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_COND_V(split.size() < 4, ret);
|
||||
const String &sub_prop = split[3];
|
||||
if (mat_prop == "normalTexture") {
|
||||
if (sub_prop == "scale") {
|
||||
ret->append_path_to_property(mat_path, "normal_scale");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
}
|
||||
} else if (mat_prop == "occlusionTexture") {
|
||||
if (sub_prop == "strength") {
|
||||
// This is the closest thing Godot has to an occlusion strength property.
|
||||
ret->append_path_to_property(mat_path, "ao_light_affect");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
}
|
||||
} else if (mat_prop == "pbrMetallicRoughness") {
|
||||
if (sub_prop == "baseColorFactor") {
|
||||
ret->append_path_to_property(mat_path, "albedo_color");
|
||||
ret->set_types(Variant::COLOR, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4);
|
||||
} else if (sub_prop == "metallicFactor") {
|
||||
ret->append_path_to_property(mat_path, "metallic");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (sub_prop == "roughnessFactor") {
|
||||
ret->append_path_to_property(mat_path, "roughness");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (sub_prop == "baseColorTexture") {
|
||||
ERR_FAIL_COND_V(split.size() < 6, ret);
|
||||
const String &tex_ext_dict = split[4];
|
||||
const String &tex_ext_name = split[5];
|
||||
const String &tex_ext_prop = split[6];
|
||||
if (tex_ext_dict == "extensions" && tex_ext_name == "KHR_texture_transform") {
|
||||
// Godot only supports UVs for the whole material, not per texture.
|
||||
// We treat the albedo texture as the main texture, and import as UV1.
|
||||
// Godot does not support texture rotation, only offset and scale.
|
||||
if (tex_ext_prop == "offset") {
|
||||
ret->append_path_to_property(mat_path, "uv1_offset");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT2);
|
||||
} else if (tex_ext_prop == "scale") {
|
||||
ret->append_path_to_property(mat_path, "uv1_scale");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (split[0] == "meshes") {
|
||||
for (Ref<GLTFNode> gltf_node : p_state->nodes) {
|
||||
if (gltf_node->mesh == top_level_index) {
|
||||
NodePath node_path = gltf_node->get_scene_node_path(p_state);
|
||||
Vector<StringName> subpath;
|
||||
subpath.append("mesh");
|
||||
partial_paths.append(NodePath(node_path.get_names(), subpath, false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (split[0] == "extensions") {
|
||||
if (split[1] == "KHR_lights_punctual" && split[2] == "lights" && split.size() > 4) {
|
||||
const int light_index = split[3].to_int();
|
||||
ERR_FAIL_INDEX_V_MSG(light_index, p_state->lights.size(), ret, vformat("glTF: Unable to find light %d for JSON pointer '%s'.", light_index, p_json_pointer));
|
||||
const String &light_prop = split[4];
|
||||
const Ref<GLTFLight> pointed_light = p_state->lights[light_index];
|
||||
for (Ref<GLTFNode> gltf_node : p_state->nodes) {
|
||||
if (gltf_node->light == light_index) {
|
||||
NodePath node_path = gltf_node->get_scene_node_path(p_state);
|
||||
partial_paths.append(node_path);
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
// Check if it's something we should be able to handle.
|
||||
if (light_prop == "color") {
|
||||
ret->append_path_to_property(node_path, "light_color");
|
||||
ret->set_types(Variant::COLOR, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (light_prop == "intensity") {
|
||||
ret->append_path_to_property(node_path, "light_energy");
|
||||
} else if (light_prop == "range") {
|
||||
const String &light_type = p_state->lights[light_index]->light_type;
|
||||
if (light_type == "spot") {
|
||||
ret->append_path_to_property(node_path, "spot_range");
|
||||
} else {
|
||||
ret->append_path_to_property(node_path, "omni_range");
|
||||
}
|
||||
} else if (light_prop == "spot") {
|
||||
ERR_FAIL_COND_V(split.size() < 6, ret);
|
||||
const String &sub_prop = split[5];
|
||||
if (sub_prop == "innerConeAngle") {
|
||||
ret->append_path_to_property(node_path, "spot_angle_attenuation");
|
||||
GLTFLight::set_cone_inner_attenuation_conversion_expressions(ret);
|
||||
} else if (sub_prop == "outerConeAngle") {
|
||||
ret->append_path_to_property(node_path, "spot_angle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Additional JSON pointers can be added by GLTFDocumentExtension classes.
|
||||
// We only need this if no mapping has been found yet from GLTFDocument's internal code.
|
||||
// When available, we pass the partial paths to the extension to help it generate the full path.
|
||||
// For example, for `/nodes/3/extensions/MY_ext/prop`, we pass a NodePath that leads to node 3,
|
||||
// so the GLTFDocumentExtension class only needs to resolve the last `MY_ext/prop` part of the path.
|
||||
// It should check `split.size() > 4 and split[0] == "nodes" and split[2] == "extensions" and split[3] == "MY_ext"`
|
||||
// at the start of the function to check if this JSON pointer applies to it, then it can handle `split[4]`.
|
||||
if (!ret->has_node_paths()) {
|
||||
for (Ref<GLTFDocumentExtension> ext : all_document_extensions) {
|
||||
ret = ext->import_object_model_property(p_state, split, partial_paths);
|
||||
if (ret.is_valid() && ret->has_node_paths()) {
|
||||
if (!ret->has_json_pointers()) {
|
||||
ret->set_json_pointers({ split });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret.is_null() || !ret->has_node_paths()) {
|
||||
if (split.has("KHR_texture_transform")) {
|
||||
WARN_VERBOSE(vformat("glTF: Texture transforms are only supported per material in Godot. All KHR_texture_transform properties will be ignored except for the albedo texture. Ignoring JSON pointer '%s'.", p_json_pointer));
|
||||
} else {
|
||||
WARN_PRINT(vformat("glTF: Animation contained JSON pointer '%s' which could not be resolved. This property will not be animated.", p_json_pointer));
|
||||
}
|
||||
}
|
||||
}
|
||||
p_state->object_model_properties[p_json_pointer] = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ref<GLTFObjectModelProperty> GLTFDocument::export_object_model_property(Ref<GLTFState> p_state, const NodePath &p_node_path, const Node *p_godot_node, GLTFNodeIndex p_gltf_node_index) {
|
||||
Ref<GLTFObjectModelProperty> ret;
|
||||
const Object *target_object = p_godot_node;
|
||||
const Vector<StringName> subpath = p_node_path.get_subnames();
|
||||
ERR_FAIL_COND_V_MSG(subpath.is_empty(), ret, "glTF: Cannot export empty property. No property was specified in the NodePath: " + p_node_path);
|
||||
int target_prop_depth = 0;
|
||||
for (StringName subname : subpath) {
|
||||
Variant target_property = target_object->get(subname);
|
||||
if (target_property.get_type() == Variant::OBJECT) {
|
||||
target_object = target_property;
|
||||
if (target_object) {
|
||||
target_prop_depth++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
const String &target_prop = subpath[target_prop_depth];
|
||||
ret.instantiate();
|
||||
ret->set_node_paths({ p_node_path });
|
||||
Vector<PackedStringArray> split_json_pointers;
|
||||
PackedStringArray split_json_pointer;
|
||||
if (Object::cast_to<BaseMaterial3D>(target_object)) {
|
||||
for (int i = 0; i < p_state->materials.size(); i++) {
|
||||
if (p_state->materials[i].ptr() == target_object) {
|
||||
split_json_pointer.append("materials");
|
||||
split_json_pointer.append(itos(i));
|
||||
if (target_prop == "alpha_scissor_threshold") {
|
||||
split_json_pointer.append("alphaCutoff");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (target_prop == "emission") {
|
||||
split_json_pointer.append("emissiveFactor");
|
||||
ret->set_types(Variant::COLOR, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (target_prop == "emission_energy_multiplier") {
|
||||
split_json_pointer.append("extensions");
|
||||
split_json_pointer.append("KHR_materials_emissive_strength");
|
||||
split_json_pointer.append("emissiveStrength");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (target_prop == "normal_scale") {
|
||||
split_json_pointer.append("normalTexture");
|
||||
split_json_pointer.append("scale");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (target_prop == "ao_light_affect") {
|
||||
split_json_pointer.append("occlusionTexture");
|
||||
split_json_pointer.append("strength");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (target_prop == "albedo_color") {
|
||||
split_json_pointer.append("pbrMetallicRoughness");
|
||||
split_json_pointer.append("baseColorFactor");
|
||||
ret->set_types(Variant::COLOR, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4);
|
||||
} else if (target_prop == "metallic") {
|
||||
split_json_pointer.append("pbrMetallicRoughness");
|
||||
split_json_pointer.append("metallicFactor");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (target_prop == "roughness") {
|
||||
split_json_pointer.append("pbrMetallicRoughness");
|
||||
split_json_pointer.append("roughnessFactor");
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
} else if (target_prop == "uv1_offset" || target_prop == "uv1_scale") {
|
||||
split_json_pointer.append("pbrMetallicRoughness");
|
||||
split_json_pointer.append("baseColorTexture");
|
||||
split_json_pointer.append("extensions");
|
||||
split_json_pointer.append("KHR_texture_transform");
|
||||
if (target_prop == "uv1_offset") {
|
||||
split_json_pointer.append("offset");
|
||||
} else {
|
||||
split_json_pointer.append("scale");
|
||||
}
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT2);
|
||||
} else {
|
||||
split_json_pointer.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Properties directly on Godot nodes.
|
||||
Ref<GLTFNode> gltf_node = p_state->nodes[p_gltf_node_index];
|
||||
if (Object::cast_to<Camera3D>(target_object) && gltf_node->camera >= 0) {
|
||||
split_json_pointer.append("cameras");
|
||||
split_json_pointer.append(itos(gltf_node->camera));
|
||||
const Camera3D *camera_node = Object::cast_to<Camera3D>(target_object);
|
||||
const Camera3D::ProjectionType projection_type = camera_node->get_projection();
|
||||
if (projection_type == Camera3D::PROJECTION_PERSPECTIVE) {
|
||||
split_json_pointer.append("perspective");
|
||||
} else {
|
||||
split_json_pointer.append("orthographic");
|
||||
}
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
if (target_prop == "size") {
|
||||
PackedStringArray xmag = split_json_pointer.duplicate();
|
||||
xmag.append("xmag");
|
||||
split_json_pointers.append(xmag);
|
||||
split_json_pointer.append("ymag");
|
||||
} else if (target_prop == "fov") {
|
||||
split_json_pointer.append("yfov");
|
||||
GLTFCamera::set_fov_conversion_expressions(ret);
|
||||
} else if (target_prop == "far") {
|
||||
split_json_pointer.append("zfar");
|
||||
} else if (target_prop == "near") {
|
||||
split_json_pointer.append("znear");
|
||||
} else {
|
||||
split_json_pointer.clear();
|
||||
}
|
||||
} else if (Object::cast_to<Light3D>(target_object) && gltf_node->light >= 0) {
|
||||
split_json_pointer.append("extensions");
|
||||
split_json_pointer.append("KHR_lights_punctual");
|
||||
split_json_pointer.append("lights");
|
||||
split_json_pointer.append(itos(gltf_node->light));
|
||||
ret->set_types(Variant::FLOAT, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT);
|
||||
if (target_prop == "light_color") {
|
||||
split_json_pointer.append("color");
|
||||
ret->set_types(Variant::COLOR, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (target_prop == "light_energy") {
|
||||
split_json_pointer.append("intensity");
|
||||
} else if (target_prop == "spot_range") {
|
||||
split_json_pointer.append("range");
|
||||
} else if (target_prop == "omni_range") {
|
||||
split_json_pointer.append("range");
|
||||
} else if (target_prop == "spot_angle") {
|
||||
split_json_pointer.append("spot");
|
||||
split_json_pointer.append("outerConeAngle");
|
||||
} else if (target_prop == "spot_angle_attenuation") {
|
||||
split_json_pointer.append("spot");
|
||||
split_json_pointer.append("innerConeAngle");
|
||||
GLTFLight::set_cone_inner_attenuation_conversion_expressions(ret);
|
||||
} else {
|
||||
split_json_pointer.clear();
|
||||
}
|
||||
} else if (Object::cast_to<MeshInstance3D>(target_object) && target_prop.begins_with("blend_shapes/morph_")) {
|
||||
const String &weight_index_string = target_prop.trim_prefix("blend_shapes/morph_");
|
||||
split_json_pointer.append("nodes");
|
||||
split_json_pointer.append(itos(p_gltf_node_index));
|
||||
split_json_pointer.append("weights");
|
||||
split_json_pointer.append(weight_index_string);
|
||||
}
|
||||
// Transform properties. Check for all 3D nodes if we haven't resolved the JSON pointer yet.
|
||||
// Note: Do not put this in an `else`, because otherwise this will not be reached.
|
||||
if (split_json_pointer.is_empty() && Object::cast_to<Node3D>(target_object)) {
|
||||
split_json_pointer.append("nodes");
|
||||
split_json_pointer.append(itos(p_gltf_node_index));
|
||||
if (target_prop == "position") {
|
||||
split_json_pointer.append("translation");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (target_prop == "quaternion") {
|
||||
// Note: Only Quaternion rotation can be converted from Godot in this mapping.
|
||||
// Struct methods like from_euler are not accessible from the Expression class. :(
|
||||
split_json_pointer.append("rotation");
|
||||
ret->set_types(Variant::QUATERNION, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4);
|
||||
} else if (target_prop == "scale") {
|
||||
split_json_pointer.append("scale");
|
||||
ret->set_types(Variant::VECTOR3, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT3);
|
||||
} else if (target_prop == "transform") {
|
||||
split_json_pointer.append("matrix");
|
||||
ret->set_types(Variant::TRANSFORM3D, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4X4);
|
||||
} else if (target_prop == "global_transform") {
|
||||
split_json_pointer.append("globalMatrix");
|
||||
ret->set_types(Variant::TRANSFORM3D, GLTFObjectModelProperty::GLTF_OBJECT_MODEL_TYPE_FLOAT4X4);
|
||||
} else {
|
||||
split_json_pointer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Additional JSON pointers can be added by GLTFDocumentExtension classes.
|
||||
// We only need this if no mapping has been found yet from GLTFDocument's internal code.
|
||||
// We pass as many pieces of information as we can to the extension to give it lots of context.
|
||||
if (split_json_pointer.is_empty()) {
|
||||
for (Ref<GLTFDocumentExtension> ext : all_document_extensions) {
|
||||
ret = ext->export_object_model_property(p_state, p_node_path, p_godot_node, p_gltf_node_index, target_object, target_prop_depth);
|
||||
if (ret.is_valid() && ret->has_json_pointers()) {
|
||||
if (!ret->has_node_paths()) {
|
||||
ret->set_node_paths({ p_node_path });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// GLTFDocument's internal code found a mapping, so set it and return it.
|
||||
split_json_pointers.append(split_json_pointer);
|
||||
ret->set_json_pointers(split_json_pointers);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, const GLTFAnimationIndex p_index, const bool p_trimming, const bool p_remove_immutable_tracks) {
|
||||
ERR_FAIL_COND(p_state.is_null());
|
||||
Node *scene_root = p_animation_player->get_parent();
|
||||
@ -7178,6 +7601,9 @@ void GLTFDocument::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lossy_quality"), "set_lossy_quality", "get_lossy_quality");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "root_node_mode"), "set_root_node_mode", "get_root_node_mode");
|
||||
|
||||
ClassDB::bind_static_method("GLTFDocument", D_METHOD("import_object_model_property", "state", "json_pointer"), &GLTFDocument::import_object_model_property);
|
||||
ClassDB::bind_static_method("GLTFDocument", D_METHOD("export_object_model_property", "state", "node_path", "godot_node", "gltf_node_index"), &GLTFDocument::export_object_model_property);
|
||||
|
||||
ClassDB::bind_static_method("GLTFDocument", D_METHOD("register_gltf_document_extension", "extension", "first_priority"),
|
||||
&GLTFDocument::register_gltf_document_extension, DEFVAL(false));
|
||||
ClassDB::bind_static_method("GLTFDocument", D_METHOD("unregister_gltf_document_extension", "extension"),
|
||||
|
@ -88,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);
|
||||
|
@ -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"
|
||||
@ -101,6 +102,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);
|
||||
|
@ -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; }
|
||||
|
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