feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -1,11 +1,11 @@
|
|||
# Godot GLTF import and export module
|
||||
# Godot glTF import and export module
|
||||
|
||||
In a nutshell, the GLTF module works like this:
|
||||
In a nutshell, the glTF module works like this:
|
||||
|
||||
* The [`structures/`](structures/) folder contains GLTF structures, the
|
||||
small pieces that make up a GLTF file, represented as C++ classes.
|
||||
* The [`extensions/`](extensions/) folder contains GLTF extensions, which
|
||||
are optional features that build on top of the base GLTF spec.
|
||||
* The [`structures/`](structures/) folder contains glTF structures, the
|
||||
small pieces that make up a glTF file, represented as C++ classes.
|
||||
* The [`extensions/`](extensions/) folder contains glTF extensions, which
|
||||
are optional features that build on top of the base glTF spec.
|
||||
* [`GLTFState`](gltf_state.h) holds collections of structures and extensions.
|
||||
* [`GLTFDocument`](gltf_document.h) operates on GLTFState and its elements.
|
||||
* The [`editor/`](editor/) folder uses GLTFDocument to import and export 3D models.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
def can_build(env, platform):
|
||||
env.module_add_dependencies("gltf", ["csg", "gridmap"], True)
|
||||
return not env["disable_3d"]
|
||||
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ def get_doc_classes():
|
|||
"GLTFLight",
|
||||
"GLTFMesh",
|
||||
"GLTFNode",
|
||||
"GLTFObjectModelProperty",
|
||||
"GLTFPhysicsBody",
|
||||
"GLTFPhysicsShape",
|
||||
"GLTFSkeleton",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFAccessor" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents a GLTF accessor.
|
||||
Represents a glTF accessor.
|
||||
</brief_description>
|
||||
<description>
|
||||
GLTFAccessor is a data structure representing GLTF a [code]accessor[/code] that would be found in the [code]"accessors"[/code] array. A buffer is a blob of binary data. A buffer view is a slice of a buffer. An accessor is a typed interpretation of the data in a buffer view.
|
||||
Most custom data stored in GLTF does not need accessors, only buffer views (see [GLTFBufferView]). Accessors are for more advanced use cases such as interleaved mesh data encoded for the GPU.
|
||||
GLTFAccessor is a data structure representing a glTF [code]accessor[/code] that would be found in the [code]"accessors"[/code] array. A buffer is a blob of binary data. A buffer view is a slice of a buffer. An accessor is a typed interpretation of the data in a buffer view.
|
||||
Most custom data stored in glTF does not need accessors, only buffer views (see [GLTFBufferView]). Accessors are for more advanced use cases such as interleaved mesh data encoded for the GPU.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Buffers, BufferViews, and Accessors in Khronos glTF specification">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md</link>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
</tutorials>
|
||||
<members>
|
||||
<member name="accessor_type" type="int" setter="set_accessor_type" getter="get_accessor_type" enum="GLTFAccessor.GLTFAccessorType" default="0">
|
||||
The GLTF accessor type as an enum. Possible values are 0 for "SCALAR", 1 for "VEC2", 2 for "VEC3", 3 for "VEC4", 4 for "MAT2", 5 for "MAT3", and 6 for "MAT4".
|
||||
The glTF accessor type as an enum. Possible values are 0 for "SCALAR", 1 for "VEC2", 2 for "VEC3", 3 for "VEC4", 4 for "MAT2", 5 for "MAT3", and 6 for "MAT4".
|
||||
</member>
|
||||
<member name="buffer_view" type="int" setter="set_buffer_view" getter="get_buffer_view" default="-1">
|
||||
The index of the buffer view this accessor is referencing. If [code]-1[/code], this accessor is not referencing any buffer view.
|
||||
|
|
@ -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.
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
The offset relative to the start of the bufferView in bytes.
|
||||
</member>
|
||||
<member name="type" type="int" setter="set_type" getter="get_type" deprecated="Use [member accessor_type] instead.">
|
||||
The GLTF accessor type as an enum. Use [member accessor_type] instead.
|
||||
The glTF accessor type as an enum. Use [member accessor_type] instead.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<param index="0" name="extension_name" type="StringName" />
|
||||
<description>
|
||||
Gets additional arbitrary data in this [GLTFAnimation] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
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.
|
||||
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 [code]null[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_additional_data">
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
<param index="1" name="additional_data" type="Variant" />
|
||||
<description>
|
||||
Sets additional arbitrary data in this [GLTFAnimation] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the second argument can be anything you want.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFBufferView" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents a GLTF buffer view.
|
||||
Represents a glTF buffer view.
|
||||
</brief_description>
|
||||
<description>
|
||||
GLTFBufferView is a data structure representing GLTF a [code]bufferView[/code] that would be found in the [code]"bufferViews"[/code] array. A buffer is a blob of binary data. A buffer view is a slice of a buffer that can be used to identify and extract data from the buffer.
|
||||
GLTFBufferView is a data structure representing a glTF [code]bufferView[/code] that would be found in the [code]"bufferViews"[/code] array. A buffer is a blob of binary data. A buffer view is a slice of a buffer that can be used to identify and extract data from the buffer.
|
||||
Most custom uses of buffers only need to use the [member buffer], [member byte_length], and [member byte_offset]. The [member byte_stride] and [member indices] properties are for more advanced use cases such as interleaved mesh data encoded for the GPU.
|
||||
</description>
|
||||
<tutorials>
|
||||
|
|
@ -34,10 +34,10 @@
|
|||
The stride, in bytes, between interleaved data. If [code]-1[/code], this buffer view is not interleaved.
|
||||
</member>
|
||||
<member name="indices" type="bool" setter="set_indices" getter="get_indices" default="false">
|
||||
True if the GLTFBufferView's OpenGL GPU buffer type is an [code]ELEMENT_ARRAY_BUFFER[/code] used for vertex indices (integer constant [code]34963[/code]). False if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export.
|
||||
[code]true[/code] if the GLTFBufferView's OpenGL GPU buffer type is an [code]ELEMENT_ARRAY_BUFFER[/code] used for vertex indices (integer constant [code]34963[/code]). [code]false[/code] if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export.
|
||||
</member>
|
||||
<member name="vertex_attributes" type="bool" setter="set_vertex_attributes" getter="get_vertex_attributes" default="false">
|
||||
True if the GLTFBufferView's OpenGL GPU buffer type is an [code]ARRAY_BUFFER[/code] used for vertex attributes (integer constant [code]34962[/code]). False if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export.
|
||||
[code]true[/code] if the GLTFBufferView's OpenGL GPU buffer type is an [code]ARRAY_BUFFER[/code] used for vertex attributes (integer constant [code]34962[/code]). [code]false[/code] if the buffer type is any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set on import and used on export.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFCamera" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents a GLTF camera.
|
||||
Represents a glTF camera.
|
||||
</brief_description>
|
||||
<description>
|
||||
Represents a camera as defined by the base GLTF spec.
|
||||
Represents a camera as defined by the base glTF spec.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
<link title="GLTF camera detailed specification">https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera</link>
|
||||
<link title="GLTF camera spec and example file">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md</link>
|
||||
<link title="glTF camera detailed specification">https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera</link>
|
||||
<link title="glTF camera spec and example file">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="from_dictionary" qualifiers="static">
|
||||
|
|
@ -41,19 +41,19 @@
|
|||
</methods>
|
||||
<members>
|
||||
<member name="depth_far" type="float" setter="set_depth_far" getter="get_depth_far" default="4000.0">
|
||||
The distance to the far culling boundary for this camera relative to its local Z axis, in meters. This maps to GLTF's [code]zfar[/code] property.
|
||||
The distance to the far culling boundary for this camera relative to its local Z axis, in meters. This maps to glTF's [code]zfar[/code] property.
|
||||
</member>
|
||||
<member name="depth_near" type="float" setter="set_depth_near" getter="get_depth_near" default="0.05">
|
||||
The distance to the near culling boundary for this camera relative to its local Z axis, in meters. This maps to GLTF's [code]znear[/code] property.
|
||||
The distance to the near culling boundary for this camera relative to its local Z axis, in meters. This maps to glTF's [code]znear[/code] property.
|
||||
</member>
|
||||
<member name="fov" type="float" setter="set_fov" getter="get_fov" default="1.309">
|
||||
The FOV of the camera. This class and GLTF define the camera FOV in radians, while Godot uses degrees. This maps to GLTF's [code]yfov[/code] property. This value is only used for perspective cameras, when [member perspective] is true.
|
||||
The FOV of the camera. This class and glTF define the camera FOV in radians, while Godot uses degrees. This maps to glTF's [code]yfov[/code] property. This value is only used for perspective cameras, when [member perspective] is [code]true[/code].
|
||||
</member>
|
||||
<member name="perspective" type="bool" setter="set_perspective" getter="get_perspective" default="true">
|
||||
Whether or not the camera is in perspective mode. If false, the camera is in orthographic/orthogonal mode. This maps to GLTF's camera [code]type[/code] property. See [member Camera3D.projection] and the GLTF spec for more information.
|
||||
If [code]true[/code], the camera is in perspective mode. Otherwise, the camera is in orthographic/orthogonal mode. This maps to glTF's camera [code]type[/code] property. See [member Camera3D.projection] and the glTF spec for more information.
|
||||
</member>
|
||||
<member name="size_mag" type="float" setter="set_size_mag" getter="get_size_mag" default="0.5">
|
||||
The size of the camera. This class and GLTF define the camera size magnitude as a radius in meters, while Godot defines it as a diameter in meters. This maps to GLTF's [code]ymag[/code] property. This value is only used for orthographic/orthogonal cameras, when [member perspective] is false.
|
||||
The size of the camera. This class and glTF define the camera size magnitude as a radius in meters, while Godot defines it as a diameter in meters. This maps to glTF's [code]ymag[/code] property. This value is only used for orthographic/orthogonal cameras, when [member perspective] is [code]false[/code].
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
GLTFDocument supports reading data from a glTF file, buffer, or Godot scene. This data can then be written to the filesystem, buffer, or used to create a Godot scene.
|
||||
All of the data in a GLTF scene is stored in the [GLTFState] class. GLTFDocument processes state objects, but does not contain any scene data itself. GLTFDocument has member variables to store export configuration settings such as the image format, but is otherwise stateless. Multiple scenes can be processed with the same settings using the same GLTFDocument object and different [GLTFState] objects.
|
||||
All of the data in a glTF scene is stored in the [GLTFState] class. GLTFDocument processes state objects, but does not contain any scene data itself. GLTFDocument has member variables to store export configuration settings such as the image format, but is otherwise stateless. Multiple scenes can be processed with the same settings using the same GLTFDocument object and different [GLTFState] objects.
|
||||
GLTFDocument can be extended with arbitrary functionality by extending the [GLTFDocumentExtension] class and registering it with GLTFDocument via [method register_gltf_document_extension]. This allows for custom data to be imported and exported.
|
||||
</description>
|
||||
<tutorials>
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<param index="2" name="state" type="GLTFState" />
|
||||
<param index="3" name="flags" type="int" default="0" />
|
||||
<description>
|
||||
Takes a [PackedByteArray] defining a GLTF and imports the data to the given [GLTFState] object through the [param state] parameter.
|
||||
Takes a [PackedByteArray] defining a glTF and imports the data to the given [GLTFState] object through the [param state] parameter.
|
||||
[b]Note:[/b] The [param base_path] tells [method append_from_buffer] where to find dependencies and can be empty.
|
||||
</description>
|
||||
</method>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
<param index="2" name="flags" type="int" default="0" />
|
||||
<param index="3" name="base_path" type="String" default="""" />
|
||||
<description>
|
||||
Takes a path to a GLTF file and imports the data at that file path to the given [GLTFState] object through the [param state] parameter.
|
||||
Takes a path to a glTF file and imports the data at that file path to the given [GLTFState] object through the [param state] parameter.
|
||||
[b]Note:[/b] The [param base_path] tells [method append_from_file] where to find dependencies and can be empty.
|
||||
</description>
|
||||
</method>
|
||||
|
|
@ -45,11 +45,21 @@
|
|||
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" />
|
||||
<description>
|
||||
Takes a [GLTFState] object through the [param state] parameter and returns a GLTF [PackedByteArray].
|
||||
Takes a [GLTFState] object through the [param state] parameter and returns a glTF [PackedByteArray].
|
||||
</description>
|
||||
</method>
|
||||
<method name="generate_scene">
|
||||
|
|
@ -63,12 +73,27 @@
|
|||
The [param bake_fps] parameter overrides the bake_fps in [param state].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_supported_gltf_extensions" qualifiers="static">
|
||||
<return type="PackedStringArray" />
|
||||
<description>
|
||||
Returns a list of all support glTF extensions, including extensions supported directly by the engine, and extensions supported by user plugins registering [GLTFDocumentExtension] classes.
|
||||
[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" />
|
||||
<param index="1" name="first_priority" type="bool" default="false" />
|
||||
<description>
|
||||
Registers the given [GLTFDocumentExtension] instance with GLTFDocument. If [param first_priority] is true, this extension will be run first. Otherwise, it will be run last.
|
||||
Registers the given [GLTFDocumentExtension] instance with GLTFDocument. If [param first_priority] is [code]true[/code], this extension will be run first. Otherwise, it will be run last.
|
||||
[b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode].
|
||||
</description>
|
||||
</method>
|
||||
|
|
@ -91,7 +116,7 @@
|
|||
</methods>
|
||||
<members>
|
||||
<member name="image_format" type="String" setter="set_image_format" getter="get_image_format" default=""PNG"">
|
||||
The user-friendly name of the export image format. This is used when exporting the GLTF file, including writing to a file and writing to a byte array.
|
||||
The user-friendly name of the export image format. This is used when exporting the glTF file, including writing to a file and writing to a byte array.
|
||||
By default, Godot allows the following options: "None", "PNG", "JPEG", "Lossless WebP", and "Lossy WebP". Support for more image formats can be added in [GLTFDocumentExtension] classes.
|
||||
</member>
|
||||
<member name="lossy_quality" type="float" setter="set_lossy_quality" getter="get_lossy_quality" default="0.75">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
[GLTFDocument] extension class.
|
||||
</brief_description>
|
||||
<description>
|
||||
Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of GLTF import or export.
|
||||
Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of glTF import or export.
|
||||
To use, make a new class extending GLTFDocumentExtension, override any methods you need, make an instance of your class, and register it using [method GLTFDocument.register_gltf_document_extension].
|
||||
[b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode].
|
||||
</description>
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<param index="1" name="gltf_node" type="GLTFNode" />
|
||||
<param index="2" name="scene_node" type="Node" />
|
||||
<description>
|
||||
Part of the export process. This method is run after [method _export_preflight] and before [method _export_preserialize].
|
||||
Part of the export process. This method is run after [method _export_preflight] and before [method _export_post_convert].
|
||||
Runs when converting the data from a Godot scene node. This method can be used to process the Godot scene node data into a format that can be used by [method _export_node].
|
||||
</description>
|
||||
</method>
|
||||
|
|
@ -30,7 +30,21 @@
|
|||
<param index="3" name="node" type="Node" />
|
||||
<description>
|
||||
Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _export_post]. If this [GLTFDocumentExtension] is used for exporting images, this runs after [method _serialize_texture_json].
|
||||
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.
|
||||
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 [Node] is also provided if available. [param node] may be [code]null[/code] 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 [code]null[/code] 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">
|
||||
|
|
@ -38,7 +52,16 @@
|
|||
<param index="0" name="state" type="GLTFState" />
|
||||
<description>
|
||||
Part of the export process. This method is run last, after all other parts of the export process.
|
||||
This method can be used to modify the final JSON of the generated GLTF file.
|
||||
This method can be used to modify the final JSON of the generated glTF file.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_post_convert" qualifiers="virtual">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<param index="1" name="root" type="Node" />
|
||||
<description>
|
||||
Part of the export process. This method is run after [method _convert_scene_node] and before [method _export_preserialize].
|
||||
This method can be used to modify the converted node data structures before serialization with any additional data from the scene tree.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_preflight" qualifiers="virtual">
|
||||
|
|
@ -47,14 +70,14 @@
|
|||
<param index="1" name="root" type="Node" />
|
||||
<description>
|
||||
Part of the export process. This method is run first, before all other parts of the export process.
|
||||
The return value is used to determine if this [GLTFDocumentExtension] instance should be used for exporting a given GLTF file. If [constant OK], the export will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned.
|
||||
The return value is used to determine if this [GLTFDocumentExtension] instance should be used for exporting a given glTF file. If [constant OK], the export will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_preserialize" qualifiers="virtual">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<description>
|
||||
Part of the export process. This method is run after [method _convert_scene_node] and before [method _get_saveable_image_formats].
|
||||
Part of the export process. This method is run after [method _export_post_convert] and before [method _get_saveable_image_formats].
|
||||
This method can be used to alter the state before performing serialization. It runs every time when generating a buffer with [method GLTFDocument.generate_buffer] or writing to the file system with [method GLTFDocument.write_to_filesystem].
|
||||
</description>
|
||||
</method>
|
||||
|
|
@ -64,9 +87,9 @@
|
|||
<param index="1" name="gltf_node" type="GLTFNode" />
|
||||
<param index="2" name="scene_parent" type="Node" />
|
||||
<description>
|
||||
Part of the import process. This method is run after [method _import_post_parse] and before [method _import_node].
|
||||
Part of the import process. This method is run after [method _import_pre_generate] and before [method _import_node].
|
||||
Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node.
|
||||
[b]Note:[/b] The [param scene_parent] parameter may be null if this is the single root node.
|
||||
[b]Note:[/b] The [param scene_parent] parameter may be [code]null[/code] if this is the single root node.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_image_file_extension" qualifiers="virtual">
|
||||
|
|
@ -86,7 +109,7 @@
|
|||
<return type="PackedStringArray" />
|
||||
<description>
|
||||
Part of the import process. This method is run after [method _import_preflight] and before [method _parse_node_extensions].
|
||||
Returns an array of the GLTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a GLTF file with required extensions can be loaded.
|
||||
Returns an array of the glTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a glTF file with required extensions can be loaded.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_import_node" qualifiers="virtual">
|
||||
|
|
@ -100,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 [code]null[/code] 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" />
|
||||
|
|
@ -113,8 +147,16 @@
|
|||
<return type="int" enum="Error" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<description>
|
||||
Part of the import process. This method is run after [method _parse_node_extensions] and before [method _generate_scene_node].
|
||||
This method can be used to modify any of the data imported so far after parsing, before generating the nodes and then running the final per-node import step.
|
||||
Part of the import process. This method is run after [method _parse_node_extensions] and before [method _import_pre_generate].
|
||||
This method can be used to modify any of the data imported so far after parsing each node, but before generating the scene or any of its nodes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_import_pre_generate" qualifiers="virtual">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="state" type="GLTFState" />
|
||||
<description>
|
||||
Part of the import process. This method is run after [method _import_post_parse] and before [method _generate_scene_node].
|
||||
This method can be used to modify or read from any of the processed data structures, before generating the nodes and then running the final per-node import step.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_import_preflight" qualifiers="virtual">
|
||||
|
|
@ -123,7 +165,7 @@
|
|||
<param index="1" name="extensions" type="PackedStringArray" />
|
||||
<description>
|
||||
Part of the import process. This method is run first, before all other parts of the import process.
|
||||
The return value is used to determine if this [GLTFDocumentExtension] instance should be used for importing a given GLTF file. If [constant OK], the import will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned.
|
||||
The return value is used to determine if this [GLTFDocumentExtension] instance should be used for importing a given glTF file. If [constant OK], the import will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_parse_image_data" qualifiers="virtual">
|
||||
|
|
@ -134,7 +176,7 @@
|
|||
<param index="3" name="ret_image" type="Image" />
|
||||
<description>
|
||||
Part of the import process. This method is run after [method _parse_node_extensions] and before [method _parse_texture_json].
|
||||
Runs when parsing image data from a GLTF file. The data could be sourced from a separate file, a URI, or a buffer, and then is passed as a byte array.
|
||||
Runs when parsing image data from a glTF file. The data could be sourced from a separate file, a URI, or a buffer, and then is passed as a byte array.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_parse_node_extensions" qualifiers="virtual">
|
||||
|
|
@ -154,7 +196,7 @@
|
|||
<param index="2" name="ret_gltf_texture" type="GLTFTexture" />
|
||||
<description>
|
||||
Part of the import process. This method is run after [method _parse_image_data] and before [method _generate_scene_node].
|
||||
Runs when parsing the texture JSON from the GLTF textures array. This can be used to set the source image index to use as the texture.
|
||||
Runs when parsing the texture JSON from the glTF textures array. This can be used to set the source image index to use as the texture.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_save_image_at_path" qualifiers="virtual">
|
||||
|
|
@ -166,7 +208,7 @@
|
|||
<param index="4" name="lossy_quality" type="float" />
|
||||
<description>
|
||||
Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _serialize_texture_json].
|
||||
This method is run when saving images separately from the GLTF file. When images are embedded, [method _serialize_image_to_bytes] runs instead. Note that these methods only run when this [GLTFDocumentExtension] is selected as the image exporter.
|
||||
This method is run when saving images separately from the glTF file. When images are embedded, [method _serialize_image_to_bytes] runs instead. Note that these methods only run when this [GLTFDocumentExtension] is selected as the image exporter.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_serialize_image_to_bytes" qualifiers="virtual">
|
||||
|
|
@ -178,7 +220,7 @@
|
|||
<param index="4" name="lossy_quality" type="float" />
|
||||
<description>
|
||||
Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _serialize_texture_json].
|
||||
This method is run when embedding images in the GLTF file. When images are saved separately, [method _save_image_at_path] runs instead. Note that these methods only run when this [GLTFDocumentExtension] is selected as the image exporter.
|
||||
This method is run when embedding images in the glTF file. When images are saved separately, [method _save_image_at_path] runs instead. Note that these methods only run when this [GLTFDocumentExtension] is selected as the image exporter.
|
||||
This method must set the image MIME type in the [param image_dict] with the [code]"mimeType"[/code] key. For example, for a PNG image, it would be set to [code]"image/png"[/code]. The return value must be a [PackedByteArray] containing the image data.
|
||||
</description>
|
||||
</method>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFLight" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents a GLTF light.
|
||||
Represents a glTF light.
|
||||
</brief_description>
|
||||
<description>
|
||||
Represents a light as defined by the [code]KHR_lights_punctual[/code] GLTF extension.
|
||||
Represents a light as defined by the [code]KHR_lights_punctual[/code] glTF extension.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
<link title="KHR_lights_punctual GLTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual</link>
|
||||
<link title="KHR_lights_punctual glTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="from_dictionary" qualifiers="static">
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
At this angle, the light drops off to zero brightness. Between the inner and outer cone angles, there is a transition from full brightness to zero brightness. If this angle is a half turn, then the spotlight emits in all directions. When creating a Godot [SpotLight3D], the outer cone angle is used as the angle of the spotlight.
|
||||
</member>
|
||||
<member name="range" type="float" setter="set_range" getter="get_range" default="inf">
|
||||
The range of the light, beyond which the light has no effect. GLTF lights with no range defined behave like physical lights (which have infinite range). When creating a Godot light, the range is clamped to 4096.
|
||||
The range of the light, beyond which the light has no effect. glTF lights with no range defined behave like physical lights (which have infinite range). When creating a Godot light, the range is clamped to 4096.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFMesh" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
GLTFMesh represents a GLTF mesh.
|
||||
GLTFMesh represents a glTF mesh.
|
||||
</brief_description>
|
||||
<description>
|
||||
GLTFMesh handles 3D mesh data imported from GLTF files. It includes properties for blend channels, blend weights, instance materials, and the mesh itself.
|
||||
GLTFMesh handles 3D mesh data imported from glTF files. It includes properties for blend channels, blend weights, instance materials, and the mesh itself.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
<param index="0" name="extension_name" type="StringName" />
|
||||
<description>
|
||||
Gets additional arbitrary data in this [GLTFMesh] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
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.
|
||||
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 [code]null[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_additional_data">
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<param index="1" name="additional_data" type="Variant" />
|
||||
<description>
|
||||
Sets additional arbitrary data in this [GLTFMesh] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the second argument can be anything you want.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFNode" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
GLTF node class.
|
||||
glTF node class.
|
||||
</brief_description>
|
||||
<description>
|
||||
Represents a GLTF node. GLTF nodes may have names, transforms, children (other GLTF nodes), and more specialized properties (represented by their own classes).
|
||||
GLTF nodes generally exist inside of [GLTFState] which represents all data of a GLTF file. Most of GLTFNode's properties are indices of other data in the GLTF file. You can extend a GLTF node with additional properties by using [method get_additional_data] and [method set_additional_data].
|
||||
Represents a glTF node. glTF nodes may have names, transforms, children (other glTF nodes), and more specialized properties (represented by their own classes).
|
||||
glTF nodes generally exist inside of [GLTFState] which represents all data of a glTF file. Most of GLTFNode's properties are indices of other data in the glTF file. You can extend a glTF node with additional properties by using [method get_additional_data] and [method set_additional_data].
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
<link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
|
||||
<link title="glTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="append_child_index">
|
||||
<return type="void" />
|
||||
<param index="0" name="child_index" type="int" />
|
||||
<description>
|
||||
Appends the given child node index to the [member children] array.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_additional_data">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="extension_name" type="StringName" />
|
||||
<description>
|
||||
Gets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
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.
|
||||
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 [code]null[/code].
|
||||
</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 [code]true[/code], 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 [code]false[/code] will become [code]^"A/B/C/Skeleton3D:Bone3"[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_additional_data">
|
||||
|
|
@ -26,25 +42,25 @@
|
|||
<param index="1" name="additional_data" type="Variant" />
|
||||
<description>
|
||||
Sets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the second argument can be anything you want.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
|
||||
If this GLTF node is a camera, the index of the [GLTFCamera] in the [GLTFState] that describes the camera's properties. If -1, this node is not a camera.
|
||||
If this glTF node is a camera, the index of the [GLTFCamera] in the [GLTFState] that describes the camera's properties. If -1, this node is not a camera.
|
||||
</member>
|
||||
<member name="children" type="PackedInt32Array" setter="set_children" getter="get_children" default="PackedInt32Array()">
|
||||
The indices of the child nodes in the [GLTFState]. If this GLTF node has no children, this will be an empty array.
|
||||
The indices of the child nodes in the [GLTFState]. If this glTF node has no children, this will be an empty array.
|
||||
</member>
|
||||
<member name="height" type="int" setter="set_height" getter="get_height" default="-1">
|
||||
How deep into the node hierarchy this node is. A root node will have a height of 0, its children will have a height of 1, and so on. If -1, the height has not been calculated.
|
||||
</member>
|
||||
<member name="light" type="int" setter="set_light" getter="get_light" default="-1">
|
||||
If this GLTF node is a light, the index of the [GLTFLight] in the [GLTFState] that describes the light's properties. If -1, this node is not a light.
|
||||
If this glTF node is a light, the index of the [GLTFLight] in the [GLTFState] that describes the light's properties. If -1, this node is not a light.
|
||||
</member>
|
||||
<member name="mesh" type="int" setter="set_mesh" getter="get_mesh" default="-1">
|
||||
If this GLTF node is a mesh, the index of the [GLTFMesh] in the [GLTFState] that describes the mesh's properties. If -1, this node is not a mesh.
|
||||
If this glTF node is a mesh, the index of the [GLTFMesh] in the [GLTFState] that describes the mesh's properties. If -1, this node is not a mesh.
|
||||
</member>
|
||||
<member name="original_name" type="String" setter="set_original_name" getter="get_original_name" default="""">
|
||||
The original name of the node.
|
||||
|
|
@ -53,22 +69,22 @@
|
|||
The index of the parent node in the [GLTFState]. If -1, this node is a root node.
|
||||
</member>
|
||||
<member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)">
|
||||
The position of the GLTF node relative to its parent.
|
||||
The position of the glTF node relative to its parent.
|
||||
</member>
|
||||
<member name="rotation" type="Quaternion" setter="set_rotation" getter="get_rotation" default="Quaternion(0, 0, 0, 1)">
|
||||
The rotation of the GLTF node relative to its parent.
|
||||
The rotation of the glTF node relative to its parent.
|
||||
</member>
|
||||
<member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)">
|
||||
The scale of the GLTF node relative to its parent.
|
||||
The scale of the glTF node relative to its parent.
|
||||
</member>
|
||||
<member name="skeleton" type="int" setter="set_skeleton" getter="get_skeleton" default="-1">
|
||||
If this GLTF node has a skeleton, the index of the [GLTFSkeleton] in the [GLTFState] that describes the skeleton's properties. If -1, this node does not have a skeleton.
|
||||
If this glTF node has a skeleton, the index of the [GLTFSkeleton] in the [GLTFState] that describes the skeleton's properties. If -1, this node does not have a skeleton.
|
||||
</member>
|
||||
<member name="skin" type="int" setter="set_skin" getter="get_skin" default="-1">
|
||||
If this GLTF node has a skin, the index of the [GLTFSkin] in the [GLTFState] that describes the skin's properties. If -1, this node does not have a skin.
|
||||
If this glTF node has a skin, the index of the [GLTFSkin] in the [GLTFState] that describes the skin's properties. If -1, this node does not have a skin.
|
||||
</member>
|
||||
<member name="xform" type="Transform3D" setter="set_xform" getter="get_xform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
|
||||
The transform of the GLTF node relative to its parent. This property is usually unused since the position, rotation, and scale properties are preferred.
|
||||
The transform of the glTF node relative to its parent. This property is usually unused since the position, rotation, and scale properties are preferred.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
|
|||
114
engine/modules/gltf/doc_classes/GLTFObjectModelProperty.xml
Normal file
114
engine/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 [code]0[/code] is [code]false[/code], and any other value is [code]true[/code].
|
||||
</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>
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFPhysicsBody" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents a GLTF physics body.
|
||||
Represents a glTF physics body.
|
||||
</brief_description>
|
||||
<description>
|
||||
Represents a physics body as an intermediary between the [code]OMI_physics_body[/code] GLTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different GLTF physics extensions in the future.
|
||||
Represents a physics body as an intermediary between the [code]OMI_physics_body[/code] glTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different glTF physics extensions in the future.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
<link title="OMI_physics_body GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_physics_body</link>
|
||||
<link title="OMI_physics_body glTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_physics_body</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="from_dictionary" qualifiers="static">
|
||||
<return type="GLTFPhysicsBody" />
|
||||
<param index="0" name="dictionary" type="Dictionary" />
|
||||
<description>
|
||||
Creates a new GLTFPhysicsBody instance by parsing the given [Dictionary] in the [code]OMI_physics_body[/code] GLTF extension format.
|
||||
Creates a new GLTFPhysicsBody instance by parsing the given [Dictionary] in the [code]OMI_physics_body[/code] glTF extension format.
|
||||
</description>
|
||||
</method>
|
||||
<method name="from_node" qualifiers="static">
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<method name="to_dictionary" qualifiers="const">
|
||||
<return type="Dictionary" />
|
||||
<description>
|
||||
Serializes this GLTFPhysicsBody instance into a [Dictionary]. It will be in the format expected by the [code]OMI_physics_body[/code] GLTF extension.
|
||||
Serializes this GLTFPhysicsBody instance into a [Dictionary]. It will be in the format expected by the [code]OMI_physics_body[/code] glTF extension.
|
||||
</description>
|
||||
</method>
|
||||
<method name="to_node" qualifiers="const">
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFPhysicsShape" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents a GLTF physics shape.
|
||||
Represents a glTF physics shape.
|
||||
</brief_description>
|
||||
<description>
|
||||
Represents a physics shape as defined by the [code]OMI_physics_shape[/code] or [code]OMI_collider[/code] GLTF extensions. This class is an intermediary between the GLTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different GLTF physics extensions in the future.
|
||||
Represents a physics shape as defined by the [code]OMI_physics_shape[/code] or [code]OMI_collider[/code] glTF extensions. This class is an intermediary between the glTF data and Godot's nodes, and it's abstracted in a way that allows adding support for different glTF physics extensions in the future.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
<link title="OMI_physics_shape GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_physics_shape</link>
|
||||
<link title="OMI_collider GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/Archived/OMI_collider</link>
|
||||
<link title="OMI_physics_shape glTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_physics_shape</link>
|
||||
<link title="OMI_collider glTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/Archived/OMI_collider</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="from_dictionary" qualifiers="static">
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
This is the only variable not used in the [method to_node] method, it's intended to be used alongside when deciding where to add the generated node as a child.
|
||||
</member>
|
||||
<member name="mesh_index" type="int" setter="set_mesh_index" getter="get_mesh_index" default="-1">
|
||||
The index of the shape's mesh in the GLTF file. This is only used when the shape type is "hull" (convex hull) or "trimesh" (concave trimesh).
|
||||
The index of the shape's mesh in the glTF file. This is only used when the shape type is "hull" (convex hull) or "trimesh" (concave trimesh).
|
||||
</member>
|
||||
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
|
||||
The radius of the shape, in meters. This is only used when the shape type is "capsule", "cylinder", or "sphere". This value should not be negative.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<method name="get_godot_bone_node">
|
||||
<return type="Dictionary" />
|
||||
<description>
|
||||
Returns a [Dictionary] that maps skeleton bone indices to the indices of GLTF nodes. This property is unused during import, and only set during export. In a GLTF file, a bone is a node, so Godot converts skeleton bones to GLTF nodes.
|
||||
Returns a [Dictionary] that maps skeleton bone indices to the indices of glTF nodes. This property is unused during import, and only set during export. In a glTF file, a bone is a node, so Godot converts skeleton bones to glTF nodes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_godot_skeleton">
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<return type="void" />
|
||||
<param index="0" name="godot_bone_node" type="Dictionary" />
|
||||
<description>
|
||||
Sets a [Dictionary] that maps skeleton bone indices to the indices of GLTF nodes. This property is unused during import, and only set during export. In a GLTF file, a bone is a node, so Godot converts skeleton bones to GLTF nodes.
|
||||
Sets a [Dictionary] that maps skeleton bone indices to the indices of glTF nodes. This property is unused during import, and only set during export. In a glTF file, a bone is a node, so Godot converts skeleton bones to glTF nodes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_unique_names">
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFSpecGloss" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Archived GLTF extension for specular/glossy materials.
|
||||
Archived glTF extension for specular/glossy materials.
|
||||
</brief_description>
|
||||
<description>
|
||||
KHR_materials_pbrSpecularGlossiness is an archived GLTF extension. This means that it is deprecated and not recommended for new files. However, it is still supported for loading old files.
|
||||
KHR_materials_pbrSpecularGlossiness is an archived glTF extension. This means that it is deprecated and not recommended for new files. However, it is still supported for loading old files.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
<link title="KHR_materials_pbrSpecularGlossiness GLTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness</link>
|
||||
<link title="KHR_materials_pbrSpecularGlossiness glTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness</link>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="diffuse_factor" type="Color" setter="set_diffuse_factor" getter="get_diffuse_factor" default="Color(1, 1, 1, 1)">
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFState" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents all data of a GLTF file.
|
||||
Represents all data of a glTF file.
|
||||
</brief_description>
|
||||
<description>
|
||||
Contains all nodes and resources of a GLTF file. This is used by [GLTFDocument] as data storage, which allows [GLTFDocument] and all [GLTFDocumentExtension] classes to remain stateless.
|
||||
GLTFState can be populated by [GLTFDocument] reading a file or by converting a Godot scene. Then the data can either be used to create a Godot scene or save to a GLTF file. The code that converts to/from a Godot scene can be intercepted at arbitrary points by [GLTFDocumentExtension] classes. This allows for custom data to be stored in the GLTF file or for custom data to be converted to/from Godot nodes.
|
||||
Contains all nodes and resources of a glTF file. This is used by [GLTFDocument] as data storage, which allows [GLTFDocument] and all [GLTFDocumentExtension] classes to remain stateless.
|
||||
GLTFState can be populated by [GLTFDocument] reading a file or by converting a Godot scene. Then the data can either be used to create a Godot scene or save to a glTF file. The code that converts to/from a Godot scene can be intercepted at arbitrary points by [GLTFDocumentExtension] classes. This allows for custom data to be stored in the glTF file or for custom data to be converted to/from Godot nodes.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
<link title="GLTF asset header schema">https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/asset.schema.json"</link>
|
||||
<link title="glTF asset header schema">https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/asset.schema.json</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_used_extension">
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
<param index="0" name="extension_name" type="String" />
|
||||
<param index="1" name="required" type="bool" />
|
||||
<description>
|
||||
Appends an extension to the list of extensions used by this GLTF file during serialization. If [param required] is true, the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically.
|
||||
Appends an extension to the list of extensions used by this glTF file during serialization. If [param required] is [code]true[/code], the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically.
|
||||
</description>
|
||||
</method>
|
||||
<method name="append_data_to_buffers">
|
||||
|
|
@ -25,7 +25,18 @@
|
|||
<param index="0" name="data" type="PackedByteArray" />
|
||||
<param index="1" name="deduplication" type="bool" />
|
||||
<description>
|
||||
Appends the given byte array data to the buffers and creates a [GLTFBufferView] for it. The index of the destination [GLTFBufferView] is returned. If [param deduplication] is true, the buffers will first be searched for duplicate data, otherwise new bytes will always be appended.
|
||||
Appends the given byte array data to the buffers and creates a [GLTFBufferView] for it. The index of the destination [GLTFBufferView] is returned. If [param deduplication] is [code]true[/code], the buffers will first be searched for duplicate data, otherwise new bytes will always be appended.
|
||||
</description>
|
||||
</method>
|
||||
<method name="append_gltf_node">
|
||||
<return type="int" />
|
||||
<param index="0" name="gltf_node" type="GLTFNode" />
|
||||
<param index="1" name="godot_scene_node" type="Node" />
|
||||
<param index="2" name="parent_node_index" type="int" />
|
||||
<description>
|
||||
Append the given [GLTFNode] to the state, and return its new index. This can be used to export one Godot node as multiple glTF nodes, or inject new glTF nodes at import time. On import, this must be called before [method GLTFDocumentExtension._generate_scene_node] finishes for the parent node. On export, this must be called before [method GLTFDocumentExtension._export_node] runs for the parent node.
|
||||
The [param godot_scene_node] parameter is the Godot scene node that corresponds to this glTF node. This is highly recommended to be set to a valid node, but may be [code]null[/code] if there is no corresponding Godot scene node. One Godot scene node may be used for multiple glTF nodes, so if exporting multiple glTF nodes for one Godot scene node, use the same Godot scene node for each.
|
||||
The [param parent_node_index] parameter is the index of the parent [GLTFNode] in the state. If [code]-1[/code], the node will be a root node, otherwise the new node will be added to the parent's list of children. The index will also be written to the [member GLTFNode.parent] property of the new node.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_accessors">
|
||||
|
|
@ -38,27 +49,27 @@
|
|||
<param index="0" name="extension_name" type="StringName" />
|
||||
<description>
|
||||
Gets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
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.
|
||||
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 [code]null[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_animation_player">
|
||||
<return type="AnimationPlayer" />
|
||||
<param index="0" name="idx" type="int" />
|
||||
<description>
|
||||
Returns the [AnimationPlayer] node with the given index. These nodes are only used during the export process when converting Godot [AnimationPlayer] nodes to GLTF animations.
|
||||
Returns the [AnimationPlayer] node with the given index. These nodes are only used during the export process when converting Godot [AnimationPlayer] nodes to glTF animations.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_animation_players_count">
|
||||
<return type="int" />
|
||||
<param index="0" name="idx" type="int" />
|
||||
<description>
|
||||
Returns the number of [AnimationPlayer] nodes in this [GLTFState]. These nodes are only used during the export process when converting Godot [AnimationPlayer] nodes to GLTF animations.
|
||||
Returns the number of [AnimationPlayer] nodes in this [GLTFState]. These nodes are only used during the export process when converting Godot [AnimationPlayer] nodes to glTF animations.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_animations">
|
||||
<return type="GLTFAnimation[]" />
|
||||
<description>
|
||||
Returns an array of all [GLTFAnimation]s in the GLTF file. When importing, these will be generated as animations in an [AnimationPlayer] node. When exporting, these will be generated from Godot [AnimationPlayer] nodes.
|
||||
Returns an array of all [GLTFAnimation]s in the glTF file. When importing, these will be generated as animations in an [AnimationPlayer] node. When exporting, these will be generated from Godot [AnimationPlayer] nodes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_buffer_views">
|
||||
|
|
@ -69,7 +80,7 @@
|
|||
<method name="get_cameras">
|
||||
<return type="GLTFCamera[]" />
|
||||
<description>
|
||||
Returns an array of all [GLTFCamera]s in the GLTF file. These are the cameras that the [member GLTFNode.camera] index refers to.
|
||||
Returns an array of all [GLTFCamera]s in the glTF file. These are the cameras that the [member GLTFNode.camera] index refers to.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_handle_binary_image">
|
||||
|
|
@ -80,13 +91,13 @@
|
|||
<method name="get_images">
|
||||
<return type="Texture2D[]" />
|
||||
<description>
|
||||
Gets the images of the GLTF file as an array of [Texture2D]s. These are the images that the [member GLTFTexture.src_image] index refers to.
|
||||
Gets the images of the glTF file as an array of [Texture2D]s. These are the images that the [member GLTFTexture.src_image] index refers to.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_lights">
|
||||
<return type="GLTFLight[]" />
|
||||
<description>
|
||||
Returns an array of all [GLTFLight]s in the GLTF file. These are the lights that the [member GLTFNode.light] index refers to.
|
||||
Returns an array of all [GLTFLight]s in the glTF file. These are the lights that the [member GLTFNode.light] index refers to.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_materials">
|
||||
|
|
@ -97,7 +108,7 @@
|
|||
<method name="get_meshes">
|
||||
<return type="GLTFMesh[]" />
|
||||
<description>
|
||||
Returns an array of all [GLTFMesh]es in the GLTF file. These are the meshes that the [member GLTFNode.mesh] index refers to.
|
||||
Returns an array of all [GLTFMesh]es in the glTF file. These are the meshes that the [member GLTFNode.mesh] index refers to.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_node_index">
|
||||
|
|
@ -111,7 +122,7 @@
|
|||
<method name="get_nodes">
|
||||
<return type="GLTFNode[]" />
|
||||
<description>
|
||||
Returns an array of all [GLTFNode]s in the GLTF file. These are the nodes that [member GLTFNode.children] and [member root_nodes] refer to. This includes nodes that may not be generated in the Godot scene, or nodes that may generate multiple Godot scene nodes.
|
||||
Returns an array of all [GLTFNode]s in the glTF file. These are the nodes that [member GLTFNode.children] and [member root_nodes] refer to. This includes nodes that may not be generated in the Godot scene, or nodes that may generate multiple Godot scene nodes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_scene_node">
|
||||
|
|
@ -125,19 +136,19 @@
|
|||
<method name="get_skeletons">
|
||||
<return type="GLTFSkeleton[]" />
|
||||
<description>
|
||||
Returns an array of all [GLTFSkeleton]s in the GLTF file. These are the skeletons that the [member GLTFNode.skeleton] index refers to.
|
||||
Returns an array of all [GLTFSkeleton]s in the glTF file. These are the skeletons that the [member GLTFNode.skeleton] index refers to.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_skins">
|
||||
<return type="GLTFSkin[]" />
|
||||
<description>
|
||||
Returns an array of all [GLTFSkin]s in the GLTF file. These are the skins that the [member GLTFNode.skin] index refers to.
|
||||
Returns an array of all [GLTFSkin]s in the glTF file. These are the skins that the [member GLTFNode.skin] index refers to.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_texture_samplers">
|
||||
<return type="GLTFTextureSampler[]" />
|
||||
<description>
|
||||
Retrieves the array of texture samplers that are used by the textures contained in the GLTF.
|
||||
Retrieves the array of texture samplers that are used by the textures contained in the glTF.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_textures">
|
||||
|
|
@ -169,7 +180,7 @@
|
|||
<param index="1" name="additional_data" type="Variant" />
|
||||
<description>
|
||||
Sets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
|
||||
The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the second argument can be anything you want.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_animations">
|
||||
|
|
@ -250,7 +261,7 @@
|
|||
<return type="void" />
|
||||
<param index="0" name="texture_samplers" type="GLTFTextureSampler[]" />
|
||||
<description>
|
||||
Sets the array of texture samplers that are used by the textures contained in the GLTF.
|
||||
Sets the array of texture samplers that are used by the textures contained in the glTF.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_textures">
|
||||
|
|
@ -279,23 +290,23 @@
|
|||
The baking fps of the animation for either import or export.
|
||||
</member>
|
||||
<member name="base_path" type="String" setter="set_base_path" getter="get_base_path" default="""">
|
||||
The folder path associated with this GLTF data. This is used to find other files the GLTF file references, like images or binary buffers. This will be set during import when appending from a file, and will be set during export when writing to a file.
|
||||
The folder path associated with this glTF data. This is used to find other files the glTF file references, like images or binary buffers. This will be set during import when appending from a file, and will be set during export when writing to a file.
|
||||
</member>
|
||||
<member name="buffers" type="PackedByteArray[]" setter="set_buffers" getter="get_buffers" default="[]">
|
||||
</member>
|
||||
<member name="copyright" type="String" setter="set_copyright" getter="get_copyright" default="""">
|
||||
The copyright string in the asset header of the GLTF file. This is set during import if present and export if non-empty. See the GLTF asset header documentation for more information.
|
||||
The copyright string in the asset header of the glTF file. This is set during import if present and export if non-empty. See the glTF asset header documentation for more information.
|
||||
</member>
|
||||
<member name="create_animations" type="bool" setter="set_create_animations" getter="get_create_animations" default="true">
|
||||
</member>
|
||||
<member name="filename" type="String" setter="set_filename" getter="get_filename" default="""">
|
||||
The file name associated with this GLTF data. If it ends with [code].gltf[/code], this is text-based GLTF, otherwise this is binary GLB. This will be set during import when appending from a file, and will be set during export when writing to a file. If writing to a buffer, this will be an empty string.
|
||||
The file name associated with this glTF data. If it ends with [code].gltf[/code], this is text-based glTF, otherwise this is binary GLB. This will be set during import when appending from a file, and will be set during export when writing to a file. If writing to a buffer, this will be an empty string.
|
||||
</member>
|
||||
<member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray()">
|
||||
The binary buffer attached to a .glb file.
|
||||
</member>
|
||||
<member name="import_as_skeleton_bones" type="bool" setter="set_import_as_skeleton_bones" getter="get_import_as_skeleton_bones" default="false">
|
||||
True to force all GLTFNodes in the document to be bones of a single Skeleton3D godot node.
|
||||
If [code]true[/code], forces all GLTFNodes in the document to be bones of a single [Skeleton3D] Godot node.
|
||||
</member>
|
||||
<member name="json" type="Dictionary" setter="set_json" getter="get_json" default="{}">
|
||||
The original raw JSON document corresponding to this GLTFState.
|
||||
|
|
@ -305,10 +316,10 @@
|
|||
<member name="minor_version" type="int" setter="set_minor_version" getter="get_minor_version" default="0">
|
||||
</member>
|
||||
<member name="root_nodes" type="PackedInt32Array" setter="set_root_nodes" getter="get_root_nodes" default="PackedInt32Array()">
|
||||
The root nodes of the GLTF file. Typically, a GLTF file will only have one scene, and therefore one root node. However, a GLTF file may have multiple scenes and therefore multiple root nodes, which will be generated as siblings of each other and as children of the root node of the generated Godot scene.
|
||||
The root nodes of the glTF file. Typically, a glTF file will only have one scene, and therefore one root node. However, a glTF file may have multiple scenes and therefore multiple root nodes, which will be generated as siblings of each other and as children of the root node of the generated Godot scene.
|
||||
</member>
|
||||
<member name="scene_name" type="String" setter="set_scene_name" getter="get_scene_name" default="""">
|
||||
The name of the scene. When importing, if not specified, this will be the file name. When exporting, if specified, the scene name will be saved to the GLTF file.
|
||||
The name of the scene. When importing, if not specified, this will be the file name. When exporting, if specified, the scene name will be saved to the glTF file.
|
||||
</member>
|
||||
<member name="use_named_skin_binds" type="bool" setter="set_use_named_skin_binds" getter="get_use_named_skin_binds" default="false">
|
||||
</member>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFTexture" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
GLTFTexture represents a texture in a GLTF file.
|
||||
GLTFTexture represents a texture in a glTF file.
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="GLTFTextureSampler" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Represents a GLTF texture sampler
|
||||
Represents a glTF texture sampler
|
||||
</brief_description>
|
||||
<description>
|
||||
Represents a texture sampler as defined by the base GLTF spec. Texture samplers in GLTF specify how to sample data from the texture's base image, when rendering the texture on an object.
|
||||
Represents a texture sampler as defined by the base glTF spec. Texture samplers in glTF specify how to sample data from the texture's base image, when rendering the texture on an object.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
#include "editor/import/3d/scene_import_settings.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
|
||||
String SceneExporterGLTFPlugin::get_name() const {
|
||||
String SceneExporterGLTFPlugin::get_plugin_name() const {
|
||||
return "ConvertGLTF2";
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ void SceneExporterGLTFPlugin::_popup_gltf_export_dialog() {
|
|||
}
|
||||
_file_dialog->set_current_file(filename + String(".gltf"));
|
||||
// Generate and refresh the export settings.
|
||||
_export_settings->generate_property_list(_gltf_document);
|
||||
_export_settings->generate_property_list(_gltf_document, root);
|
||||
_settings_inspector->edit(nullptr);
|
||||
_settings_inspector->edit(_export_settings.ptr());
|
||||
// Show the file dialog.
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class SceneExporterGLTFPlugin : public EditorPlugin {
|
|||
void _export_scene_as_gltf(const String &p_file_path);
|
||||
|
||||
public:
|
||||
virtual String get_name() const override;
|
||||
virtual String get_plugin_name() const override;
|
||||
bool has_main_screen() const override;
|
||||
SceneExporterGLTFPlugin();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ const uint32_t PROP_EDITOR_SCRIPT_VAR = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_S
|
|||
|
||||
bool EditorSceneExporterGLTFSettings::_set(const StringName &p_name, const Variant &p_value) {
|
||||
String name_str = String(p_name);
|
||||
if (name_str.contains("/")) {
|
||||
if (name_str.contains_char('/')) {
|
||||
return _set_extension_setting(name_str, p_value);
|
||||
}
|
||||
if (p_name == StringName("image_format")) {
|
||||
|
|
@ -55,7 +55,7 @@ bool EditorSceneExporterGLTFSettings::_set(const StringName &p_name, const Varia
|
|||
|
||||
bool EditorSceneExporterGLTFSettings::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
String name_str = String(p_name);
|
||||
if (name_str.contains("/")) {
|
||||
if (name_str.contains_char('/')) {
|
||||
return _get_extension_setting(name_str, r_ret);
|
||||
}
|
||||
if (p_name == StringName("image_format")) {
|
||||
|
|
@ -129,7 +129,7 @@ String get_friendly_config_prefix(Ref<GLTFDocumentExtension> p_extension) {
|
|||
}
|
||||
|
||||
// Run this before popping up the export settings, because the extensions may have changed.
|
||||
void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p_document) {
|
||||
void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p_document, Node *p_root) {
|
||||
_property_list.clear();
|
||||
_document = p_document;
|
||||
String image_format_hint_string = "None,PNG,JPEG";
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ protected:
|
|||
bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const;
|
||||
|
||||
public:
|
||||
void generate_property_list(Ref<GLTFDocument> p_document);
|
||||
void generate_property_list(Ref<GLTFDocument> p_document, Node *p_root = nullptr);
|
||||
|
||||
String get_copyright() const;
|
||||
void set_copyright(const String &p_copyright);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino
|
|||
}
|
||||
pipe = pipe.substr(bl);
|
||||
pipe = pipe.replace_first("Blender ", "");
|
||||
int pp = pipe.find(".");
|
||||
int pp = pipe.find_char('.');
|
||||
if (pp == -1) {
|
||||
if (r_err) {
|
||||
*r_err = vformat(TTR("Couldn't extract version information from Blender executable at: %s."), p_path);
|
||||
|
|
@ -96,16 +96,12 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino
|
|||
return false;
|
||||
}
|
||||
|
||||
int pp2 = pipe.find(".", pp + 1);
|
||||
int pp2 = pipe.find_char('.', pp + 1);
|
||||
r_minor = pp2 > pp ? pipe.substr(pp + 1, pp2 - pp - 1).to_int() : 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t EditorSceneFormatImporterBlend::get_import_flags() const {
|
||||
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions) const {
|
||||
r_extensions->push_back("blend");
|
||||
}
|
||||
|
|
@ -115,8 +111,15 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
|||
List<String> *r_missing_deps, Error *r_err) {
|
||||
String blender_path = EDITOR_GET("filesystem/import/blender/blender_path");
|
||||
|
||||
if (blender_major_version == -1 || blender_minor_version == -1) {
|
||||
_get_blender_version(blender_path, blender_major_version, blender_minor_version, nullptr);
|
||||
ERR_FAIL_COND_V_MSG(blender_path.is_empty(), nullptr, "Blender path is empty, check your Editor Settings.");
|
||||
ERR_FAIL_COND_V_MSG(!FileAccess::exists(blender_path), nullptr, vformat("Invalid Blender path: %s, check your Editor Settings.", blender_path));
|
||||
|
||||
if (blender_major_version == -1 || blender_minor_version == -1 || last_tested_blender_path != blender_path) {
|
||||
String error;
|
||||
if (!_get_blender_version(blender_path, blender_major_version, blender_minor_version, &error)) {
|
||||
ERR_FAIL_V_MSG(nullptr, error);
|
||||
}
|
||||
last_tested_blender_path = blender_path;
|
||||
}
|
||||
|
||||
// Get global paths for source and sink.
|
||||
|
|
@ -136,6 +139,10 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
|||
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
|
||||
vformat("%s-%s.gltf", blend_basename, p_path.md5_text()));
|
||||
const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink);
|
||||
// If true, unpack the original images to the Godot file system and use them. Allows changing image import settings like VRAM compression.
|
||||
// If false, allow Blender to convert the original images, such as re-packing roughness and metallic into one roughness+metallic texture.
|
||||
// In most cases this is desired, but if the .blend file's images are not in the correct format, this must be disabled for correct behavior.
|
||||
const bool unpack_original_images = p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")];
|
||||
|
||||
// Handle configuration options.
|
||||
|
||||
|
|
@ -143,7 +150,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
|||
Dictionary parameters_map;
|
||||
|
||||
parameters_map["filepath"] = sink_global;
|
||||
parameters_map["export_keep_originals"] = true;
|
||||
parameters_map["export_keep_originals"] = unpack_original_images;
|
||||
parameters_map["export_format"] = "GLTF_SEPARATE";
|
||||
parameters_map["export_yup"] = true;
|
||||
|
||||
|
|
@ -227,6 +234,18 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
|||
} else {
|
||||
parameters_map["export_normals"] = false;
|
||||
}
|
||||
|
||||
if (blender_major_version > 4 || (blender_major_version == 4 && blender_minor_version >= 1)) {
|
||||
if (p_options.has(SNAME("blender/meshes/export_geometry_nodes_instances")) && p_options[SNAME("blender/meshes/export_geometry_nodes_instances")]) {
|
||||
parameters_map["export_gn_mesh"] = true;
|
||||
if (blender_major_version == 4 && blender_minor_version == 1) {
|
||||
// There is a bug in Blender 4.1 where it can't export lights and geometry nodes at the same time, one must be disabled.
|
||||
parameters_map["export_lights"] = false;
|
||||
}
|
||||
} else {
|
||||
parameters_map["export_gn_mesh"] = false;
|
||||
}
|
||||
}
|
||||
if (p_options.has(SNAME("blender/meshes/tangents")) && p_options[SNAME("blender/meshes/tangents")]) {
|
||||
parameters_map["export_tangents"] = true;
|
||||
} else {
|
||||
|
|
@ -266,12 +285,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
|||
parameters_map["export_apply"] = false;
|
||||
}
|
||||
|
||||
if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) {
|
||||
request_options["unpack_all"] = true;
|
||||
} else {
|
||||
request_options["unpack_all"] = false;
|
||||
}
|
||||
|
||||
request_options["unpack_all"] = unpack_original_images;
|
||||
request_options["path"] = source_global;
|
||||
request_options["gltf_options"] = parameters_map;
|
||||
|
||||
|
|
@ -292,15 +306,13 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
|||
Ref<GLTFState> state;
|
||||
state.instantiate();
|
||||
|
||||
String base_dir;
|
||||
if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) {
|
||||
base_dir = sink.get_base_dir();
|
||||
}
|
||||
if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) {
|
||||
state->set_import_as_skeleton_bones(true);
|
||||
}
|
||||
state->set_scene_name(blend_basename);
|
||||
err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, base_dir);
|
||||
state->set_extract_path(p_path.get_base_dir());
|
||||
state->set_extract_prefix(blend_basename);
|
||||
err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, sink.get_base_dir());
|
||||
if (err != OK) {
|
||||
if (r_err) {
|
||||
*r_err = FAILED;
|
||||
|
|
@ -317,7 +329,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
|
|||
#endif
|
||||
}
|
||||
|
||||
Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
|
||||
Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option,
|
||||
const HashMap<StringName, Variant> &p_options) {
|
||||
if (p_path.get_extension().to_lower() != "blend") {
|
||||
return true;
|
||||
|
|
@ -350,6 +362,7 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li
|
|||
ADD_OPTION_BOOL("blender/meshes/colors", false);
|
||||
ADD_OPTION_BOOL("blender/meshes/uvs", true);
|
||||
ADD_OPTION_BOOL("blender/meshes/normals", true);
|
||||
ADD_OPTION_BOOL("blender/meshes/export_geometry_nodes_instances", false);
|
||||
ADD_OPTION_BOOL("blender/meshes/tangents", true);
|
||||
ADD_OPTION_ENUM("blender/meshes/skins", "None,4 Influences (Compatible),All Influences", BLEND_BONE_INFLUENCES_ALL);
|
||||
ADD_OPTION_BOOL("blender/meshes/export_bones_deforming_mesh_only", false);
|
||||
|
|
@ -483,7 +496,7 @@ void EditorFileSystemImportFormatSupportQueryBlend::_browse_install() {
|
|||
}
|
||||
|
||||
void EditorFileSystemImportFormatSupportQueryBlend::_update_icons() {
|
||||
blender_path_browse->set_icon(blender_path_browse->get_editor_theme_icon(SNAME("FolderBrowse")));
|
||||
blender_path_browse->set_button_icon(blender_path_browse->get_editor_theme_icon(SNAME("FolderBrowse")));
|
||||
}
|
||||
|
||||
bool EditorFileSystemImportFormatSupportQueryBlend::query() {
|
||||
|
|
@ -557,7 +570,6 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() {
|
|||
confirmed = false;
|
||||
|
||||
while (true) {
|
||||
OS::get_singleton()->delay_usec(1);
|
||||
DisplayServer::get_singleton()->process_events();
|
||||
Main::iteration();
|
||||
if (!configure_blender_dialog->is_visible() || confirmed) {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter {
|
|||
|
||||
int blender_major_version = -1;
|
||||
int blender_minor_version = -1;
|
||||
String last_tested_blender_path;
|
||||
|
||||
public:
|
||||
enum {
|
||||
|
|
@ -66,14 +67,13 @@ public:
|
|||
BLEND_MODIFIERS_ALL
|
||||
};
|
||||
|
||||
virtual uint32_t get_import_flags() const override;
|
||||
virtual void get_extensions(List<String> *r_extensions) const override;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags,
|
||||
const HashMap<StringName, Variant> &p_options,
|
||||
List<String> *r_missing_deps, Error *r_err = nullptr) override;
|
||||
virtual void get_import_options(const String &p_path,
|
||||
List<ResourceImporter::ImportOption> *r_options) override;
|
||||
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
|
||||
virtual Variant get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option,
|
||||
const HashMap<StringName, Variant> &p_options) override;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -35,10 +35,6 @@
|
|||
#include "../gltf_defines.h"
|
||||
#include "../gltf_document.h"
|
||||
|
||||
uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const {
|
||||
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
|
||||
}
|
||||
|
||||
void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) const {
|
||||
r_extensions->push_back("gltf");
|
||||
r_extensions->push_back("glb");
|
||||
|
|
@ -62,6 +58,9 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
|
|||
if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) {
|
||||
state->set_import_as_skeleton_bones(true);
|
||||
}
|
||||
if (p_options.has(SNAME("extract_path"))) {
|
||||
state->set_extract_path(p_options["extract_path"]);
|
||||
}
|
||||
state->set_bake_fps(p_options["animation/fps"]);
|
||||
Error err = gltf->append_from_file(p_path, state, p_flags);
|
||||
if (err != OK) {
|
||||
|
|
@ -100,7 +99,7 @@ void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringN
|
|||
}
|
||||
}
|
||||
|
||||
Variant EditorSceneFormatImporterGLTF::get_option_visibility(const String &p_path, bool p_for_animation,
|
||||
Variant EditorSceneFormatImporterGLTF::get_option_visibility(const String &p_path, const String &p_scene_import_type,
|
||||
const String &p_option, const HashMap<StringName, Variant> &p_options) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter {
|
|||
GDCLASS(EditorSceneFormatImporterGLTF, EditorSceneFormatImporter);
|
||||
|
||||
public:
|
||||
virtual uint32_t get_import_flags() const override;
|
||||
virtual void get_extensions(List<String> *r_extensions) const override;
|
||||
virtual Node *import_scene(const String &p_path, uint32_t p_flags,
|
||||
const HashMap<StringName, Variant> &p_options,
|
||||
|
|
@ -50,7 +49,7 @@ public:
|
|||
virtual void get_import_options(const String &p_path,
|
||||
List<ResourceImporter::ImportOption> *r_options) override;
|
||||
virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const override;
|
||||
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation,
|
||||
virtual Variant get_option_visibility(const String &p_path, const String &p_scene_import_type,
|
||||
const String &p_option, const HashMap<StringName, Variant> &p_options) override;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
|
|
|||
|
|
@ -38,14 +38,18 @@ 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(_generate_scene_node, "state", "gltf_node", "scene_parent");
|
||||
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");
|
||||
GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node");
|
||||
GDVIRTUAL_BIND(_import_post, "state", "root");
|
||||
// Export process.
|
||||
GDVIRTUAL_BIND(_export_preflight, "state", "root");
|
||||
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");
|
||||
|
|
@ -56,7 +60,7 @@ void GLTFDocumentExtension::_bind_methods() {
|
|||
|
||||
// Import process.
|
||||
Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_import_preflight, p_state, p_extensions, err);
|
||||
return err;
|
||||
|
|
@ -69,16 +73,16 @@ Vector<String> GLTFDocumentExtension::get_supported_extensions() {
|
|||
}
|
||||
|
||||
Error GLTFDocumentExtension::parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_gltf_node.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_parse_node_extensions, p_state, p_gltf_node, p_extensions, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> r_image) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(r_image, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(r_image.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_parse_image_data, p_state, p_image_data, p_mime_type, r_image, err);
|
||||
return err;
|
||||
|
|
@ -91,31 +95,45 @@ String GLTFDocumentExtension::get_image_file_extension() {
|
|||
}
|
||||
|
||||
Error GLTFDocumentExtension::parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(r_gltf_texture, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(r_gltf_texture.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_parse_texture_json, p_state, p_texture_json, r_gltf_texture, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
|
||||
ERR_FAIL_NULL_V(p_state, nullptr);
|
||||
ERR_FAIL_NULL_V(p_gltf_node, nullptr);
|
||||
Node3D *ret_node = nullptr;
|
||||
GDVIRTUAL_CALL(_generate_scene_node, p_state, p_gltf_node, p_scene_parent, ret_node);
|
||||
return ret_node;
|
||||
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_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_import_post_parse, p_state, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::import_pre_generate(Ref<GLTFState> p_state) {
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_import_pre_generate, p_state, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
|
||||
ERR_FAIL_COND_V(p_state.is_null(), nullptr);
|
||||
ERR_FAIL_COND_V(p_gltf_node.is_null(), nullptr);
|
||||
Node3D *ret_node = nullptr;
|
||||
GDVIRTUAL_CALL(_generate_scene_node, p_state, p_gltf_node, p_scene_parent, ret_node);
|
||||
return ret_node;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_gltf_node.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err);
|
||||
|
|
@ -124,7 +142,7 @@ Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p
|
|||
|
||||
Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) {
|
||||
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_import_post, p_state, p_root, err);
|
||||
return err;
|
||||
|
|
@ -139,19 +157,36 @@ Error GLTFDocumentExtension::export_preflight(Ref<GLTFState> p_state, Node *p_ro
|
|||
}
|
||||
|
||||
void GLTFDocumentExtension::convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node) {
|
||||
ERR_FAIL_NULL(p_state);
|
||||
ERR_FAIL_NULL(p_gltf_node);
|
||||
ERR_FAIL_COND(p_state.is_null());
|
||||
ERR_FAIL_COND(p_gltf_node.is_null());
|
||||
ERR_FAIL_NULL(p_scene_node);
|
||||
GDVIRTUAL_CALL(_convert_scene_node, p_state, p_gltf_node, p_scene_node);
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::export_post_convert(Ref<GLTFState> p_state, Node *p_root) {
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_export_post_convert, p_state, p_root, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::export_preserialize(Ref<GLTFState> p_state) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_export_preserialize, p_state, err);
|
||||
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);
|
||||
|
|
@ -160,38 +195,38 @@ Vector<String> GLTFDocumentExtension::get_saveable_image_formats() {
|
|||
|
||||
PackedByteArray GLTFDocumentExtension::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) {
|
||||
PackedByteArray ret;
|
||||
ERR_FAIL_NULL_V(p_state, ret);
|
||||
ERR_FAIL_NULL_V(p_image, ret);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ret);
|
||||
ERR_FAIL_COND_V(p_image.is_null(), ret);
|
||||
GDVIRTUAL_CALL(_serialize_image_to_bytes, p_state, p_image, p_image_dict, p_image_format, p_lossy_quality, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::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) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_image, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_image.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error ret = OK;
|
||||
GDVIRTUAL_CALL(_save_image_at_path, p_state, p_image, p_file_path, p_image_format, p_lossy_quality, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::serialize_texture_json(Ref<GLTFState> p_state, Dictionary p_texture_json, Ref<GLTFTexture> p_gltf_texture, const String &p_image_format) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_gltf_texture, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_gltf_texture.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_serialize_texture_json, p_state, p_texture_json, p_gltf_texture, p_image_format, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_gltf_node.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
Error err = OK;
|
||||
GDVIRTUAL_CALL(_export_post, p_state, err);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -49,14 +49,18 @@ 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);
|
||||
virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
|
||||
virtual Error import_post(Ref<GLTFState> p_state, Node *p_node);
|
||||
// Export process.
|
||||
virtual Error export_preflight(Ref<GLTFState> p_state, Node *p_root);
|
||||
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);
|
||||
|
|
@ -71,14 +75,18 @@ 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(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
|
||||
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 *);
|
||||
GDVIRTUAL4R(Error, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
|
||||
GDVIRTUAL2R(Error, _import_post, Ref<GLTFState>, Node *);
|
||||
// Export process.
|
||||
GDVIRTUAL2R(Error, _export_preflight, Ref<GLTFState>, Node *);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -34,9 +34,6 @@
|
|||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/resources/3d/importer_mesh.h"
|
||||
|
||||
void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() {
|
||||
}
|
||||
|
||||
void GLTFDocumentExtensionConvertImporterMesh::_copy_meta(Object *p_src_object, Object *p_dst_object) {
|
||||
List<StringName> meta_list;
|
||||
p_src_object->get_meta_list(&meta_list);
|
||||
|
|
@ -46,34 +43,42 @@ void GLTFDocumentExtensionConvertImporterMesh::_copy_meta(Object *p_src_object,
|
|||
}
|
||||
}
|
||||
|
||||
MeshInstance3D *GLTFDocumentExtensionConvertImporterMesh::convert_importer_mesh_instance_3d(ImporterMeshInstance3D *p_importer_mesh_instance_3d) {
|
||||
// Convert the node itself first.
|
||||
MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D);
|
||||
ERR_FAIL_NULL_V(p_importer_mesh_instance_3d, mesh_instance_node_3d);
|
||||
mesh_instance_node_3d->set_name(p_importer_mesh_instance_3d->get_name());
|
||||
mesh_instance_node_3d->set_transform(p_importer_mesh_instance_3d->get_transform());
|
||||
mesh_instance_node_3d->set_skin(p_importer_mesh_instance_3d->get_skin());
|
||||
mesh_instance_node_3d->set_skeleton_path(p_importer_mesh_instance_3d->get_skeleton_path());
|
||||
mesh_instance_node_3d->set_visible(p_importer_mesh_instance_3d->is_visible());
|
||||
p_importer_mesh_instance_3d->replace_by(mesh_instance_node_3d);
|
||||
_copy_meta(p_importer_mesh_instance_3d, mesh_instance_node_3d);
|
||||
// Convert the mesh data in the mesh resource.
|
||||
Ref<ImporterMesh> importer_mesh = p_importer_mesh_instance_3d->get_mesh();
|
||||
if (importer_mesh.is_valid()) {
|
||||
Ref<ArrayMesh> array_mesh = importer_mesh->get_mesh();
|
||||
mesh_instance_node_3d->set_mesh(array_mesh);
|
||||
_copy_meta(importer_mesh.ptr(), array_mesh.ptr());
|
||||
} else {
|
||||
WARN_PRINT("glTF: ImporterMeshInstance3D does not have a valid mesh. This should not happen. Continuing anyway.");
|
||||
}
|
||||
return mesh_instance_node_3d;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFState> p_state, Node *p_root) {
|
||||
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
List<Node *> queue;
|
||||
queue.push_back(p_root);
|
||||
List<Node *> delete_queue;
|
||||
while (!queue.is_empty()) {
|
||||
List<Node *>::Element *E = queue.front();
|
||||
Node *node = E->get();
|
||||
ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node);
|
||||
if (mesh_3d) {
|
||||
MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D);
|
||||
Ref<ImporterMesh> mesh = mesh_3d->get_mesh();
|
||||
if (mesh.is_valid()) {
|
||||
Ref<ArrayMesh> array_mesh = mesh->get_mesh();
|
||||
mesh_instance_node_3d->set_name(node->get_name());
|
||||
mesh_instance_node_3d->set_transform(mesh_3d->get_transform());
|
||||
mesh_instance_node_3d->set_mesh(array_mesh);
|
||||
mesh_instance_node_3d->set_skin(mesh_3d->get_skin());
|
||||
mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
|
||||
node->replace_by(mesh_instance_node_3d);
|
||||
_copy_meta(mesh_3d, mesh_instance_node_3d);
|
||||
_copy_meta(mesh.ptr(), array_mesh.ptr());
|
||||
delete_queue.push_back(node);
|
||||
node = mesh_instance_node_3d;
|
||||
} else {
|
||||
memdelete(mesh_instance_node_3d);
|
||||
}
|
||||
ImporterMeshInstance3D *importer_mesh_3d = Object::cast_to<ImporterMeshInstance3D>(node);
|
||||
if (importer_mesh_3d) {
|
||||
delete_queue.push_back(importer_mesh_3d);
|
||||
node = convert_importer_mesh_instance_3d(importer_mesh_3d);
|
||||
}
|
||||
int child_count = node->get_child_count();
|
||||
for (int i = 0; i < child_count; i++) {
|
||||
|
|
|
|||
|
|
@ -33,14 +33,16 @@
|
|||
|
||||
#include "gltf_document_extension.h"
|
||||
|
||||
class MeshInstance3D;
|
||||
|
||||
class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension {
|
||||
GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static void _copy_meta(Object *p_src_object, Object *p_dst_object);
|
||||
|
||||
public:
|
||||
static MeshInstance3D *convert_importer_mesh_instance_3d(ImporterMeshInstance3D *p_importer_mesh_instance_3d);
|
||||
Error import_post(Ref<GLTFState> p_state, Node *p_root) override;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -170,7 +186,7 @@ Light3D *GLTFLight::to_node() const {
|
|||
}
|
||||
|
||||
Ref<GLTFLight> GLTFLight::from_dictionary(const Dictionary p_dictionary) {
|
||||
ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFLight>(), "Failed to parse GLTF light, missing required field 'type'.");
|
||||
ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFLight>(), "Failed to parse glTF light, missing required field 'type'.");
|
||||
Ref<GLTFLight> light;
|
||||
light.instantiate();
|
||||
const String &type = p_dictionary["type"];
|
||||
|
|
@ -181,7 +197,7 @@ Ref<GLTFLight> GLTFLight::from_dictionary(const Dictionary p_dictionary) {
|
|||
if (arr.size() == 3) {
|
||||
light->color = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF light: The color must have exactly 3 numbers.");
|
||||
ERR_PRINT("Error parsing glTF light: The color must have exactly 3 numbers.");
|
||||
}
|
||||
}
|
||||
if (p_dictionary.has("intensity")) {
|
||||
|
|
@ -195,31 +211,37 @@ Ref<GLTFLight> GLTFLight::from_dictionary(const Dictionary p_dictionary) {
|
|||
light->inner_cone_angle = spot["innerConeAngle"];
|
||||
light->outer_cone_angle = spot["outerConeAngle"];
|
||||
if (light->inner_cone_angle >= light->outer_cone_angle) {
|
||||
ERR_PRINT("Error parsing GLTF light: The inner angle must be smaller than the outer angle.");
|
||||
ERR_PRINT("Error parsing glTF light: The inner angle must be smaller than the outer angle.");
|
||||
}
|
||||
} else if (type != "point" && type != "directional") {
|
||||
ERR_PRINT("Error parsing GLTF light: Light type '" + type + "' is unknown.");
|
||||
ERR_PRINT("Error parsing glTF light: Light type '" + type + "' is unknown.");
|
||||
}
|
||||
return light;
|
||||
}
|
||||
|
||||
Dictionary GLTFLight::to_dictionary() const {
|
||||
Dictionary d;
|
||||
Array color_array;
|
||||
color_array.resize(3);
|
||||
color_array[0] = color.r;
|
||||
color_array[1] = color.g;
|
||||
color_array[2] = color.b;
|
||||
d["color"] = color_array;
|
||||
d["type"] = light_type;
|
||||
if (color != Color(1.0f, 1.0f, 1.0f)) {
|
||||
Array color_array;
|
||||
color_array.resize(3);
|
||||
color_array[0] = color.r;
|
||||
color_array[1] = color.g;
|
||||
color_array[2] = color.b;
|
||||
d["color"] = color_array;
|
||||
}
|
||||
if (intensity != 1.0f) {
|
||||
d["intensity"] = intensity;
|
||||
}
|
||||
if (light_type != "directional" && range != INFINITY) {
|
||||
d["range"] = range;
|
||||
}
|
||||
if (light_type == "spot") {
|
||||
Dictionary spot_dict;
|
||||
spot_dict["innerConeAngle"] = inner_cone_angle;
|
||||
spot_dict["outerConeAngle"] = outer_cone_angle;
|
||||
d["spot"] = spot_dict;
|
||||
}
|
||||
d["intensity"] = intensity;
|
||||
d["range"] = range;
|
||||
d["type"] = light_type;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")) {
|
||||
|
|
@ -88,7 +91,7 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
|
|||
// "collider" is the index of the collider in the state colliders array.
|
||||
int node_collider_index = node_collider_ext["collider"];
|
||||
Array state_colliders = p_state->get_additional_data(StringName("GLTFPhysicsShapes"));
|
||||
ERR_FAIL_INDEX_V_MSG(node_collider_index, state_colliders.size(), Error::ERR_FILE_CORRUPT, "GLTF Physics: On node " + p_gltf_node->get_name() + ", the collider index " + itos(node_collider_index) + " is not in the state colliders (size: " + itos(state_colliders.size()) + ").");
|
||||
ERR_FAIL_INDEX_V_MSG(node_collider_index, state_colliders.size(), Error::ERR_FILE_CORRUPT, "glTF Physics: On node " + p_gltf_node->get_name() + ", the collider index " + itos(node_collider_index) + " is not in the state colliders (size: " + itos(state_colliders.size()) + ").");
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), state_colliders[node_collider_index]);
|
||||
} else {
|
||||
p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), GLTFPhysicsShape::from_dictionary(node_collider_ext));
|
||||
|
|
@ -103,8 +106,9 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
|
|||
int node_shape_index = node_collider.get("shape", -1);
|
||||
if (node_shape_index != -1) {
|
||||
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()) + ").");
|
||||
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.
|
||||
|
|
@ -117,8 +121,9 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
|
|||
int node_shape_index = node_trigger.get("shape", -1);
|
||||
if (node_shape_index != -1) {
|
||||
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()) + ").");
|
||||
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) {
|
||||
|
|
@ -150,7 +293,7 @@ void _setup_shape_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state, Ref
|
|||
return; // The mesh resource is already set up.
|
||||
}
|
||||
TypedArray<GLTFMesh> state_meshes = p_state->get_meshes();
|
||||
ERR_FAIL_INDEX_MSG(shape_mesh_index, state_meshes.size(), "GLTF Physics: When importing '" + p_state->get_scene_name() + "', the shape mesh index " + itos(shape_mesh_index) + " is not in the state meshes (size: " + itos(state_meshes.size()) + ").");
|
||||
ERR_FAIL_INDEX_MSG(shape_mesh_index, state_meshes.size(), "glTF Physics: When importing '" + p_state->get_scene_name() + "', the shape mesh index " + itos(shape_mesh_index) + " is not in the state meshes (size: " + itos(state_meshes.size()) + ").");
|
||||
Ref<GLTFMesh> gltf_mesh = state_meshes[shape_mesh_index];
|
||||
ERR_FAIL_COND(gltf_mesh.is_null());
|
||||
importer_mesh = gltf_mesh->get_mesh();
|
||||
|
|
@ -164,12 +307,12 @@ CollisionObject3D *_generate_shape_with_body(Ref<GLTFState> p_state, Ref<GLTFNod
|
|||
bool is_trigger = p_physics_shape->get_is_trigger();
|
||||
// This method is used for the case where we must generate a parent body.
|
||||
// This is can happen for multiple reasons. One possibility is that this
|
||||
// GLTF file is using OMI_collider but not OMI_physics_body, or at least
|
||||
// glTF file is using OMI_collider but not OMI_physics_body, or at least
|
||||
// this particular node is not using it. Another possibility is that the
|
||||
// physics body information is set up on the same GLTF node, not a parent.
|
||||
// physics body information is set up on the same glTF node, not a parent.
|
||||
CollisionObject3D *body;
|
||||
if (p_physics_body.is_valid()) {
|
||||
// This code is run when the physics body is on the same GLTF node.
|
||||
// This code is run when the physics body is on the same glTF node.
|
||||
body = p_physics_body->to_node();
|
||||
if (is_trigger && (p_physics_body->get_body_type() != "trigger")) {
|
||||
// Edge case: If the body's trigger and the collider's trigger
|
||||
|
|
@ -266,7 +409,7 @@ Node3D *GLTFDocumentExtensionPhysics::generate_scene_node(Ref<GLTFState> p_state
|
|||
Ref<GLTFPhysicsShape> gltf_physics_shape = p_gltf_node->get_additional_data(StringName("GLTFPhysicsShape"));
|
||||
if (gltf_physics_shape.is_valid()) {
|
||||
_setup_shape_mesh_resource_from_index_if_needed(p_state, gltf_physics_shape);
|
||||
// If this GLTF node specifies both a shape and a body, generate both.
|
||||
// If this glTF node specifies both a shape and a body, generate both.
|
||||
if (gltf_physics_body.is_valid()) {
|
||||
return _generate_shape_with_body(p_state, p_gltf_node, gltf_physics_shape, gltf_physics_body);
|
||||
}
|
||||
|
|
@ -309,7 +452,7 @@ Node3D *GLTFDocumentExtensionPhysics::generate_scene_node(Ref<GLTFState> p_state
|
|||
}
|
||||
} else if (!Object::cast_to<PhysicsBody3D>(ancestor_col_obj)) {
|
||||
if (p_gltf_node->get_additional_data(StringName("GLTFPhysicsCompoundCollider"))) {
|
||||
// If the GLTF file wants this node to group solid shapes together,
|
||||
// If the glTF file wants this node to group solid shapes together,
|
||||
// and there is no parent body, we need to create a static body.
|
||||
ancestor_col_obj = memnew(StaticBody3D);
|
||||
ret = ancestor_col_obj;
|
||||
|
|
@ -386,7 +529,7 @@ void GLTFDocumentExtensionPhysics::convert_scene_node(Ref<GLTFState> p_state, Re
|
|||
if (cast_to<CollisionShape3D>(p_scene_node)) {
|
||||
CollisionShape3D *godot_shape = Object::cast_to<CollisionShape3D>(p_scene_node);
|
||||
Ref<GLTFPhysicsShape> gltf_shape = GLTFPhysicsShape::from_node(godot_shape);
|
||||
ERR_FAIL_COND_MSG(gltf_shape.is_null(), "GLTF Physics: Could not convert CollisionShape3D to GLTFPhysicsShape. Does it have a valid Shape3D?");
|
||||
ERR_FAIL_COND_MSG(gltf_shape.is_null(), "glTF Physics: Could not convert CollisionShape3D to GLTFPhysicsShape. Does it have a valid Shape3D?");
|
||||
{
|
||||
Ref<ImporterMesh> importer_mesh = gltf_shape->get_importer_mesh();
|
||||
if (importer_mesh.is_valid()) {
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ void GLTFPhysicsBody::set_body_type(String p_body_type) {
|
|||
} else if (p_body_type == "trigger") {
|
||||
body_type = PhysicsBodyType::TRIGGER;
|
||||
} else {
|
||||
ERR_PRINT("Error setting GLTF physics body type: The body type must be one of \"static\", \"animatable\", \"character\", \"rigid\", \"vehicle\", or \"trigger\".");
|
||||
ERR_PRINT("Error setting glTF physics body type: The body type must be one of \"static\", \"animatable\", \"character\", \"rigid\", \"vehicle\", or \"trigger\".");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
@ -289,7 +286,7 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_dictionary(const Dictionary p_diction
|
|||
physics_body->body_type = PhysicsBodyType::TRIGGER;
|
||||
#endif // DISABLE_DEPRECATED
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF physics body: The body type in the GLTF file \"" + body_type_string + "\" was not recognized.");
|
||||
ERR_PRINT("Error parsing glTF physics body: The body type in the glTF file \"" + body_type_string + "\" was not recognized.");
|
||||
}
|
||||
}
|
||||
if (motion.has("mass")) {
|
||||
|
|
@ -300,7 +297,7 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_dictionary(const Dictionary p_diction
|
|||
if (arr.size() == 3) {
|
||||
physics_body->set_linear_velocity(Vector3(arr[0], arr[1], arr[2]));
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF physics body: The linear velocity vector must have exactly 3 numbers.");
|
||||
ERR_PRINT("Error parsing glTF physics body: The linear velocity vector must have exactly 3 numbers.");
|
||||
}
|
||||
}
|
||||
if (motion.has("angularVelocity")) {
|
||||
|
|
@ -308,7 +305,7 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_dictionary(const Dictionary p_diction
|
|||
if (arr.size() == 3) {
|
||||
physics_body->set_angular_velocity(Vector3(arr[0], arr[1], arr[2]));
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF physics body: The angular velocity vector must have exactly 3 numbers.");
|
||||
ERR_PRINT("Error parsing glTF physics body: The angular velocity vector must have exactly 3 numbers.");
|
||||
}
|
||||
}
|
||||
if (motion.has("centerOfMass")) {
|
||||
|
|
@ -316,7 +313,7 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_dictionary(const Dictionary p_diction
|
|||
if (arr.size() == 3) {
|
||||
physics_body->set_center_of_mass(Vector3(arr[0], arr[1], arr[2]));
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF physics body: The center of mass vector must have exactly 3 numbers.");
|
||||
ERR_PRINT("Error parsing glTF physics body: The center of mass vector must have exactly 3 numbers.");
|
||||
}
|
||||
}
|
||||
if (motion.has("inertiaDiagonal")) {
|
||||
|
|
@ -324,7 +321,7 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_dictionary(const Dictionary p_diction
|
|||
if (arr.size() == 3) {
|
||||
physics_body->set_inertia_diagonal(Vector3(arr[0], arr[1], arr[2]));
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF physics body: The inertia diagonal vector must have exactly 3 numbers.");
|
||||
ERR_PRINT("Error parsing glTF physics body: The inertia diagonal vector must have exactly 3 numbers.");
|
||||
}
|
||||
}
|
||||
if (motion.has("inertiaOrientation")) {
|
||||
|
|
@ -332,7 +329,7 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_dictionary(const Dictionary p_diction
|
|||
if (arr.size() == 4) {
|
||||
physics_body->set_inertia_orientation(Quaternion(arr[0], arr[1], arr[2], arr[3]));
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF physics body: The inertia orientation quaternion must have exactly 4 numbers.");
|
||||
ERR_PRINT("Error parsing glTF physics body: The inertia orientation quaternion must have exactly 4 numbers.");
|
||||
}
|
||||
}
|
||||
return physics_body;
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ void GLTFPhysicsShape::set_importer_mesh(Ref<ImporterMesh> p_importer_mesh) {
|
|||
|
||||
Ref<ImporterMesh> _convert_hull_points_to_mesh(const Vector<Vector3> &p_hull_points) {
|
||||
Ref<ImporterMesh> importer_mesh;
|
||||
ERR_FAIL_COND_V_MSG(p_hull_points.size() < 3, importer_mesh, "GLTFPhysicsShape: Convex hull has fewer points (" + itos(p_hull_points.size()) + ") than the minimum of 3. At least 3 points are required in order to save to GLTF, since it uses a mesh to represent convex hulls.");
|
||||
ERR_FAIL_COND_V_MSG(p_hull_points.size() < 3, importer_mesh, "GLTFPhysicsShape: Convex hull has fewer points (" + itos(p_hull_points.size()) + ") than the minimum of 3. At least 3 points are required in order to save to glTF, since it uses a mesh to represent convex hulls.");
|
||||
if (p_hull_points.size() > 255) {
|
||||
WARN_PRINT("GLTFPhysicsShape: Convex hull has more points (" + itos(p_hull_points.size()) + ") than the recommended maximum of 255. This may not load correctly in other engines.");
|
||||
}
|
||||
|
|
@ -229,7 +229,7 @@ Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_resource(const Ref<Shape3D> &p_shap
|
|||
}
|
||||
|
||||
Ref<Shape3D> GLTFPhysicsShape::to_resource(bool p_cache_shapes) {
|
||||
if (!p_cache_shapes || _shape_cache == nullptr) {
|
||||
if (!p_cache_shapes || _shape_cache.is_null()) {
|
||||
if (shape_type == "box") {
|
||||
Ref<BoxShape3D> box;
|
||||
box.instantiate();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -92,6 +85,12 @@ public:
|
|||
static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension);
|
||||
static void unregister_all_gltf_document_extensions();
|
||||
static Vector<Ref<GLTFDocumentExtension>> get_all_gltf_document_extensions();
|
||||
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;
|
||||
|
|
@ -104,11 +103,11 @@ public:
|
|||
static String _gen_unique_name_static(HashSet<String> &r_unique_names, const String &p_name);
|
||||
|
||||
private:
|
||||
void _build_parent_hierachy(Ref<GLTFState> p_state);
|
||||
void _build_parent_hierarchy(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);
|
||||
|
|
@ -138,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,
|
||||
|
|
@ -176,13 +175,22 @@ 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);
|
||||
Error _serialize_images(Ref<GLTFState> p_state);
|
||||
Error _serialize_lights(Ref<GLTFState> p_state);
|
||||
Ref<Image> _parse_image_bytes_into_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_mime_type, int p_index, String &r_file_extension);
|
||||
void _parse_image_save_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_file_extension, int p_index, Ref<Image> p_image);
|
||||
void _parse_image_save_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_resource_uri, const String &p_file_extension, int p_index, Ref<Image> p_image);
|
||||
Error _parse_images(Ref<GLTFState> p_state, const String &p_base_path);
|
||||
Error _parse_textures(Ref<GLTFState> p_state);
|
||||
Error _parse_texture_samplers(Ref<GLTFState> p_state);
|
||||
|
|
@ -203,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,
|
||||
|
|
@ -214,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,
|
||||
|
|
@ -227,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,
|
||||
|
|
@ -267,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);
|
||||
|
||||
|
|
@ -278,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);
|
||||
|
|
@ -340,17 +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 _create_gltf_node(Ref<GLTFState> p_state,
|
||||
Node *p_scene_parent,
|
||||
GLTFNodeIndex p_current_node_i,
|
||||
GLTFNodeIndex p_parent_node_index,
|
||||
GLTFNodeIndex p_root_gltf_node,
|
||||
Ref<GLTFNode> p_gltf_node);
|
||||
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);
|
||||
|
|
@ -381,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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
void GLTFState::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension);
|
||||
ClassDB::bind_method(D_METHOD("append_data_to_buffers", "data", "deduplication"), &GLTFState::append_data_to_buffers);
|
||||
ClassDB::bind_method(D_METHOD("append_gltf_node", "gltf_node", "godot_scene_node", "parent_node_index"), &GLTFState::append_gltf_node);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json);
|
||||
ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json);
|
||||
|
|
@ -396,8 +397,27 @@ String GLTFState::get_base_path() {
|
|||
return base_path;
|
||||
}
|
||||
|
||||
void GLTFState::set_base_path(String p_base_path) {
|
||||
void GLTFState::set_base_path(const String &p_base_path) {
|
||||
base_path = p_base_path;
|
||||
if (extract_path.is_empty()) {
|
||||
extract_path = p_base_path;
|
||||
}
|
||||
}
|
||||
|
||||
String GLTFState::get_extract_path() {
|
||||
return extract_path;
|
||||
}
|
||||
|
||||
void GLTFState::set_extract_path(const String &p_extract_path) {
|
||||
extract_path = p_extract_path;
|
||||
}
|
||||
|
||||
String GLTFState::get_extract_prefix() {
|
||||
return extract_prefix;
|
||||
}
|
||||
|
||||
void GLTFState::set_extract_prefix(const String &p_extract_prefix) {
|
||||
extract_prefix = p_extract_prefix;
|
||||
}
|
||||
|
||||
String GLTFState::get_filename() const {
|
||||
|
|
@ -406,6 +426,9 @@ String GLTFState::get_filename() const {
|
|||
|
||||
void GLTFState::set_filename(const String &p_filename) {
|
||||
filename = p_filename;
|
||||
if (extract_prefix.is_empty()) {
|
||||
extract_prefix = p_filename.get_basename();
|
||||
}
|
||||
}
|
||||
|
||||
Variant GLTFState::get_additional_data(const StringName &p_extension_name) {
|
||||
|
|
@ -441,3 +464,16 @@ GLTFBufferViewIndex GLTFState::append_data_to_buffers(const Vector<uint8_t> &p_d
|
|||
buffer_views.push_back(buffer_view);
|
||||
return new_index;
|
||||
}
|
||||
|
||||
GLTFNodeIndex GLTFState::append_gltf_node(Ref<GLTFNode> p_gltf_node, Node *p_godot_scene_node, GLTFNodeIndex p_parent_node_index) {
|
||||
p_gltf_node->set_parent(p_parent_node_index);
|
||||
const GLTFNodeIndex new_index = nodes.size();
|
||||
nodes.append(p_gltf_node);
|
||||
scene_nodes.insert(new_index, p_godot_scene_node);
|
||||
if (p_parent_node_index == -1) {
|
||||
root_nodes.append(new_index);
|
||||
} else if (p_parent_node_index < new_index) {
|
||||
nodes.write[p_parent_node_index]->append_child_index(new_index);
|
||||
}
|
||||
return new_index;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,19 +38,24 @@
|
|||
#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"
|
||||
#include "structures/gltf_texture_sampler.h"
|
||||
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
|
||||
class GLTFState : public Resource {
|
||||
GDCLASS(GLTFState, Resource);
|
||||
friend class GLTFDocument;
|
||||
friend class GLTFNode;
|
||||
|
||||
protected:
|
||||
String base_path;
|
||||
String extract_path;
|
||||
String extract_prefix;
|
||||
String filename;
|
||||
Dictionary json;
|
||||
int major_version = 0;
|
||||
|
|
@ -100,6 +105,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;
|
||||
|
|
@ -119,6 +125,7 @@ public:
|
|||
|
||||
void add_used_extension(const String &p_extension, bool p_required = false);
|
||||
GLTFBufferViewIndex append_data_to_buffers(const Vector<uint8_t> &p_data, const bool p_deduplication);
|
||||
GLTFNodeIndex append_gltf_node(Ref<GLTFNode> p_gltf_node, Node *p_godot_scene_node, GLTFNodeIndex p_parent_node_index);
|
||||
|
||||
enum GLTFHandleBinary {
|
||||
HANDLE_BINARY_DISCARD_TEXTURES = 0,
|
||||
|
|
@ -185,7 +192,13 @@ public:
|
|||
void set_scene_name(String p_scene_name);
|
||||
|
||||
String get_base_path();
|
||||
void set_base_path(String p_base_path);
|
||||
void set_base_path(const String &p_base_path);
|
||||
|
||||
String get_extract_path();
|
||||
void set_extract_path(const String &p_extract_path);
|
||||
|
||||
String get_extract_prefix();
|
||||
void set_extract_prefix(const String &p_extract_prefix);
|
||||
|
||||
String get_filename() const;
|
||||
void set_filename(const String &p_filename);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -602,6 +602,11 @@ Error SkinTool::_create_skeletons(
|
|||
skeleton->set_bone_pose_rotation(bone_index, node->transform.basis.get_rotation_quaternion());
|
||||
skeleton->set_bone_pose_scale(bone_index, node->transform.basis.get_scale());
|
||||
|
||||
// Store bone-level GLTF extras in skeleton per bone meta.
|
||||
if (node->has_meta("extras")) {
|
||||
skeleton->set_bone_meta(bone_index, "extras", node->get_meta("extras"));
|
||||
}
|
||||
|
||||
if (node->parent >= 0 && nodes[node->parent]->skeleton == skel_i) {
|
||||
const int bone_parent = skeleton->find_bone(nodes[node->parent]->get_name());
|
||||
ERR_FAIL_COND_V(bone_parent < 0, FAILED);
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
#ifndef GLTF_ANIMATION_H
|
||||
#define GLTF_ANIMATION_H
|
||||
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/animation.h"
|
||||
|
||||
class GLTFAnimation : public Resource {
|
||||
GDCLASS(GLTFAnimation, Resource);
|
||||
|
|
@ -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,14 +58,29 @@ 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();
|
||||
ERR_FAIL_NULL_V_MSG(p_camera, c, "Tried to create a GLTFCamera from a Camera3D node, but the given node was null.");
|
||||
c->set_perspective(p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE);
|
||||
// GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
|
||||
// glTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
|
||||
c->set_fov(Math::deg_to_rad(p_camera->get_fov()));
|
||||
// GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters.
|
||||
// glTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters.
|
||||
c->set_size_mag(p_camera->get_size() * 0.5f);
|
||||
c->set_depth_far(p_camera->get_far());
|
||||
c->set_depth_near(p_camera->get_near());
|
||||
|
|
@ -74,9 +90,9 @@ Ref<GLTFCamera> GLTFCamera::from_node(const Camera3D *p_camera) {
|
|||
Camera3D *GLTFCamera::to_node() const {
|
||||
Camera3D *camera = memnew(Camera3D);
|
||||
camera->set_projection(perspective ? Camera3D::PROJECTION_PERSPECTIVE : Camera3D::PROJECTION_ORTHOGONAL);
|
||||
// GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
|
||||
// glTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
|
||||
camera->set_fov(Math::rad_to_deg(fov));
|
||||
// GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters.
|
||||
// glTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters.
|
||||
camera->set_size(size_mag * 2.0f);
|
||||
camera->set_near(depth_near);
|
||||
camera->set_far(depth_far);
|
||||
|
|
@ -84,7 +100,7 @@ Camera3D *GLTFCamera::to_node() const {
|
|||
}
|
||||
|
||||
Ref<GLTFCamera> GLTFCamera::from_dictionary(const Dictionary p_dictionary) {
|
||||
ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFCamera>(), "Failed to parse GLTF camera, missing required field 'type'.");
|
||||
ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFCamera>(), "Failed to parse glTF camera, missing required field 'type'.");
|
||||
Ref<GLTFCamera> camera;
|
||||
camera.instantiate();
|
||||
const String &type = p_dictionary["type"];
|
||||
|
|
@ -107,7 +123,7 @@ Ref<GLTFCamera> GLTFCamera::from_dictionary(const Dictionary p_dictionary) {
|
|||
camera->set_depth_near(ortho["znear"]);
|
||||
}
|
||||
} else {
|
||||
ERR_PRINT("Error parsing GLTF camera: Camera type '" + type + "' is unknown, should be perspective or orthographic.");
|
||||
ERR_PRINT("Error parsing glTF camera: Camera type '" + type + "' is unknown, should be perspective or orthographic.");
|
||||
}
|
||||
return camera;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -42,8 +43,8 @@ class GLTFCamera : public Resource {
|
|||
GDCLASS(GLTFCamera, Resource);
|
||||
|
||||
private:
|
||||
// GLTF has no default camera values, they should always be specified in
|
||||
// the GLTF file. Here we default to Godot's default camera settings.
|
||||
// glTF has no default camera values, they should always be specified in
|
||||
// the glTF file. Here we default to Godot's default camera settings.
|
||||
bool perspective = true;
|
||||
real_t fov = Math::deg_to_rad(75.0);
|
||||
real_t size_mag = 0.5;
|
||||
|
|
@ -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);
|
||||
|
|
@ -55,10 +57,12 @@ void GLTFNode::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &GLTFNode::set_scale);
|
||||
ClassDB::bind_method(D_METHOD("get_children"), &GLTFNode::get_children);
|
||||
ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children);
|
||||
ClassDB::bind_method(D_METHOD("append_child_index", "child_index"), &GLTFNode::append_child_index);
|
||||
ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light);
|
||||
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
|
||||
|
|
@ -170,6 +174,10 @@ void GLTFNode::set_children(Vector<int> p_children) {
|
|||
children = p_children;
|
||||
}
|
||||
|
||||
void GLTFNode::append_child_index(int p_child_index) {
|
||||
children.append(p_child_index);
|
||||
}
|
||||
|
||||
GLTFLightIndex GLTFNode::get_light() {
|
||||
return light;
|
||||
}
|
||||
|
|
@ -182,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,12 +97,16 @@ public:
|
|||
|
||||
Vector<int> get_children();
|
||||
void set_children(Vector<int> p_children);
|
||||
void append_child_index(int p_child_index);
|
||||
|
||||
GLTFLightIndex get_light();
|
||||
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
engine/modules/gltf/structures/gltf_object_model_property.cpp
Normal file
173
engine/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
engine/modules/gltf/structures/gltf_object_model_property.h
Normal file
104
engine/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
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v4.2.70",
|
||||
"version":"2.0"
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"mesh":0,
|
||||
"name":"mesh_instance_3d"
|
||||
},
|
||||
{
|
||||
"children":[
|
||||
0
|
||||
],
|
||||
"name":"_Node3D_6"
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"name":"material",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0.9999998807907104,
|
||||
0.9999998807907104,
|
||||
0.9999998807907104,
|
||||
1
|
||||
],
|
||||
"baseColorTexture":{
|
||||
"index":0
|
||||
},
|
||||
"metallicFactor":0
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"name":"Mesh_0",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"NORMAL":1,
|
||||
"TEXCOORD_0":2
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures":[
|
||||
{
|
||||
"sampler":0,
|
||||
"source":0
|
||||
}
|
||||
],
|
||||
"images":[
|
||||
{
|
||||
"mimeType":"image/png",
|
||||
"name":"material_albedo000",
|
||||
"uri":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABZJREFUCJljZGBg+P+fgYGBBUIxMAAAKCAEAplLvcoAAAAASUVORK5CYII="
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"max":[
|
||||
1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
0,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":6,
|
||||
"type":"SCALAR"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":48,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":32,
|
||||
"byteOffset":96,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":12,
|
||||
"byteOffset":128,
|
||||
"target":34963
|
||||
}
|
||||
],
|
||||
"samplers":[
|
||||
{
|
||||
"magFilter":9729,
|
||||
"minFilter":9987
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":140,
|
||||
"uri":"data:application/octet-stream;base64,AACAPwAAAAAAAIA/AACAvwAAAAAAAIA/AACAPwAAAAAAAIC/AACAvwAAAAAAAIC/AAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAACAAEAAAACAAMAAQA="
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v4.2.70",
|
||||
"version":"2.0"
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"mesh":0,
|
||||
"name":"mesh_instance_3d"
|
||||
},
|
||||
{
|
||||
"children":[
|
||||
0
|
||||
],
|
||||
"name":"_Node3D_6"
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"name":"material",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0.9999998807907104,
|
||||
0.9999998807907104,
|
||||
0.9999998807907104,
|
||||
1
|
||||
],
|
||||
"baseColorTexture":{
|
||||
"index":0
|
||||
},
|
||||
"metallicFactor":0
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"name":"Mesh_0",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"NORMAL":1,
|
||||
"TEXCOORD_0":2
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures":[
|
||||
{
|
||||
"sampler":0,
|
||||
"source":0
|
||||
}
|
||||
],
|
||||
"images":[
|
||||
{
|
||||
"mimeType":"image/png",
|
||||
"name":"material_albedo000",
|
||||
"uri":"texture.png",
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"max":[
|
||||
1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
0,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":6,
|
||||
"type":"SCALAR"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":48,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":32,
|
||||
"byteOffset":96,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":12,
|
||||
"byteOffset":128,
|
||||
"target":34963
|
||||
}
|
||||
],
|
||||
"samplers":[
|
||||
{
|
||||
"magFilter":9729,
|
||||
"minFilter":9987
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":140,
|
||||
"uri":"data:application/octet-stream;base64,AACAPwAAAAAAAIA/AACAvwAAAAAAAIA/AACAPwAAAAAAAIC/AACAvwAAAAAAAIC/AAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAACAAEAAAACAAMAAQA="
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 92 B |
|
|
@ -0,0 +1,147 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v4.2.70",
|
||||
"version":"2.0"
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"mesh":0,
|
||||
"name":"mesh_instance_3d"
|
||||
},
|
||||
{
|
||||
"children":[
|
||||
0
|
||||
],
|
||||
"name":"_Node3D_6"
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"name":"material",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0.9999998807907104,
|
||||
0.9999998807907104,
|
||||
0.9999998807907104,
|
||||
1
|
||||
],
|
||||
"baseColorTexture":{
|
||||
"index":0
|
||||
},
|
||||
"metallicFactor":0
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"name":"Mesh_0",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"NORMAL":1,
|
||||
"TEXCOORD_0":2
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures":[
|
||||
{
|
||||
"sampler":0,
|
||||
"source":0
|
||||
}
|
||||
],
|
||||
"images":[
|
||||
{
|
||||
"mimeType":"image/png",
|
||||
"name":"material_albedo000",
|
||||
"uri":"../texture.png",
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"max":[
|
||||
1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
0,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":6,
|
||||
"type":"SCALAR"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":48,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":32,
|
||||
"byteOffset":96,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":12,
|
||||
"byteOffset":128,
|
||||
"target":34963
|
||||
}
|
||||
],
|
||||
"samplers":[
|
||||
{
|
||||
"magFilter":9729,
|
||||
"minFilter":9987
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":140,
|
||||
"uri":"data:application/octet-stream;base64,AACAPwAAAAAAAIA/AACAvwAAAAAAAIA/AACAPwAAAAAAAIC/AACAvwAAAAAAAIC/AAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAACAAEAAAACAAMAAQA="
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 92 B |
166
engine/modules/gltf/tests/test_gltf.h
Normal file
166
engine/modules/gltf/tests/test_gltf.h
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/**************************************************************************/
|
||||
/* test_gltf.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 TEST_GLTF_H
|
||||
#define TEST_GLTF_H
|
||||
|
||||
#include "tests/test_macros.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "drivers/png/image_loader_png.h"
|
||||
#include "editor/editor_resource_preview.h"
|
||||
#include "editor/import/3d/resource_importer_scene.h"
|
||||
#include "editor/import/resource_importer_texture.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/resources/3d/primitive_meshes.h"
|
||||
#include "scene/resources/compressed_texture.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/packed_scene.h"
|
||||
#include "tests/core/config/test_project_settings.h"
|
||||
|
||||
#include "modules/gltf/editor/editor_scene_importer_gltf.h"
|
||||
#include "modules/gltf/gltf_document.h"
|
||||
#include "modules/gltf/gltf_state.h"
|
||||
|
||||
namespace TestGltf {
|
||||
|
||||
static Node *gltf_import(const String &p_file) {
|
||||
// Setting up importers.
|
||||
Ref<ResourceImporterScene> import_scene;
|
||||
import_scene.instantiate("PackedScene", true);
|
||||
ResourceFormatImporter::get_singleton()->add_importer(import_scene);
|
||||
Ref<EditorSceneFormatImporterGLTF> import_gltf;
|
||||
import_gltf.instantiate();
|
||||
ResourceImporterScene::add_scene_importer(import_gltf);
|
||||
|
||||
// Support processing png files in editor import.
|
||||
Ref<ResourceImporterTexture> import_texture;
|
||||
import_texture.instantiate(true);
|
||||
ResourceFormatImporter::get_singleton()->add_importer(import_texture);
|
||||
|
||||
// Once editor import convert pngs to ctex, we will need to load it as ctex resource.
|
||||
Ref<ResourceFormatLoaderCompressedTexture2D> resource_loader_stream_texture;
|
||||
resource_loader_stream_texture.instantiate();
|
||||
ResourceLoader::add_resource_format_loader(resource_loader_stream_texture);
|
||||
|
||||
HashMap<StringName, Variant> options(21);
|
||||
options["nodes/root_type"] = "";
|
||||
options["nodes/root_name"] = "";
|
||||
options["nodes/apply_root_scale"] = true;
|
||||
options["nodes/root_scale"] = 1.0;
|
||||
options["meshes/ensure_tangents"] = true;
|
||||
options["meshes/generate_lods"] = false;
|
||||
options["meshes/create_shadow_meshes"] = true;
|
||||
options["meshes/light_baking"] = 1;
|
||||
options["meshes/lightmap_texel_size"] = 0.2;
|
||||
options["meshes/force_disable_compression"] = false;
|
||||
options["skins/use_named_skins"] = true;
|
||||
options["animation/import"] = true;
|
||||
options["animation/fps"] = 30;
|
||||
options["animation/trimming"] = false;
|
||||
options["animation/remove_immutable_tracks"] = true;
|
||||
options["import_script/path"] = "";
|
||||
options["extract_path"] = "res://";
|
||||
options["_subresources"] = Dictionary();
|
||||
options["gltf/naming_version"] = 1;
|
||||
|
||||
// Process gltf file, note that this generates `.scn` resource from the 2nd argument.
|
||||
String scene_file = "res://" + p_file.get_file().get_basename();
|
||||
Error err = import_scene->import(0, p_file, scene_file, options, nullptr, nullptr, nullptr);
|
||||
CHECK_MESSAGE(err == OK, "GLTF import failed.");
|
||||
|
||||
Ref<PackedScene> packed_scene = ResourceLoader::load(scene_file + ".scn", "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
|
||||
CHECK_MESSAGE(err == OK, "Loading scene failed.");
|
||||
Node *p_scene = packed_scene->instantiate();
|
||||
|
||||
ResourceImporterScene::remove_scene_importer(import_gltf);
|
||||
ResourceFormatImporter::get_singleton()->remove_importer(import_texture);
|
||||
ResourceLoader::remove_resource_format_loader(resource_loader_stream_texture);
|
||||
return p_scene;
|
||||
}
|
||||
|
||||
static Node *gltf_export_then_import(Node *p_root, const String &p_test_name) {
|
||||
String tempfile = TestUtils::get_temp_path(p_test_name);
|
||||
|
||||
Ref<GLTFDocument> doc;
|
||||
doc.instantiate();
|
||||
Ref<GLTFState> state;
|
||||
state.instantiate();
|
||||
Error err = doc->append_from_scene(p_root, state, EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS);
|
||||
CHECK_MESSAGE(err == OK, "GLTF state generation failed.");
|
||||
|
||||
err = doc->write_to_filesystem(state, tempfile + ".gltf");
|
||||
CHECK_MESSAGE(err == OK, "Writing GLTF to cache dir failed.");
|
||||
|
||||
return gltf_import(tempfile + ".gltf");
|
||||
}
|
||||
|
||||
void init(const String &p_test, const String &p_copy_target = String()) {
|
||||
Error err;
|
||||
|
||||
// Setup project settings since it's needed for the import process.
|
||||
String project_folder = TestUtils::get_temp_path(p_test.get_file().get_basename());
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
da->make_dir_recursive(project_folder.path_join(".godot").path_join("imported"));
|
||||
// Initialize res:// to `project_folder`.
|
||||
TestProjectSettingsInternalsAccessor::resource_path() = project_folder;
|
||||
err = ProjectSettings::get_singleton()->setup(project_folder, String(), true);
|
||||
|
||||
if (p_copy_target.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy all the necessary test data files to the res:// directory.
|
||||
da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
String test_data = String("modules/gltf/tests/data/").path_join(p_test);
|
||||
da = DirAccess::open(test_data);
|
||||
CHECK_MESSAGE(da.is_valid(), "Unable to open folder.");
|
||||
da->list_dir_begin();
|
||||
for (String item = da->get_next(); !item.is_empty(); item = da->get_next()) {
|
||||
if (!FileAccess::exists(test_data.path_join(item))) {
|
||||
continue;
|
||||
}
|
||||
Ref<FileAccess> output = FileAccess::open(p_copy_target.path_join(item), FileAccess::WRITE, &err);
|
||||
CHECK_MESSAGE(err == OK, "Unable to open output file.");
|
||||
output->store_buffer(FileAccess::get_file_as_bytes(test_data.path_join(item)));
|
||||
output->close();
|
||||
}
|
||||
da->list_dir_end();
|
||||
}
|
||||
|
||||
} //namespace TestGltf
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // TEST_GLTF_H
|
||||
178
engine/modules/gltf/tests/test_gltf_extras.h
Normal file
178
engine/modules/gltf/tests/test_gltf_extras.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/**************************************************************************/
|
||||
/* test_gltf_extras.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 TEST_GLTF_EXTRAS_H
|
||||
#define TEST_GLTF_EXTRAS_H
|
||||
|
||||
#include "test_gltf.h"
|
||||
#include "tests/test_macros.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "editor/import/3d/resource_importer_scene.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/resources/3d/primitive_meshes.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/packed_scene.h"
|
||||
|
||||
#include "modules/gltf/editor/editor_scene_importer_gltf.h"
|
||||
#include "modules/gltf/gltf_document.h"
|
||||
#include "modules/gltf/gltf_state.h"
|
||||
|
||||
namespace TestGltf {
|
||||
|
||||
TEST_CASE("[SceneTree][Node] GLTF test mesh and material meta export and import") {
|
||||
init("gltf_mesh_material_extras");
|
||||
// Setup scene.
|
||||
Ref<StandardMaterial3D> original_material = memnew(StandardMaterial3D);
|
||||
original_material->set_albedo(Color(1.0, .0, .0));
|
||||
original_material->set_name("material");
|
||||
Dictionary material_dict;
|
||||
material_dict["node_type"] = "material";
|
||||
original_material->set_meta("extras", material_dict);
|
||||
|
||||
Ref<PlaneMesh> original_meshdata = memnew(PlaneMesh);
|
||||
original_meshdata->set_name("planemesh");
|
||||
Dictionary meshdata_dict;
|
||||
meshdata_dict["node_type"] = "planemesh";
|
||||
original_meshdata->set_meta("extras", meshdata_dict);
|
||||
original_meshdata->surface_set_material(0, original_material);
|
||||
|
||||
MeshInstance3D *original_mesh_instance = memnew(MeshInstance3D);
|
||||
original_mesh_instance->set_mesh(original_meshdata);
|
||||
original_mesh_instance->set_name("mesh_instance_3d");
|
||||
Dictionary mesh_instance_dict;
|
||||
mesh_instance_dict["node_type"] = "mesh_instance_3d";
|
||||
original_mesh_instance->set_meta("extras", mesh_instance_dict);
|
||||
|
||||
Node3D *original = memnew(Node3D);
|
||||
SceneTree::get_singleton()->get_root()->add_child(original);
|
||||
original->add_child(original_mesh_instance);
|
||||
original->set_name("node3d");
|
||||
Dictionary node_dict;
|
||||
node_dict["node_type"] = "node3d";
|
||||
original->set_meta("extras", node_dict);
|
||||
original->set_meta("meta_not_nested_under_extras", "should not propagate");
|
||||
|
||||
original->set_owner(SceneTree::get_singleton()->get_root());
|
||||
original_mesh_instance->set_owner(SceneTree::get_singleton()->get_root());
|
||||
|
||||
// Convert to GLFT and back.
|
||||
Node *loaded = gltf_export_then_import(original, "gltf_extras");
|
||||
|
||||
// Compare the results.
|
||||
CHECK(loaded->get_name() == "node3d");
|
||||
CHECK(Dictionary(loaded->get_meta("extras")).size() == 1);
|
||||
CHECK(Dictionary(loaded->get_meta("extras"))["node_type"] == "node3d");
|
||||
CHECK_FALSE(loaded->has_meta("meta_not_nested_under_extras"));
|
||||
CHECK_FALSE(Dictionary(loaded->get_meta("extras")).has("meta_not_nested_under_extras"));
|
||||
|
||||
MeshInstance3D *mesh_instance_3d = Object::cast_to<MeshInstance3D>(loaded->find_child("mesh_instance_3d", false, true));
|
||||
CHECK(mesh_instance_3d->get_name() == "mesh_instance_3d");
|
||||
CHECK(Dictionary(mesh_instance_3d->get_meta("extras"))["node_type"] == "mesh_instance_3d");
|
||||
|
||||
Ref<Mesh> mesh = mesh_instance_3d->get_mesh();
|
||||
CHECK(Dictionary(mesh->get_meta("extras"))["node_type"] == "planemesh");
|
||||
|
||||
Ref<Material> material = mesh->surface_get_material(0);
|
||||
CHECK(material->get_name() == "material");
|
||||
CHECK(Dictionary(material->get_meta("extras"))["node_type"] == "material");
|
||||
|
||||
memdelete(original_mesh_instance);
|
||||
memdelete(original);
|
||||
memdelete(loaded);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Node] GLTF test skeleton and bone export and import") {
|
||||
init("gltf_skeleton_extras");
|
||||
// Setup scene.
|
||||
Skeleton3D *skeleton = memnew(Skeleton3D);
|
||||
skeleton->set_name("skeleton");
|
||||
Dictionary skeleton_extras;
|
||||
skeleton_extras["node_type"] = "skeleton";
|
||||
skeleton->set_meta("extras", skeleton_extras);
|
||||
|
||||
skeleton->add_bone("parent");
|
||||
skeleton->set_bone_rest(0, Transform3D());
|
||||
Dictionary parent_bone_extras;
|
||||
parent_bone_extras["bone"] = "i_am_parent_bone";
|
||||
skeleton->set_bone_meta(0, "extras", parent_bone_extras);
|
||||
|
||||
skeleton->add_bone("child");
|
||||
skeleton->set_bone_rest(1, Transform3D());
|
||||
skeleton->set_bone_parent(1, 0);
|
||||
Dictionary child_bone_extras;
|
||||
child_bone_extras["bone"] = "i_am_child_bone";
|
||||
skeleton->set_bone_meta(1, "extras", child_bone_extras);
|
||||
|
||||
// We have to have a mesh to link with skeleton or it will not get imported.
|
||||
Ref<PlaneMesh> meshdata = memnew(PlaneMesh);
|
||||
meshdata->set_name("planemesh");
|
||||
|
||||
MeshInstance3D *mesh = memnew(MeshInstance3D);
|
||||
mesh->set_mesh(meshdata);
|
||||
mesh->set_name("mesh_instance_3d");
|
||||
|
||||
Node3D *original = memnew(Node3D);
|
||||
SceneTree::get_singleton()->get_root()->add_child(original);
|
||||
original->add_child(skeleton);
|
||||
original->add_child(mesh);
|
||||
original->set_name("node3d");
|
||||
|
||||
// Now that both skeleton and mesh are part of scene, link them.
|
||||
mesh->set_skeleton_path(mesh->get_path_to(skeleton));
|
||||
|
||||
mesh->set_owner(SceneTree::get_singleton()->get_root());
|
||||
original->set_owner(SceneTree::get_singleton()->get_root());
|
||||
|
||||
// Convert to GLFT and back.
|
||||
Node *loaded = gltf_export_then_import(original, "gltf_bone_extras");
|
||||
|
||||
// Compare the results.
|
||||
CHECK(loaded->get_name() == "node3d");
|
||||
Skeleton3D *result = Object::cast_to<Skeleton3D>(loaded->find_child("Skeleton3D", false, true));
|
||||
CHECK(result->get_bone_name(0) == "parent");
|
||||
CHECK(Dictionary(result->get_bone_meta(0, "extras"))["bone"] == "i_am_parent_bone");
|
||||
CHECK(result->get_bone_name(1) == "child");
|
||||
CHECK(Dictionary(result->get_bone_meta(1, "extras"))["bone"] == "i_am_child_bone");
|
||||
|
||||
memdelete(skeleton);
|
||||
memdelete(mesh);
|
||||
memdelete(original);
|
||||
memdelete(loaded);
|
||||
}
|
||||
} //namespace TestGltf
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // TEST_GLTF_EXTRAS_H
|
||||
169
engine/modules/gltf/tests/test_gltf_images.h
Normal file
169
engine/modules/gltf/tests/test_gltf_images.h
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/**************************************************************************/
|
||||
/* test_gltf_images.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 TEST_GLTF_IMAGES_H
|
||||
#define TEST_GLTF_IMAGES_H
|
||||
|
||||
#include "test_gltf.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_paths.h"
|
||||
#include "scene/resources/image_texture.h"
|
||||
|
||||
namespace TestGltf {
|
||||
Ref<Texture2D> _check_texture(Node *p_node) {
|
||||
MeshInstance3D *mesh_instance_3d = Object::cast_to<MeshInstance3D>(p_node->find_child("mesh_instance_3d", true, true));
|
||||
Ref<StandardMaterial3D> material = mesh_instance_3d->get_active_material(0);
|
||||
Ref<Texture2D> texture = material->get_texture(StandardMaterial3D::TextureParam::TEXTURE_ALBEDO);
|
||||
|
||||
CHECK_MESSAGE(texture->get_size().x == 2, "Texture width not correct.");
|
||||
CHECK_MESSAGE(texture->get_size().y == 2, "Texture height not correct.");
|
||||
|
||||
// Check if the loaded texture pixels are exactly as we expect.
|
||||
for (int x = 0; x < 2; ++x) {
|
||||
for (int y = 0; y < 2; ++y) {
|
||||
Color c = texture->get_image()->get_pixel(x, y);
|
||||
CHECK_MESSAGE(c == Color(x, y, y), "Texture content is incorrect.");
|
||||
}
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Node] Export GLTF with external texture and import") {
|
||||
init("gltf_images_external_export_import");
|
||||
// Setup scene.
|
||||
Ref<ImageTexture> original_texture;
|
||||
original_texture.instantiate();
|
||||
Ref<Image> image;
|
||||
image.instantiate();
|
||||
image->initialize_data(2, 2, false, Image::FORMAT_RGBA8);
|
||||
for (int x = 0; x < 2; ++x) {
|
||||
for (int y = 0; y < 2; ++y) {
|
||||
image->set_pixel(x, y, Color(x, y, y));
|
||||
}
|
||||
}
|
||||
|
||||
original_texture->set_image(image);
|
||||
|
||||
Ref<StandardMaterial3D> original_material;
|
||||
original_material.instantiate();
|
||||
original_material->set_texture(StandardMaterial3D::TextureParam::TEXTURE_ALBEDO, original_texture);
|
||||
original_material->set_name("material");
|
||||
|
||||
Ref<PlaneMesh> original_meshdata;
|
||||
original_meshdata.instantiate();
|
||||
original_meshdata->set_name("planemesh");
|
||||
original_meshdata->surface_set_material(0, original_material);
|
||||
|
||||
MeshInstance3D *original_mesh_instance = memnew(MeshInstance3D);
|
||||
original_mesh_instance->set_mesh(original_meshdata);
|
||||
original_mesh_instance->set_name("mesh_instance_3d");
|
||||
|
||||
Node3D *original = memnew(Node3D);
|
||||
SceneTree::get_singleton()->get_root()->add_child(original);
|
||||
original->add_child(original_mesh_instance);
|
||||
original->set_owner(SceneTree::get_singleton()->get_root());
|
||||
original_mesh_instance->set_owner(SceneTree::get_singleton()->get_root());
|
||||
|
||||
// Convert to GLFT and back.
|
||||
Node *loaded = gltf_export_then_import(original, "gltf_images");
|
||||
_check_texture(loaded);
|
||||
|
||||
memdelete(original_mesh_instance);
|
||||
memdelete(original);
|
||||
memdelete(loaded);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Node][Editor] Import GLTF from .godot/imported folder with external texture") {
|
||||
init("gltf_placed_in_dot_godot_imported", "res://.godot/imported");
|
||||
|
||||
EditorFileSystem *efs = memnew(EditorFileSystem);
|
||||
EditorResourcePreview *erp = memnew(EditorResourcePreview);
|
||||
|
||||
Node *loaded = gltf_import("res://.godot/imported/gltf_placed_in_dot_godot_imported.gltf");
|
||||
Ref<Texture2D> texture = _check_texture(loaded);
|
||||
|
||||
// In-editor imports of gltf and texture from .godot/imported folder should end up in res:// if extract_path is defined.
|
||||
CHECK_MESSAGE(texture->get_path() == "res://gltf_placed_in_dot_godot_imported_material_albedo000.png", "Texture not parsed as resource.");
|
||||
|
||||
memdelete(loaded);
|
||||
memdelete(erp);
|
||||
memdelete(efs);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Node][Editor] Import GLTF with texture outside of res:// directory") {
|
||||
init("gltf_pointing_to_texture_outside_of_res_folder", "res://");
|
||||
|
||||
EditorFileSystem *efs = memnew(EditorFileSystem);
|
||||
EditorResourcePreview *erp = memnew(EditorResourcePreview);
|
||||
|
||||
// Copy texture to the parent folder of res:// - i.e. to res://.. where we can't import from.
|
||||
String oneup = TestUtils::get_temp_path("texture.png");
|
||||
Error err;
|
||||
Ref<FileAccess> output = FileAccess::open(oneup, FileAccess::WRITE, &err);
|
||||
CHECK_MESSAGE(err == OK, "Unable to open texture file.");
|
||||
output->store_buffer(FileAccess::get_file_as_bytes("res://texture_source.png"));
|
||||
output->close();
|
||||
|
||||
Node *loaded = gltf_import("res://gltf_pointing_to_texture_outside_of_res_folder.gltf");
|
||||
Ref<Texture2D> texture = _check_texture(loaded);
|
||||
|
||||
// Imports of gltf with texture from outside of res:// folder should end up being copied to res://
|
||||
CHECK_MESSAGE(texture->get_path() == "res://gltf_pointing_to_texture_outside_of_res_folder_material_albedo000.png", "Texture not parsed as resource.");
|
||||
|
||||
memdelete(loaded);
|
||||
memdelete(erp);
|
||||
memdelete(efs);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Node][Editor] Import GLTF with embedded texture, check how it got extracted") {
|
||||
init("gltf_embedded_texture", "res://");
|
||||
|
||||
EditorFileSystem *efs = memnew(EditorFileSystem);
|
||||
EditorResourcePreview *erp = memnew(EditorResourcePreview);
|
||||
|
||||
Node *loaded = gltf_import("res://embedded_texture.gltf");
|
||||
Ref<Texture2D> texture = _check_texture(loaded);
|
||||
|
||||
// In-editor imports of texture embedded in file should end up with a resource.
|
||||
CHECK_MESSAGE(texture->get_path() == "res://embedded_texture_material_albedo000.png", "Texture not parsed as resource.");
|
||||
|
||||
memdelete(loaded);
|
||||
memdelete(erp);
|
||||
memdelete(efs);
|
||||
}
|
||||
|
||||
} //namespace TestGltf
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
#endif // TEST_GLTF_IMAGES_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue