Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate Shape3D resource logic in GLTFPhysicsShape #90230

Merged
merged 1 commit into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/gltf/doc_classes/GLTFPhysicsBody.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<return type="GLTFPhysicsBody" />
<param index="0" name="body_node" type="CollisionObject3D" />
<description>
Create a new GLTFPhysicsBody instance from the given Godot [CollisionObject3D] node.
Creates a new GLTFPhysicsBody instance from the given Godot [CollisionObject3D] node.
</description>
</method>
<method name="to_dictionary" qualifiers="const">
Expand Down
16 changes: 15 additions & 1 deletion modules/gltf/doc_classes/GLTFPhysicsShape.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@
<return type="GLTFPhysicsShape" />
<param index="0" name="shape_node" type="CollisionShape3D" />
<description>
Create a new GLTFPhysicsShape instance from the given Godot [CollisionShape3D] node.
Creates a new GLTFPhysicsShape instance from the given Godot [CollisionShape3D] node.
</description>
</method>
<method name="from_resource" qualifiers="static">
<return type="GLTFPhysicsShape" />
<param index="0" name="shape_resource" type="Shape3D" />
<description>
Creates a new GLTFPhysicsShape instance from the given Godot [Shape3D] resource.
</description>
</method>
<method name="to_dictionary" qualifiers="const">
Expand All @@ -39,6 +46,13 @@
Converts this GLTFPhysicsShape instance into a Godot [CollisionShape3D] node.
</description>
</method>
<method name="to_resource">
<return type="Shape3D" />
<param index="0" name="cache_shapes" type="bool" default="false" />
<description>
Converts this GLTFPhysicsShape instance into a Godot [Shape3D] resource.
</description>
</method>
</methods>
<members>
<member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,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?");
{
Ref<ImporterMesh> importer_mesh = gltf_shape->get_importer_mesh();
if (importer_mesh.is_valid()) {
Expand Down
65 changes: 40 additions & 25 deletions modules/gltf/extensions/physics/gltf_physics_shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ 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("GLTFPhysicsShape", D_METHOD("from_resource", "shape_resource"), &GLTFPhysicsShape::from_resource);
ClassDB::bind_method(D_METHOD("to_resource", "cache_shapes"), &GLTFPhysicsShape::to_resource, DEFVAL(false));

ClassDB::bind_static_method("GLTFPhysicsShape", D_METHOD("from_dictionary", "dictionary"), &GLTFPhysicsShape::from_dictionary);
ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFPhysicsShape::to_dictionary);

Expand Down Expand Up @@ -159,44 +162,57 @@ Ref<ImporterMesh> _convert_hull_points_to_mesh(const Vector<Vector3> &p_hull_poi

Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_node(const CollisionShape3D *p_godot_shape_node) {
Ref<GLTFPhysicsShape> gltf_shape;
gltf_shape.instantiate();
ERR_FAIL_NULL_V_MSG(p_godot_shape_node, gltf_shape, "Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node was null.");
Ref<Shape3D> shape_resource = p_godot_shape_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 = from_resource(shape_resource);
// Check if the shape is part of a trigger.
Node *parent = p_godot_shape_node->get_parent();
if (cast_to<const Area3D>(parent)) {
gltf_shape->set_is_trigger(true);
}
// All the code for working with the shape is below this comment.
Ref<Shape3D> shape_resource = p_godot_shape_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())) {
return gltf_shape;
}

CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) {
CollisionShape3D *godot_shape_node = memnew(CollisionShape3D);
to_resource(p_cache_shapes); // Sets `_shape_cache`.
godot_shape_node->set_shape(_shape_cache);
return godot_shape_node;
}

Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_resource(const Ref<Shape3D> &p_shape_resource) {
Ref<GLTFPhysicsShape> gltf_shape;
gltf_shape.instantiate();
ERR_FAIL_COND_V_MSG(p_shape_resource.is_null(), gltf_shape, "Tried to create a GLTFPhysicsShape from a Shape3D resource, but the given resource was null.");
if (cast_to<BoxShape3D>(p_shape_resource.ptr())) {
gltf_shape->shape_type = "box";
Ref<BoxShape3D> box = shape_resource;
Ref<BoxShape3D> box = p_shape_resource;
gltf_shape->set_size(box->get_size());
} else if (cast_to<const CapsuleShape3D>(shape_resource.ptr())) {
} else if (cast_to<const CapsuleShape3D>(p_shape_resource.ptr())) {
gltf_shape->shape_type = "capsule";
Ref<CapsuleShape3D> capsule = shape_resource;
Ref<CapsuleShape3D> capsule = p_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())) {
} else if (cast_to<const CylinderShape3D>(p_shape_resource.ptr())) {
gltf_shape->shape_type = "cylinder";
Ref<CylinderShape3D> cylinder = shape_resource;
Ref<CylinderShape3D> cylinder = p_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())) {
} else if (cast_to<const SphereShape3D>(p_shape_resource.ptr())) {
gltf_shape->shape_type = "sphere";
Ref<SphereShape3D> sphere = shape_resource;
Ref<SphereShape3D> sphere = p_shape_resource;
gltf_shape->set_radius(sphere->get_radius());
} else if (cast_to<const ConvexPolygonShape3D>(shape_resource.ptr())) {
} else if (cast_to<const ConvexPolygonShape3D>(p_shape_resource.ptr())) {
gltf_shape->shape_type = "convex";
Ref<ConvexPolygonShape3D> convex = shape_resource;
Ref<ConvexPolygonShape3D> convex = p_shape_resource;
Vector<Vector3> hull_points = convex->get_points();
Ref<ImporterMesh> importer_mesh = _convert_hull_points_to_mesh(hull_points);
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), gltf_shape, "GLTFPhysicsShape: Failed to convert convex hull points to a mesh.");
gltf_shape->set_importer_mesh(importer_mesh);
} else if (cast_to<const ConcavePolygonShape3D>(shape_resource.ptr())) {
} else if (cast_to<const ConcavePolygonShape3D>(p_shape_resource.ptr())) {
gltf_shape->shape_type = "trimesh";
Ref<ConcavePolygonShape3D> concave = shape_resource;
Ref<ConcavePolygonShape3D> concave = p_shape_resource;
Ref<ImporterMesh> importer_mesh;
importer_mesh.instantiate();
Array surface_array;
Expand All @@ -205,14 +221,14 @@ Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_node(const CollisionShape3D *p_godo
importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array);
gltf_shape->set_importer_mesh(importer_mesh);
} else {
ERR_PRINT("Tried to create a GLTFPhysicsShape from a CollisionShape3D node, but the given node's shape '" + String(Variant(shape_resource)) +
ERR_PRINT("Tried to create a GLTFPhysicsShape from a Shape3D, but the given shape '" + String(Variant(p_shape_resource)) +
"' had an unsupported shape type. Only BoxShape3D, CapsuleShape3D, CylinderShape3D, SphereShape3D, ConcavePolygonShape3D, and ConvexPolygonShape3D are supported.");
}
gltf_shape->_shape_cache = p_shape_resource;
return gltf_shape;
}

CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) {
CollisionShape3D *godot_shape_node = memnew(CollisionShape3D);
Ref<Shape3D> GLTFPhysicsShape::to_resource(bool p_cache_shapes) {
if (!p_cache_shapes || _shape_cache == nullptr) {
if (shape_type == "box") {
Ref<BoxShape3D> box;
Expand All @@ -237,19 +253,18 @@ CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) {
sphere->set_radius(radius);
_shape_cache = sphere;
} else if (shape_type == "convex") {
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), godot_shape_node, "GLTFPhysicsShape: Error converting convex hull shape to a node: The mesh resource is null.");
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), _shape_cache, "GLTFPhysicsShape: Error converting convex hull shape to a shape resource: 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(), godot_shape_node, "GLTFPhysicsShape: Error converting concave mesh shape to a node: The mesh resource is null.");
ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), _shape_cache, "GLTFPhysicsShape: Error converting concave mesh shape to a shape resource: The mesh resource is null.");
Ref<ConcavePolygonShape3D> concave = importer_mesh->create_trimesh_shape();
_shape_cache = concave;
} else {
ERR_PRINT("GLTFPhysicsShape: Error converting to a node: Shape type '" + shape_type + "' is unknown.");
ERR_PRINT("GLTFPhysicsShape: Error converting to a shape resource: Shape type '" + shape_type + "' is unknown.");
}
}
godot_shape_node->set_shape(_shape_cache);
return godot_shape_node;
return _shape_cache;
}

Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_dictionary(const Dictionary p_dictionary) {
Expand Down
5 changes: 4 additions & 1 deletion modules/gltf/extensions/physics/gltf_physics_shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class GLTFPhysicsShape : public Resource {
bool is_trigger = false;
GLTFMeshIndex mesh_index = -1;
Ref<ImporterMesh> importer_mesh = nullptr;
// Internal only, for caching Godot shape resources. Used in `to_node`.
// Internal only, for caching Godot shape resources. Used in `to_resource` and `to_node`.
Ref<Shape3D> _shape_cache = nullptr;

public:
Expand Down Expand Up @@ -83,6 +83,9 @@ class GLTFPhysicsShape : public Resource {
static Ref<GLTFPhysicsShape> from_node(const CollisionShape3D *p_shape_node);
CollisionShape3D *to_node(bool p_cache_shapes = false);

static Ref<GLTFPhysicsShape> from_resource(const Ref<Shape3D> &p_shape_resource);
Ref<Shape3D> to_resource(bool p_cache_shapes = false);

static Ref<GLTFPhysicsShape> from_dictionary(const Dictionary p_dictionary);
Dictionary to_dictionary() const;
};
Expand Down
Loading