1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-14 13:41:12 +00:00

Separate Shape3D resource logic in GLTFPhysicsShape

This commit is contained in:
Aaron Franke
2024-04-04 03:54:33 -07:00
parent 79de2eaae7
commit 92b243dc3c
5 changed files with 61 additions and 28 deletions

View File

@@ -22,7 +22,7 @@
<return type="GLTFPhysicsBody" /> <return type="GLTFPhysicsBody" />
<param index="0" name="body_node" type="CollisionObject3D" /> <param index="0" name="body_node" type="CollisionObject3D" />
<description> <description>
Create a new GLTFPhysicsBody instance from the given Godot [CollisionObject3D] node. Creates a new GLTFPhysicsBody instance from the given Godot [CollisionObject3D] node.
</description> </description>
</method> </method>
<method name="to_dictionary" qualifiers="const"> <method name="to_dictionary" qualifiers="const">

View File

@@ -23,7 +23,14 @@
<return type="GLTFPhysicsShape" /> <return type="GLTFPhysicsShape" />
<param index="0" name="shape_node" type="CollisionShape3D" /> <param index="0" name="shape_node" type="CollisionShape3D" />
<description> <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> </description>
</method> </method>
<method name="to_dictionary" qualifiers="const"> <method name="to_dictionary" qualifiers="const">
@@ -39,6 +46,13 @@
Converts this GLTFPhysicsShape instance into a Godot [CollisionShape3D] node. Converts this GLTFPhysicsShape instance into a Godot [CollisionShape3D] node.
</description> </description>
</method> </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> </methods>
<members> <members>
<member name="height" type="float" setter="set_height" getter="get_height" default="2.0"> <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">

View File

@@ -355,6 +355,7 @@ void GLTFDocumentExtensionPhysics::convert_scene_node(Ref<GLTFState> p_state, Re
if (cast_to<CollisionShape3D>(p_scene_node)) { if (cast_to<CollisionShape3D>(p_scene_node)) {
CollisionShape3D *godot_shape = Object::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); 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(); Ref<ImporterMesh> importer_mesh = gltf_shape->get_importer_mesh();
if (importer_mesh.is_valid()) { if (importer_mesh.is_valid()) {

View File

@@ -46,6 +46,9 @@ void GLTFPhysicsShape::_bind_methods() {
ClassDB::bind_static_method("GLTFPhysicsShape", D_METHOD("from_node", "shape_node"), &GLTFPhysicsShape::from_node); 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_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_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("to_dictionary"), &GLTFPhysicsShape::to_dictionary);
@@ -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> GLTFPhysicsShape::from_node(const CollisionShape3D *p_godot_shape_node) {
Ref<GLTFPhysicsShape> gltf_shape; 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."); 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(); Node *parent = p_godot_shape_node->get_parent();
if (cast_to<const Area3D>(parent)) { if (cast_to<const Area3D>(parent)) {
gltf_shape->set_is_trigger(true); gltf_shape->set_is_trigger(true);
} }
// All the code for working with the shape is below this comment. return gltf_shape;
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; CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) {
if (cast_to<BoxShape3D>(shape_resource.ptr())) { 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"; gltf_shape->shape_type = "box";
Ref<BoxShape3D> box = shape_resource; Ref<BoxShape3D> box = p_shape_resource;
gltf_shape->set_size(box->get_size()); 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"; 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_radius(capsule->get_radius());
gltf_shape->set_height(capsule->get_height()); 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"; 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_radius(cylinder->get_radius());
gltf_shape->set_height(cylinder->get_height()); 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"; gltf_shape->shape_type = "sphere";
Ref<SphereShape3D> sphere = shape_resource; Ref<SphereShape3D> sphere = p_shape_resource;
gltf_shape->set_radius(sphere->get_radius()); 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"; gltf_shape->shape_type = "convex";
Ref<ConvexPolygonShape3D> convex = shape_resource; Ref<ConvexPolygonShape3D> convex = p_shape_resource;
Vector<Vector3> hull_points = convex->get_points(); Vector<Vector3> hull_points = convex->get_points();
Ref<ImporterMesh> importer_mesh = _convert_hull_points_to_mesh(hull_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."); 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); 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"; gltf_shape->shape_type = "trimesh";
Ref<ConcavePolygonShape3D> concave = shape_resource; Ref<ConcavePolygonShape3D> concave = p_shape_resource;
Ref<ImporterMesh> importer_mesh; Ref<ImporterMesh> importer_mesh;
importer_mesh.instantiate(); importer_mesh.instantiate();
Array surface_array; Array surface_array;
@@ -205,14 +221,14 @@ Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_node(const CollisionShape3D *p_godo
importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array); importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array);
gltf_shape->set_importer_mesh(importer_mesh); gltf_shape->set_importer_mesh(importer_mesh);
} else { } 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."); "' 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; return gltf_shape;
} }
CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) { Ref<Shape3D> GLTFPhysicsShape::to_resource(bool p_cache_shapes) {
CollisionShape3D *godot_shape_node = memnew(CollisionShape3D);
if (!p_cache_shapes || _shape_cache == nullptr) { if (!p_cache_shapes || _shape_cache == nullptr) {
if (shape_type == "box") { if (shape_type == "box") {
Ref<BoxShape3D> box; Ref<BoxShape3D> box;
@@ -237,19 +253,18 @@ CollisionShape3D *GLTFPhysicsShape::to_node(bool p_cache_shapes) {
sphere->set_radius(radius); sphere->set_radius(radius);
_shape_cache = sphere; _shape_cache = sphere;
} else if (shape_type == "convex") { } 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(); Ref<ConvexPolygonShape3D> convex = importer_mesh->get_mesh()->create_convex_shape();
_shape_cache = convex; _shape_cache = convex;
} else if (shape_type == "trimesh") { } 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(); Ref<ConcavePolygonShape3D> concave = importer_mesh->create_trimesh_shape();
_shape_cache = concave; _shape_cache = concave;
} else { } 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 _shape_cache;
return godot_shape_node;
} }
Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_dictionary(const Dictionary p_dictionary) { Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_dictionary(const Dictionary p_dictionary) {

View File

@@ -55,7 +55,7 @@ private:
bool is_trigger = false; bool is_trigger = false;
GLTFMeshIndex mesh_index = -1; GLTFMeshIndex mesh_index = -1;
Ref<ImporterMesh> importer_mesh = nullptr; 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; Ref<Shape3D> _shape_cache = nullptr;
public: public:
@@ -83,6 +83,9 @@ public:
static Ref<GLTFPhysicsShape> from_node(const CollisionShape3D *p_shape_node); static Ref<GLTFPhysicsShape> from_node(const CollisionShape3D *p_shape_node);
CollisionShape3D *to_node(bool p_cache_shapes = false); 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); static Ref<GLTFPhysicsShape> from_dictionary(const Dictionary p_dictionary);
Dictionary to_dictionary() const; Dictionary to_dictionary() const;
}; };