GLTF: Rename GLTFCollider class to GLTFPhysicsShape

This commit is contained in:
Aaron Franke 2023-06-16 15:01:35 -05:00
parent fa268be823
commit a222bdf83f
No known key found for this signature in database
GPG key ID: 40A1750B977E56BF
8 changed files with 185 additions and 185 deletions

View file

@ -15,7 +15,6 @@ def get_doc_classes():
"GLTFAnimation",
"GLTFBufferView",
"GLTFCamera",
"GLTFCollider",
"GLTFDocument",
"GLTFDocumentExtension",
"GLTFDocumentExtensionConvertImporterMesh",
@ -23,6 +22,7 @@ def get_doc_classes():
"GLTFMesh",
"GLTFNode",
"GLTFPhysicsBody",
"GLTFPhysicsShape",
"GLTFSkeleton",
"GLTFSkin",
"GLTFSpecGloss",

View file

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFCollider" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF collider.
</brief_description>
<description>
Represents a collider as defined by the [code]OMI_collider[/code] GLTF extension. 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="OMI_collider GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_collider</link>
</tutorials>
<methods>
<method name="from_dictionary" qualifiers="static">
<return type="GLTFCollider" />
<param index="0" name="dictionary" type="Dictionary" />
<description>
Creates a new GLTFCollider instance by parsing the given [Dictionary].
</description>
</method>
<method name="from_node" qualifiers="static">
<return type="GLTFCollider" />
<param index="0" name="collider_node" type="CollisionShape3D" />
<description>
Create a new GLTFCollider instance from the given Godot [CollisionShape3D] node.
</description>
</method>
<method name="to_dictionary" qualifiers="const">
<return type="Dictionary" />
<description>
Serializes this GLTFCollider instance into a [Dictionary].
</description>
</method>
<method name="to_node">
<return type="CollisionShape3D" />
<param index="0" name="cache_shapes" type="bool" default="false" />
<description>
Converts this GLTFCollider instance into a Godot [CollisionShape3D] node.
</description>
</method>
</methods>
<members>
<member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
The height of the collider, in meters. This is only used when the collider type is "capsule" or "cylinder". This value should not be negative, and for "capsule" it should be at least twice the radius.
</member>
<member name="importer_mesh" type="ImporterMesh" setter="set_importer_mesh" getter="get_importer_mesh">
The [ImporterMesh] resource of the collider. This is only used when the collider type is "hull" (convex hull) or "trimesh" (concave trimesh).
</member>
<member name="is_trigger" type="bool" setter="set_is_trigger" getter="get_is_trigger" default="false">
If [code]true[/code], indicates that this collider is a trigger. For Godot, this means that the collider should be a child of an Area3D node.
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 collider's mesh in the GLTF file. This is only used when the collider 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 collider, in meters. This is only used when the collider type is "capsule", "cylinder", or "sphere". This value should not be negative.
</member>
<member name="shape_type" type="String" setter="set_shape_type" getter="get_shape_type" default="&quot;&quot;">
The type of shape this collider represents. Valid values are "box", "capsule", "cylinder", "sphere", "hull", and "trimesh".
</member>
<member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(1, 1, 1)">
The size of the collider, in meters. This is only used when the collider type is "box", and it represents the "diameter" of the box. This value should not be negative.
</member>
</members>
</class>

View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFPhysicsShape" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF physics shape.
</brief_description>
<description>
Represents a physics shape as defined by the [code]OMI_collider[/code] GLTF extension. 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="OMI_collider GLTF extension">https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_collider</link>
</tutorials>
<methods>
<method name="from_dictionary" qualifiers="static">
<return type="GLTFPhysicsShape" />
<param index="0" name="dictionary" type="Dictionary" />
<description>
Creates a new GLTFPhysicsShape instance by parsing the given [Dictionary].
</description>
</method>
<method name="from_node" qualifiers="static">
<return type="GLTFPhysicsShape" />
<param index="0" name="shape_node" type="CollisionShape3D" />
<description>
Create a new GLTFPhysicsShape instance from the given Godot [CollisionShape3D] node.
</description>
</method>
<method name="to_dictionary" qualifiers="const">
<return type="Dictionary" />
<description>
Serializes this GLTFPhysicsShape instance into a [Dictionary].
</description>
</method>
<method name="to_node">
<return type="CollisionShape3D" />
<param index="0" name="cache_shapes" type="bool" default="false" />
<description>
Converts this GLTFPhysicsShape instance into a Godot [CollisionShape3D] node.
</description>
</method>
</methods>
<members>
<member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
The height of the shape, in meters. This is only used when the shape type is "capsule" or "cylinder". This value should not be negative, and for "capsule" it should be at least twice the radius.
</member>
<member name="importer_mesh" type="ImporterMesh" setter="set_importer_mesh" getter="get_importer_mesh">
The [ImporterMesh] resource of the shape. This is only used when the shape type is "hull" (convex hull) or "trimesh" (concave trimesh).
</member>
<member name="is_trigger" type="bool" setter="set_is_trigger" getter="get_is_trigger" default="false">
If [code]true[/code], indicates that this shape is a trigger. For Godot, this means that the shape should be a child of an Area3D node.
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).
</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.
</member>
<member name="shape_type" type="String" setter="set_shape_type" getter="get_shape_type" default="&quot;&quot;">
The type of shape this shape represents. Valid values are "box", "capsule", "cylinder", "sphere", "hull", and "trimesh".
</member>
<member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(1, 1, 1)">
The size of the shape, in meters. This is only used when the shape type is "box", and it represents the "diameter" of the box. This value should not be negative.
</member>
</members>
</class>

View file

@ -47,9 +47,9 @@ Error GLTFDocumentExtensionPhysics::import_preflight(Ref<GLTFState> p_state, Vec
if (state_collider_dicts.size() > 0) {
Array state_colliders;
for (int i = 0; i < state_collider_dicts.size(); i++) {
state_colliders.push_back(GLTFCollider::from_dictionary(state_collider_dicts[i]));
state_colliders.push_back(GLTFPhysicsShape::from_dictionary(state_collider_dicts[i]));
}
p_state->set_additional_data("GLTFColliders", state_colliders);
p_state->set_additional_data("GLTFPhysicsShapes", state_colliders);
}
}
}
@ -70,11 +70,11 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
if (node_collider_ext.has("collider")) {
// "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("GLTFColliders");
Array state_colliders = p_state->get_additional_data("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()) + ").");
p_gltf_node->set_additional_data(StringName("GLTFCollider"), state_colliders[node_collider_index]);
p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), state_colliders[node_collider_index]);
} else {
p_gltf_node->set_additional_data(StringName("GLTFCollider"), GLTFCollider::from_dictionary(p_extensions["OMI_collider"]));
p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), GLTFPhysicsShape::from_dictionary(p_extensions["OMI_collider"]));
}
}
if (p_extensions.has("OMI_physics_body")) {
@ -83,7 +83,7 @@ Error GLTFDocumentExtensionPhysics::parse_node_extensions(Ref<GLTFState> p_state
return OK;
}
void _setup_collider_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state, Ref<GLTFCollider> p_collider) {
void _setup_collider_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state, Ref<GLTFPhysicsShape> p_collider) {
GLTFMeshIndex collider_mesh_index = p_collider->get_mesh_index();
if (collider_mesh_index == -1) {
return; // No mesh for this collider.
@ -101,7 +101,7 @@ void _setup_collider_mesh_resource_from_index_if_needed(Ref<GLTFState> p_state,
p_collider->set_importer_mesh(importer_mesh);
}
CollisionObject3D *_generate_collision_with_body(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Ref<GLTFCollider> p_collider, Ref<GLTFPhysicsBody> p_physics_body) {
CollisionObject3D *_generate_collision_with_body(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Ref<GLTFPhysicsShape> p_collider, Ref<GLTFPhysicsBody> p_physics_body) {
print_verbose("glTF: Creating collision for: " + p_gltf_node->get_name());
bool is_trigger = p_collider->get_is_trigger();
// This method is used for the case where we must generate a parent body.
@ -134,7 +134,7 @@ CollisionObject3D *_generate_collision_with_body(Ref<GLTFState> p_state, Ref<GLT
Node3D *GLTFDocumentExtensionPhysics::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
Ref<GLTFPhysicsBody> physics_body = p_gltf_node->get_additional_data(StringName("GLTFPhysicsBody"));
Ref<GLTFCollider> collider = p_gltf_node->get_additional_data(StringName("GLTFCollider"));
Ref<GLTFPhysicsShape> collider = p_gltf_node->get_additional_data(StringName("GLTFPhysicsShape"));
if (collider.is_valid()) {
_setup_collider_mesh_resource_from_index_if_needed(p_state, collider);
// If the collider has the correct type of parent, we just return one node.
@ -203,14 +203,14 @@ GLTFMeshIndex _get_or_insert_mesh_in_state(Ref<GLTFState> p_state, Ref<ImporterM
void GLTFDocumentExtensionPhysics::convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node) {
if (cast_to<CollisionShape3D>(p_scene_node)) {
CollisionShape3D *shape = Object::cast_to<CollisionShape3D>(p_scene_node);
Ref<GLTFCollider> collider = GLTFCollider::from_node(shape);
Ref<GLTFPhysicsShape> collider = GLTFPhysicsShape::from_node(shape);
{
Ref<ImporterMesh> importer_mesh = collider->get_importer_mesh();
if (importer_mesh.is_valid()) {
collider->set_mesh_index(_get_or_insert_mesh_in_state(p_state, importer_mesh));
}
}
p_gltf_node->set_additional_data(StringName("GLTFCollider"), collider);
p_gltf_node->set_additional_data(StringName("GLTFPhysicsShape"), collider);
} else if (cast_to<CollisionObject3D>(p_scene_node)) {
CollisionObject3D *body = Object::cast_to<CollisionObject3D>(p_scene_node);
p_gltf_node->set_additional_data(StringName("GLTFPhysicsBody"), GLTFPhysicsBody::from_node(body));
@ -248,7 +248,7 @@ Error GLTFDocumentExtensionPhysics::export_node(Ref<GLTFState> p_state, Ref<GLTF
node_extensions["OMI_physics_body"] = physics_body->to_dictionary();
p_state->add_used_extension("OMI_physics_body");
}
Ref<GLTFCollider> collider = p_gltf_node->get_additional_data(StringName("GLTFCollider"));
Ref<GLTFPhysicsShape> collider = p_gltf_node->get_additional_data(StringName("GLTFPhysicsShape"));
if (collider.is_valid()) {
Array state_colliders = _get_or_create_state_colliders_in_state(p_state);
int size = state_colliders.size();

View file

@ -32,8 +32,8 @@
#define GLTF_DOCUMENT_EXTENSION_PHYSICS_H
#include "../gltf_document_extension.h"
#include "gltf_collider.h"
#include "gltf_physics_body.h"
#include "gltf_physics_shape.h"
class GLTFDocumentExtensionPhysics : public GLTFDocumentExtension {
GDCLASS(GLTFDocumentExtensionPhysics, GLTFDocumentExtension);

View file

@ -1,5 +1,5 @@
/**************************************************************************/
/* gltf_collider.cpp */
/* gltf_physics_shape.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "gltf_collider.h"
#include "gltf_physics_shape.h"
#include "../../gltf_state.h"
@ -42,27 +42,27 @@
#include "scene/resources/importer_mesh.h"
#include "scene/resources/sphere_shape_3d.h"
void GLTFCollider::_bind_methods() {
ClassDB::bind_static_method("GLTFCollider", D_METHOD("from_node", "collider_node"), &GLTFCollider::from_node);
ClassDB::bind_method(D_METHOD("to_node", "cache_shapes"), &GLTFCollider::to_node, DEFVAL(false));
void GLTFPhysicsShape::_bind_methods() {
ClassDB::bind_static_method("GLTFPhysicsShape", D_METHOD("from_node", "shape_node"), &GLTFPhysicsShape::from_node);
ClassDB::bind_method(D_METHOD("to_node", "cache_shapes"), &GLTFPhysicsShape::to_node, DEFVAL(false));
ClassDB::bind_static_method("GLTFCollider", D_METHOD("from_dictionary", "dictionary"), &GLTFCollider::from_dictionary);
ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFCollider::to_dictionary);
ClassDB::bind_static_method("GLTFPhysicsShape", D_METHOD("from_dictionary", "dictionary"), &GLTFPhysicsShape::from_dictionary);
ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFPhysicsShape::to_dictionary);
ClassDB::bind_method(D_METHOD("get_shape_type"), &GLTFCollider::get_shape_type);
ClassDB::bind_method(D_METHOD("set_shape_type", "shape_type"), &GLTFCollider::set_shape_type);
ClassDB::bind_method(D_METHOD("get_size"), &GLTFCollider::get_size);
ClassDB::bind_method(D_METHOD("set_size", "size"), &GLTFCollider::set_size);
ClassDB::bind_method(D_METHOD("get_radius"), &GLTFCollider::get_radius);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GLTFCollider::set_radius);
ClassDB::bind_method(D_METHOD("get_height"), &GLTFCollider::get_height);
ClassDB::bind_method(D_METHOD("set_height", "height"), &GLTFCollider::set_height);
ClassDB::bind_method(D_METHOD("get_is_trigger"), &GLTFCollider::get_is_trigger);
ClassDB::bind_method(D_METHOD("set_is_trigger", "is_trigger"), &GLTFCollider::set_is_trigger);
ClassDB::bind_method(D_METHOD("get_mesh_index"), &GLTFCollider::get_mesh_index);
ClassDB::bind_method(D_METHOD("set_mesh_index", "mesh_index"), &GLTFCollider::set_mesh_index);
ClassDB::bind_method(D_METHOD("get_importer_mesh"), &GLTFCollider::get_importer_mesh);
ClassDB::bind_method(D_METHOD("set_importer_mesh", "importer_mesh"), &GLTFCollider::set_importer_mesh);
ClassDB::bind_method(D_METHOD("get_shape_type"), &GLTFPhysicsShape::get_shape_type);
ClassDB::bind_method(D_METHOD("set_shape_type", "shape_type"), &GLTFPhysicsShape::set_shape_type);
ClassDB::bind_method(D_METHOD("get_size"), &GLTFPhysicsShape::get_size);
ClassDB::bind_method(D_METHOD("set_size", "size"), &GLTFPhysicsShape::set_size);
ClassDB::bind_method(D_METHOD("get_radius"), &GLTFPhysicsShape::get_radius);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GLTFPhysicsShape::set_radius);
ClassDB::bind_method(D_METHOD("get_height"), &GLTFPhysicsShape::get_height);
ClassDB::bind_method(D_METHOD("set_height", "height"), &GLTFPhysicsShape::set_height);
ClassDB::bind_method(D_METHOD("get_is_trigger"), &GLTFPhysicsShape::get_is_trigger);
ClassDB::bind_method(D_METHOD("set_is_trigger", "is_trigger"), &GLTFPhysicsShape::set_is_trigger);
ClassDB::bind_method(D_METHOD("get_mesh_index"), &GLTFPhysicsShape::get_mesh_index);
ClassDB::bind_method(D_METHOD("set_mesh_index", "mesh_index"), &GLTFPhysicsShape::set_mesh_index);
ClassDB::bind_method(D_METHOD("get_importer_mesh"), &GLTFPhysicsShape::get_importer_mesh);
ClassDB::bind_method(D_METHOD("set_importer_mesh", "importer_mesh"), &GLTFPhysicsShape::set_importer_mesh);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "shape_type"), "set_shape_type", "get_shape_type");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
@ -73,104 +73,104 @@ void GLTFCollider::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "importer_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ImporterMesh"), "set_importer_mesh", "get_importer_mesh");
}
String GLTFCollider::get_shape_type() const {
String GLTFPhysicsShape::get_shape_type() const {
return shape_type;
}
void GLTFCollider::set_shape_type(String p_shape_type) {
void GLTFPhysicsShape::set_shape_type(String p_shape_type) {
shape_type = p_shape_type;
}
Vector3 GLTFCollider::get_size() const {
Vector3 GLTFPhysicsShape::get_size() const {
return size;
}
void GLTFCollider::set_size(Vector3 p_size) {
void GLTFPhysicsShape::set_size(Vector3 p_size) {
size = p_size;
}
real_t GLTFCollider::get_radius() const {
real_t GLTFPhysicsShape::get_radius() const {
return radius;
}
void GLTFCollider::set_radius(real_t p_radius) {
void GLTFPhysicsShape::set_radius(real_t p_radius) {
radius = p_radius;
}
real_t GLTFCollider::get_height() const {
real_t GLTFPhysicsShape::get_height() const {
return height;
}
void GLTFCollider::set_height(real_t p_height) {
void GLTFPhysicsShape::set_height(real_t p_height) {
height = p_height;
}
bool GLTFCollider::get_is_trigger() const {
bool GLTFPhysicsShape::get_is_trigger() const {
return is_trigger;
}
void GLTFCollider::set_is_trigger(bool p_is_trigger) {
void GLTFPhysicsShape::set_is_trigger(bool p_is_trigger) {
is_trigger = p_is_trigger;
}
GLTFMeshIndex GLTFCollider::get_mesh_index() const {
GLTFMeshIndex GLTFPhysicsShape::get_mesh_index() const {
return mesh_index;
}
void GLTFCollider::set_mesh_index(GLTFMeshIndex p_mesh_index) {
void GLTFPhysicsShape::set_mesh_index(GLTFMeshIndex p_mesh_index) {
mesh_index = p_mesh_index;
}
Ref<ImporterMesh> GLTFCollider::get_importer_mesh() const {
Ref<ImporterMesh> GLTFPhysicsShape::get_importer_mesh() const {
return importer_mesh;
}
void GLTFCollider::set_importer_mesh(Ref<ImporterMesh> p_importer_mesh) {
void GLTFPhysicsShape::set_importer_mesh(Ref<ImporterMesh> p_importer_mesh) {
importer_mesh = p_importer_mesh;
}
Ref<GLTFCollider> GLTFCollider::from_node(const CollisionShape3D *p_collider_node) {
Ref<GLTFCollider> collider;
collider.instantiate();
ERR_FAIL_NULL_V_MSG(p_collider_node, collider, "Tried to create a GLTFCollider from a CollisionShape3D node, but the given node was null.");
Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_node(const CollisionShape3D *p_collider_node) {
Ref<GLTFPhysicsShape> gltf_shape;
gltf_shape.instantiate();
ERR_FAIL_NULL_V_MSG(p_collider_node, gltf_shape, "Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node was null.");
Node *parent = p_collider_node->get_parent();
if (cast_to<const Area3D>(parent)) {
collider->set_is_trigger(true);
gltf_shape->set_is_trigger(true);
}
// All the code for working with the shape is below this comment.
Ref<Shape3D> shape = p_collider_node->get_shape();
ERR_FAIL_COND_V_MSG(shape.is_null(), collider, "Tried to create a GLTFCollider from a CollisionShape3D node, but the given node had a null shape.");
collider->_shape_cache = shape;
if (cast_to<BoxShape3D>(shape.ptr())) {
collider->shape_type = "box";
Ref<BoxShape3D> box = shape;
collider->set_size(box->get_size());
} else if (cast_to<const CapsuleShape3D>(shape.ptr())) {
collider->shape_type = "capsule";
Ref<CapsuleShape3D> capsule = shape;
collider->set_radius(capsule->get_radius());
collider->set_height(capsule->get_height());
} else if (cast_to<const CylinderShape3D>(shape.ptr())) {
collider->shape_type = "cylinder";
Ref<CylinderShape3D> cylinder = shape;
collider->set_radius(cylinder->get_radius());
collider->set_height(cylinder->get_height());
} else if (cast_to<const SphereShape3D>(shape.ptr())) {
collider->shape_type = "sphere";
Ref<SphereShape3D> sphere = shape;
collider->set_radius(sphere->get_radius());
} else if (cast_to<const ConvexPolygonShape3D>(shape.ptr())) {
collider->shape_type = "hull";
Ref<ConvexPolygonShape3D> convex = shape;
Ref<Shape3D> shape_resource = p_collider_node->get_shape();
ERR_FAIL_COND_V_MSG(shape_resource.is_null(), gltf_shape, "Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node had a null shape.");
gltf_shape->_shape_cache = shape_resource;
if (cast_to<BoxShape3D>(shape_resource.ptr())) {
gltf_shape->shape_type = "box";
Ref<BoxShape3D> box = shape_resource;
gltf_shape->set_size(box->get_size());
} else if (cast_to<const CapsuleShape3D>(shape_resource.ptr())) {
gltf_shape->shape_type = "capsule";
Ref<CapsuleShape3D> capsule = shape_resource;
gltf_shape->set_radius(capsule->get_radius());
gltf_shape->set_height(capsule->get_height());
} else if (cast_to<const CylinderShape3D>(shape_resource.ptr())) {
gltf_shape->shape_type = "cylinder";
Ref<CylinderShape3D> cylinder = shape_resource;
gltf_shape->set_radius(cylinder->get_radius());
gltf_shape->set_height(cylinder->get_height());
} else if (cast_to<const SphereShape3D>(shape_resource.ptr())) {
gltf_shape->shape_type = "sphere";
Ref<SphereShape3D> sphere = shape_resource;
gltf_shape->set_radius(sphere->get_radius());
} else if (cast_to<const ConvexPolygonShape3D>(shape_resource.ptr())) {
gltf_shape->shape_type = "hull";
Ref<ConvexPolygonShape3D> convex = shape_resource;
Vector<Vector3> hull_points = convex->get_points();
ERR_FAIL_COND_V_MSG(hull_points.size() < 3, collider, "GLTFCollider: Convex hull has fewer points (" + itos(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(hull_points.size() < 3, gltf_shape, "GLTFPhysicsShape: Convex hull has fewer points (" + itos(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 (hull_points.size() > 255) {
WARN_PRINT("GLTFCollider: Convex hull has more points (" + itos(hull_points.size()) + ") than the recommended maximum of 255. This may not load correctly in other engines.");
WARN_PRINT("GLTFPhysicsShape: Convex hull has more points (" + itos(hull_points.size()) + ") than the recommended maximum of 255. This may not load correctly in other engines.");
}
// Convert the convex hull points into an array of faces.
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(hull_points, md);
ERR_FAIL_COND_V_MSG(err != OK, collider, "GLTFCollider: Failed to compute convex hull.");
ERR_FAIL_COND_V_MSG(err != OK, gltf_shape, "GLTFPhysicsShape: Failed to compute convex hull.");
Vector<Vector3> face_vertices;
for (uint32_t i = 0; i < md.faces.size(); i++) {
uint32_t index_count = md.faces[i].indices.size();
@ -187,26 +187,26 @@ Ref<GLTFCollider> GLTFCollider::from_node(const CollisionShape3D *p_collider_nod
surface_array.resize(Mesh::ArrayType::ARRAY_MAX);
surface_array[Mesh::ArrayType::ARRAY_VERTEX] = face_vertices;
importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array);
collider->set_importer_mesh(importer_mesh);
} else if (cast_to<const ConcavePolygonShape3D>(shape.ptr())) {
collider->shape_type = "trimesh";
Ref<ConcavePolygonShape3D> concave = shape;
gltf_shape->set_importer_mesh(importer_mesh);
} else if (cast_to<const ConcavePolygonShape3D>(shape_resource.ptr())) {
gltf_shape->shape_type = "trimesh";
Ref<ConcavePolygonShape3D> concave = shape_resource;
Ref<ImporterMesh> importer_mesh;
importer_mesh.instantiate();
Array surface_array;
surface_array.resize(Mesh::ArrayType::ARRAY_MAX);
surface_array[Mesh::ArrayType::ARRAY_VERTEX] = concave->get_faces();
importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array);
collider->set_importer_mesh(importer_mesh);
gltf_shape->set_importer_mesh(importer_mesh);
} else {
ERR_PRINT("Tried to create a GLTFCollider from a CollisionShape3D node, but the given node's shape '" + String(Variant(shape)) +
ERR_PRINT("Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node's shape '" + String(Variant(shape_resource)) +
"' had an unsupported shape type. Only BoxShape3D, CapsuleShape3D, CylinderShape3D, SphereShape3D, ConcavePolygonShape3D, and ConvexPolygonShape3D are supported.");
}
return collider;
return gltf_shape;
}
CollisionShape3D *GLTFCollider::to_node(bool p_cache_shapes) {
CollisionShape3D *collider = memnew(CollisionShape3D);
CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) {
CollisionShape3D *gltf_shape = memnew(CollisionShape3D);
if (!p_cache_shapes || _shape_cache == nullptr) {
if (shape_type == "box") {
Ref<BoxShape3D> box;
@ -231,57 +231,57 @@ CollisionShape3D *GLTFCollider::to_node(bool p_cache_shapes) {
sphere->set_radius(radius);
_shape_cache = sphere;
} else if (shape_type == "hull") {
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), collider, "GLTFCollider: Error converting convex hull collider to a node: The mesh resource is null.");
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), gltf_shape, "GLTFPhysicsShape: Error converting convex hull shape to a node: The mesh resource is null.");
Ref<ConvexPolygonShape3D> convex = importer_mesh->get_mesh()->create_convex_shape();
_shape_cache = convex;
} else if (shape_type == "trimesh") {
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), collider, "GLTFCollider: Error converting concave mesh collider to a node: The mesh resource is null.");
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), gltf_shape, "GLTFPhysicsShape: Error converting concave mesh shape to a node: The mesh resource is null.");
Ref<ConcavePolygonShape3D> concave = importer_mesh->create_trimesh_shape();
_shape_cache = concave;
} else {
ERR_PRINT("GLTFCollider: Error converting to a node: Shape type '" + shape_type + "' is unknown.");
ERR_PRINT("GLTFPhysicsShape: Error converting to a node: Shape type '" + shape_type + "' is unknown.");
}
}
collider->set_shape(_shape_cache);
return collider;
gltf_shape->set_shape(_shape_cache);
return gltf_shape;
}
Ref<GLTFCollider> GLTFCollider::from_dictionary(const Dictionary p_dictionary) {
ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFCollider>(), "Failed to parse GLTF collider, missing required field 'type'.");
Ref<GLTFCollider> collider;
collider.instantiate();
Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_dictionary(const Dictionary p_dictionary) {
ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFPhysicsShape>(), "Failed to parse GLTFPhysicsShape, missing required field 'type'.");
Ref<GLTFPhysicsShape> gltf_shape;
gltf_shape.instantiate();
const String &shape_type = p_dictionary["type"];
collider->shape_type = shape_type;
gltf_shape->shape_type = shape_type;
if (shape_type != "box" && shape_type != "capsule" && shape_type != "cylinder" && shape_type != "sphere" && shape_type != "hull" && shape_type != "trimesh") {
ERR_PRINT("Error parsing GLTF collider: Shape type '" + shape_type + "' is unknown. Only box, capsule, cylinder, sphere, hull, and trimesh are supported.");
ERR_PRINT("GLTFPhysicsShape: Error parsing unknown shape type '" + shape_type + "'. Only box, capsule, cylinder, sphere, hull, and trimesh are supported.");
}
if (p_dictionary.has("radius")) {
collider->set_radius(p_dictionary["radius"]);
gltf_shape->set_radius(p_dictionary["radius"]);
}
if (p_dictionary.has("height")) {
collider->set_height(p_dictionary["height"]);
gltf_shape->set_height(p_dictionary["height"]);
}
if (p_dictionary.has("size")) {
const Array &arr = p_dictionary["size"];
if (arr.size() == 3) {
collider->set_size(Vector3(arr[0], arr[1], arr[2]));
gltf_shape->set_size(Vector3(arr[0], arr[1], arr[2]));
} else {
ERR_PRINT("Error parsing GLTF collider: The size must have exactly 3 numbers.");
ERR_PRINT("GLTFPhysicsShape: Error parsing the size, it must have exactly 3 numbers.");
}
}
if (p_dictionary.has("isTrigger")) {
collider->set_is_trigger(p_dictionary["isTrigger"]);
gltf_shape->set_is_trigger(p_dictionary["isTrigger"]);
}
if (p_dictionary.has("mesh")) {
collider->set_mesh_index(p_dictionary["mesh"]);
gltf_shape->set_mesh_index(p_dictionary["mesh"]);
}
if (unlikely(collider->get_mesh_index() < 0 && (shape_type == "hull" || shape_type == "trimesh"))) {
ERR_PRINT("Error parsing GLTF collider: The mesh-based shape type '" + shape_type + "' does not have a valid mesh index.");
if (unlikely(gltf_shape->get_mesh_index() < 0 && (shape_type == "hull" || shape_type == "trimesh"))) {
ERR_PRINT("Error parsing GLTFPhysicsShape: The mesh-based shape type '" + shape_type + "' does not have a valid mesh index.");
}
return collider;
return gltf_shape;
}
Dictionary GLTFCollider::to_dictionary() const {
Dictionary GLTFPhysicsShape::to_dictionary() const {
Dictionary d;
d["type"] = shape_type;
if (shape_type == "box") {

View file

@ -1,5 +1,5 @@
/**************************************************************************/
/* gltf_collider.h */
/* gltf_physics_shape.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GLTF_COLLIDER_H
#define GLTF_COLLIDER_H
#ifndef GLTF_PHYSICS_SHAPE_H
#define GLTF_PHYSICS_SHAPE_H
#include "../../gltf_defines.h"
@ -37,11 +37,11 @@
class ImporterMesh;
// GLTFCollider is an intermediary between OMI_collider and Godot's collision shape nodes.
// GLTFPhysicsShape is an intermediary between OMI_collider and Godot's collision shape nodes.
// https://github.com/omigroup/gltf-extensions/tree/main/extensions/2.0/OMI_collider
class GLTFCollider : public Resource {
GDCLASS(GLTFCollider, Resource)
class GLTFPhysicsShape : public Resource {
GDCLASS(GLTFPhysicsShape, Resource)
protected:
static void _bind_methods();
@ -79,11 +79,11 @@ public:
Ref<ImporterMesh> get_importer_mesh() const;
void set_importer_mesh(Ref<ImporterMesh> p_importer_mesh);
static Ref<GLTFCollider> from_node(const CollisionShape3D *p_collider_node);
static Ref<GLTFPhysicsShape> from_node(const CollisionShape3D *p_shape_node);
CollisionShape3D *to_node(bool p_cache_shapes = false);
static Ref<GLTFCollider> from_dictionary(const Dictionary p_dictionary);
static Ref<GLTFPhysicsShape> from_dictionary(const Dictionary p_dictionary);
Dictionary to_dictionary() const;
};
#endif // GLTF_COLLIDER_H
#endif // GLTF_PHYSICS_SHAPE_H

View file

@ -117,7 +117,6 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(GLTFAnimation);
GDREGISTER_CLASS(GLTFBufferView);
GDREGISTER_CLASS(GLTFCamera);
GDREGISTER_CLASS(GLTFCollider);
GDREGISTER_CLASS(GLTFDocument);
GDREGISTER_CLASS(GLTFDocumentExtension);
GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
@ -125,6 +124,7 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(GLTFMesh);
GDREGISTER_CLASS(GLTFNode);
GDREGISTER_CLASS(GLTFPhysicsBody);
GDREGISTER_CLASS(GLTFPhysicsShape);
GDREGISTER_CLASS(GLTFSkeleton);
GDREGISTER_CLASS(GLTFSkin);
GDREGISTER_CLASS(GLTFSpecGloss);