feat: updated engine

This commit is contained in:
Sara Gerretsen 2026-07-10 17:04:34 +02:00
parent cbe99774ff
commit f4cf6b3999
6607 changed files with 910135 additions and 430025 deletions

View file

@ -30,18 +30,28 @@
#include "csg_shape.h"
#include "core/config/engine.h"
#include "core/math/geometry_2d.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
#include "scene/resources/navigation_mesh.h"
#include "scene/resources/surface_tool.h"
#include "servers/rendering/rendering_server.h"
#ifdef DEV_ENABLED
#include "core/io/json.h"
#endif // DEV_ENABLED
#include "core/math/geometry_2d.h"
#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h"
#include "scene/resources/navigation_mesh.h"
#ifndef NAVIGATION_3D_DISABLED
#include "servers/navigation_3d/navigation_server_3d.h"
#endif // NAVIGATION_3D_DISABLED
#include <manifold/manifold.h>
#include <cfloat> // FLT_EPSILON
#ifndef NAVIGATION_3D_DISABLED
Callable CSGShape3D::_navmesh_source_geometry_parsing_callback;
RID CSGShape3D::_navmesh_source_geometry_parser;
@ -95,22 +105,23 @@ void CSGShape3D::set_use_collision(bool p_enable) {
if (use_collision) {
root_collision_shape.instantiate();
root_collision_instance = PhysicsServer3D::get_singleton()->body_create();
PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space());
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
root_collision_body = PhysicsServer3D::get_singleton()->body_create();
PhysicsServer3D::get_singleton()->body_set_mode(root_collision_body, PS3DE::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_state(root_collision_body, PS3DE::BODY_STATE_TRANSFORM, get_global_transform());
PhysicsServer3D::get_singleton()->body_add_shape(root_collision_body, root_collision_shape->get_rid());
PhysicsServer3D::get_singleton()->body_set_space(root_collision_body, get_world_3d()->get_space());
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_body, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
set_collision_priority(collision_priority);
_make_dirty(); //force update
} else {
PhysicsServer3D::get_singleton()->free_rid(root_collision_instance);
root_collision_instance = RID();
PhysicsServer3D::get_singleton()->free_rid(root_collision_body);
root_collision_body = RID();
root_collision_shape.unref();
}
notify_property_list_changed();
update_gizmos();
}
bool CSGShape3D::is_using_collision() const {
@ -119,8 +130,8 @@ bool CSGShape3D::is_using_collision() const {
void CSGShape3D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
if (root_collision_instance.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_collision_layer(root_collision_instance, p_layer);
if (root_collision_body.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_collision_layer(root_collision_body, p_layer);
}
}
@ -130,8 +141,8 @@ uint32_t CSGShape3D::get_collision_layer() const {
void CSGShape3D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
if (root_collision_instance.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_collision_mask(root_collision_instance, p_mask);
if (root_collision_body.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_collision_mask(root_collision_body, p_mask);
}
}
@ -176,8 +187,8 @@ bool CSGShape3D::get_collision_mask_value(int p_layer_number) const {
}
RID CSGShape3D::_get_root_collision_instance() const {
if (root_collision_instance.is_valid()) {
return root_collision_instance;
if (root_collision_body.is_valid()) {
return root_collision_body;
} else if (parent_shape) {
return parent_shape->_get_root_collision_instance();
}
@ -187,14 +198,34 @@ RID CSGShape3D::_get_root_collision_instance() const {
void CSGShape3D::set_collision_priority(real_t p_priority) {
collision_priority = p_priority;
if (root_collision_instance.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_collision_priority(root_collision_instance, p_priority);
if (root_collision_body.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_collision_priority(root_collision_body, p_priority);
}
}
real_t CSGShape3D::get_collision_priority() const {
return collision_priority;
}
void CSGShape3D::set_autosmooth(bool p_smooth) {
autosmooth = p_smooth;
_make_dirty();
notify_property_list_changed();
}
bool CSGShape3D::is_autosmooth() const {
return autosmooth;
}
void CSGShape3D::set_smoothing_angle(const float p_angle) {
smoothing_angle = p_angle;
_make_dirty();
}
float CSGShape3D::get_smoothing_angle() const {
return smoothing_angle;
}
#endif // PHYSICS_3D_DISABLED
bool CSGShape3D::is_root_shape() const {
@ -511,58 +542,42 @@ CSGBrush *CSGShape3D::_get_brush() {
return brush;
}
int CSGShape3D::mikktGetNumFaces(const SMikkTSpaceContext *pContext) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
static void _generate_tangents_unindexed(float *p_tangents, size_t p_count, const Vector3 *p_positions, const Vector3 *p_normals, const Vector2 *p_uvs) {
ERR_FAIL_COND_MSG(!SurfaceTool::generate_tangents_func, "Meshoptimizer library is not initialized.");
ERR_FAIL_COND(p_count % 3 != 0);
return surface.vertices.size() / 3;
}
if (p_count == 0) {
return;
}
int CSGShape3D::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) {
// always 3
return 3;
}
struct TangentVertex {
float position[3];
float normal[3];
float uv[2];
};
void CSGShape3D::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
// We can't operate on input arrays directly because in double-precision builds, vectors use double components
// So we convert the inputs to single precision floats before generating tangents.
LocalVector<TangentVertex> tangent_vertices;
tangent_vertices.resize(p_count);
Vector3 v = surface.verticesw[iFace * 3 + iVert];
fvPosOut[0] = v.x;
fvPosOut[1] = v.y;
fvPosOut[2] = v.z;
}
for (size_t i = 0; i < p_count; i++) {
TangentVertex &tangent_vertex = tangent_vertices[i];
void CSGShape3D::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
tangent_vertex.position[0] = p_positions[i].x;
tangent_vertex.position[1] = p_positions[i].y;
tangent_vertex.position[2] = p_positions[i].z;
tangent_vertex.normal[0] = p_normals[i].x;
tangent_vertex.normal[1] = p_normals[i].y;
tangent_vertex.normal[2] = p_normals[i].z;
tangent_vertex.uv[0] = p_uvs[i].x;
tangent_vertex.uv[1] = p_uvs[i].y;
}
Vector3 n = surface.normalsw[iFace * 3 + iVert];
fvNormOut[0] = n.x;
fvNormOut[1] = n.y;
fvNormOut[2] = n.z;
}
void CSGShape3D::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
Vector2 t = surface.uvsw[iFace * 3 + iVert];
fvTexcOut[0] = t.x;
fvTexcOut[1] = t.y;
}
void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
int i = iFace * 3 + iVert;
Vector3 normal = surface.normalsw[i];
Vector3 tangent = Vector3(fvTangent[0], fvTangent[1], fvTangent[2]);
Vector3 bitangent = Vector3(-fvBiTangent[0], -fvBiTangent[1], -fvBiTangent[2]); // for some reason these are reversed, something with the coordinate system in Godot
float d = bitangent.dot(normal.cross(tangent));
i *= 4;
surface.tansw[i++] = tangent.x;
surface.tansw[i++] = tangent.y;
surface.tansw[i++] = tangent.z;
surface.tansw[i++] = d < 0 ? -1 : 1;
SurfaceTool::generate_tangents_func(p_tangents, nullptr, p_count,
tangent_vertices.ptr()->position, p_count, sizeof(TangentVertex),
tangent_vertices.ptr()->normal, sizeof(TangentVertex),
tangent_vertices.ptr()->uv, sizeof(TangentVertex), 0);
}
void CSGShape3D::update_shape() {
@ -576,112 +591,17 @@ void CSGShape3D::update_shape() {
CSGBrush *n = _get_brush();
ERR_FAIL_NULL_MSG(n, "Cannot get CSGBrush.");
AHashMap<Vector3, Vector3> vec_map;
Vector<int> face_count;
face_count.resize(n->materials.size() + 1);
for (int i = 0; i < face_count.size(); i++) {
face_count.write[i] = 0;
}
for (int i = 0; i < n->faces.size(); i++) {
int mat = n->faces[i].material;
ERR_CONTINUE(mat < -1 || mat >= face_count.size());
int idx = mat == -1 ? face_count.size() - 1 : mat;
if (n->faces[i].smooth) {
Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]);
for (int j = 0; j < 3; j++) {
Vector3 v = n->faces[i].vertices[j];
Vector3 *vec = vec_map.getptr(v);
if (vec) {
*vec += p.normal;
} else {
vec_map.insert(v, p.normal);
}
}
}
face_count.write[idx]++;
}
face_count.fill(0);
Vector<ShapeUpdateSurface> surfaces;
surfaces.resize(face_count.size());
//create arrays
for (int i = 0; i < surfaces.size(); i++) {
surfaces.write[i].vertices.resize(face_count[i] * 3);
surfaces.write[i].normals.resize(face_count[i] * 3);
surfaces.write[i].uvs.resize(face_count[i] * 3);
if (calculate_tangents) {
surfaces.write[i].tans.resize(face_count[i] * 3 * 4);
}
surfaces.write[i].last_added = 0;
if (i != surfaces.size() - 1) {
surfaces.write[i].material = n->materials[i];
}
surfaces.write[i].verticesw = surfaces.write[i].vertices.ptrw();
surfaces.write[i].normalsw = surfaces.write[i].normals.ptrw();
surfaces.write[i].uvsw = surfaces.write[i].uvs.ptrw();
if (calculate_tangents) {
surfaces.write[i].tansw = surfaces.write[i].tans.ptrw();
}
}
//fill arrays
{
for (int i = 0; i < n->faces.size(); i++) {
int order[3] = { 0, 1, 2 };
if (n->faces[i].invert) {
SWAP(order[1], order[2]);
}
int mat = n->faces[i].material;
ERR_CONTINUE(mat < -1 || mat >= face_count.size());
int idx = mat == -1 ? face_count.size() - 1 : mat;
int last = surfaces[idx].last_added;
Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]);
for (int j = 0; j < 3; j++) {
Vector3 v = n->faces[i].vertices[j];
Vector3 normal = p.normal;
if (n->faces[i].smooth) {
Vector3 *ptr = vec_map.getptr(v);
if (ptr) {
normal = ptr->normalized();
}
}
if (n->faces[i].invert) {
normal = -normal;
}
int k = last + order[j];
surfaces[idx].verticesw[k] = v;
surfaces[idx].uvsw[k] = n->faces[i].uvs[j];
surfaces[idx].normalsw[k] = normal;
if (calculate_tangents) {
// zero out our tangents for now
k *= 4;
surfaces[idx].tansw[k++] = 0.0;
surfaces[idx].tansw[k++] = 0.0;
surfaces[idx].tansw[k++] = 0.0;
surfaces[idx].tansw[k++] = 0.0;
}
}
surfaces.write[idx].last_added += 3;
}
if (autosmooth) {
_build_surfaces_smoothed(n, surfaces, face_count);
} else {
_build_surfaces_default(n, surfaces, face_count);
}
root_mesh.instantiate();
@ -689,21 +609,11 @@ void CSGShape3D::update_shape() {
for (int i = 0; i < surfaces.size(); i++) {
// calculate tangents for this surface
bool have_tangents = calculate_tangents;
bool have_tangents = calculate_tangents && SurfaceTool::generate_tangents_func;
if (have_tangents) {
SMikkTSpaceInterface mkif;
mkif.m_getNormal = mikktGetNormal;
mkif.m_getNumFaces = mikktGetNumFaces;
mkif.m_getNumVerticesOfFace = mikktGetNumVerticesOfFace;
mkif.m_getPosition = mikktGetPosition;
mkif.m_getTexCoord = mikktGetTexCoord;
mkif.m_setTSpace = mikktSetTSpaceDefault;
mkif.m_setTSpaceBasic = nullptr;
ShapeUpdateSurface &surface = surfaces.write[i];
SMikkTSpaceContext msc;
msc.m_pInterface = &mkif;
msc.m_pUserData = &surfaces.write[i];
have_tangents = genTangSpaceDefault(&msc);
_generate_tangents_unindexed(surface.tansw, surface.vertices.size(), surface.verticesw, surface.normalsw, surface.uvsw);
}
if (surfaces[i].last_added == 0) {
@ -728,11 +638,238 @@ void CSGShape3D::update_shape() {
set_base(root_mesh->get_rid());
update_gizmos();
#ifndef PHYSICS_3D_DISABLED
_update_collision_faces();
#endif // PHYSICS_3D_DISABLED
}
void CSGShape3D::_build_surfaces_smoothed(CSGBrush *p_brush, Vector<CSGShape3D::ShapeUpdateSurface> &r_surfaces, Vector<int> &r_face_count) {
Vector<Vector3> smooth_faces;
LocalVector<Vector3> smooth_vertex;
smooth_faces.resize(p_brush->faces.size());
smooth_vertex.resize(p_brush->faces.size() * 3);
Vector3 *smooth_faces_ptrw = smooth_faces.ptrw();
int *face_count_ptrw = r_face_count.ptrw();
for (int i = 0; i < p_brush->faces.size(); i++) {
int mat = p_brush->faces[i].material;
ERR_CONTINUE(mat < -1 || mat >= r_face_count.size());
int idx = mat == -1 ? r_face_count.size() - 1 : mat;
Plane p(p_brush->faces[i].vertices[0], p_brush->faces[i].vertices[1], p_brush->faces[i].vertices[2]);
smooth_faces_ptrw[i] = p.normal;
// Not sure if resize populates the LocalVector.
smooth_vertex[i * 3 + 0] = Vector3(p.normal);
smooth_vertex[i * 3 + 1] = Vector3(p.normal);
smooth_vertex[i * 3 + 2] = Vector3(p.normal);
// We could use a AHashMap Vector3, int to store the number of connections of each vertex position and end the loop earlier. But I'm not sure if the performance gains outweigh the cost.
face_count_ptrw[idx]++;
}
const Vector3 *smooth_faces_ptr = smooth_faces.ptr();
const int smooth_faces_size = smooth_faces.size();
// We could add a `use_groups` property later to only apply autosmooth on smooth faces or respect smoothing groups in some way.
if (smoothing_angle > 0.1) {
float smooth_angle_rad = Math::cos(Math::deg_to_rad(smoothing_angle));
for (int i = 0; i < smooth_faces_size; i++) {
for (int k = 0; k < 3; k++) {
int curr_vert = i * 3 + k;
// Skip the other vertices of the face as they will never occupy the same position.
Vector3 vert_a = p_brush->faces[i].vertices[k];
for (int j = i + 1; j < smooth_faces_size; j++) {
// Compare the angles of faces instead of vertices.
if (smooth_faces_ptr[i].dot(smooth_faces_ptr[j]) > smooth_angle_rad) {
for (int h = 0; h < 3; h++) {
Vector3 vert_b = p_brush->faces[j].vertices[h];
if (vert_a == vert_b) {
int curr_j = j * 3 + h;
smooth_vertex[curr_vert] += smooth_faces_ptr[j];
smooth_vertex[curr_j] += smooth_faces_ptr[i];
// Skip the other 2 vertices as only one vertex of each face can connect with one vertex of other face.
break;
}
}
}
}
smooth_vertex[curr_vert].normalize();
}
}
}
//create arrays
for (int i = 0; i < r_surfaces.size(); i++) {
r_surfaces.write[i].vertices.resize(r_face_count[i] * 3);
r_surfaces.write[i].normals.resize(r_face_count[i] * 3);
r_surfaces.write[i].uvs.resize(r_face_count[i] * 3);
if (calculate_tangents) {
r_surfaces.write[i].tans.resize(r_face_count[i] * 3 * 4);
}
r_surfaces.write[i].last_added = 0;
if (i != r_surfaces.size() - 1) {
r_surfaces.write[i].material = p_brush->materials[i];
}
r_surfaces.write[i].verticesw = r_surfaces.write[i].vertices.ptrw();
r_surfaces.write[i].normalsw = r_surfaces.write[i].normals.ptrw();
r_surfaces.write[i].uvsw = r_surfaces.write[i].uvs.ptrw();
if (calculate_tangents) {
r_surfaces.write[i].tansw = r_surfaces.write[i].tans.ptrw();
}
}
//fill arrays
{
for (int i = 0; i < p_brush->faces.size(); i++) {
int order[3] = { 0, 1, 2 };
if (p_brush->faces[i].invert) {
SWAP(order[1], order[2]);
}
int mat = p_brush->faces[i].material;
ERR_CONTINUE(mat < -1 || mat >= r_face_count.size());
int idx = mat == -1 ? r_face_count.size() - 1 : mat;
int last = r_surfaces[idx].last_added;
int face_pos_i = i * 3;
for (int j = 0; j < 3; j++) {
Vector3 v = p_brush->faces[i].vertices[j];
Vector3 normal = smooth_vertex[face_pos_i + j];
if (p_brush->faces[i].invert) {
normal = -normal;
}
int k = last + order[j];
r_surfaces[idx].verticesw[k] = v;
r_surfaces[idx].uvsw[k] = p_brush->faces[i].uvs[j];
r_surfaces[idx].normalsw[k] = normal;
if (calculate_tangents) {
// zero out our tangents for now
k *= 4;
r_surfaces[idx].tansw[k++] = 0.0;
r_surfaces[idx].tansw[k++] = 0.0;
r_surfaces[idx].tansw[k++] = 0.0;
r_surfaces[idx].tansw[k++] = 0.0;
}
}
r_surfaces.write[idx].last_added += 3;
}
}
}
void CSGShape3D::_build_surfaces_default(CSGBrush *p_brush, Vector<CSGShape3D::ShapeUpdateSurface> &r_surfaces, Vector<int> &r_face_count) {
AHashMap<Vector3, Vector3> vec_map;
vec_map.reserve(p_brush->faces.size() * 3);
for (int i = 0; i < p_brush->faces.size(); i++) {
int mat = p_brush->faces[i].material;
ERR_CONTINUE(mat < -1 || mat >= r_face_count.size());
int idx = mat == -1 ? r_face_count.size() - 1 : mat;
if (p_brush->faces[i].smooth) {
Plane p(p_brush->faces[i].vertices[0], p_brush->faces[i].vertices[1], p_brush->faces[i].vertices[2]);
for (int j = 0; j < 3; j++) {
Vector3 v = p_brush->faces[i].vertices[j];
Vector3 *vec = vec_map.getptr(v);
if (vec) {
*vec += p.normal;
} else {
vec_map.insert(v, p.normal);
}
}
}
r_face_count.write[idx]++;
}
//create arrays
for (int i = 0; i < r_surfaces.size(); i++) {
r_surfaces.write[i].vertices.resize(r_face_count[i] * 3);
r_surfaces.write[i].normals.resize(r_face_count[i] * 3);
r_surfaces.write[i].uvs.resize(r_face_count[i] * 3);
if (calculate_tangents) {
r_surfaces.write[i].tans.resize(r_face_count[i] * 3 * 4);
}
r_surfaces.write[i].last_added = 0;
if (i != r_surfaces.size() - 1) {
r_surfaces.write[i].material = p_brush->materials[i];
}
r_surfaces.write[i].verticesw = r_surfaces.write[i].vertices.ptrw();
r_surfaces.write[i].normalsw = r_surfaces.write[i].normals.ptrw();
r_surfaces.write[i].uvsw = r_surfaces.write[i].uvs.ptrw();
if (calculate_tangents) {
r_surfaces.write[i].tansw = r_surfaces.write[i].tans.ptrw();
}
}
//fill arrays
{
for (int i = 0; i < p_brush->faces.size(); i++) {
int order[3] = { 0, 1, 2 };
if (p_brush->faces[i].invert) {
SWAP(order[1], order[2]);
}
int mat = p_brush->faces[i].material;
ERR_CONTINUE(mat < -1 || mat >= r_face_count.size());
int idx = mat == -1 ? r_face_count.size() - 1 : mat;
int last = r_surfaces[idx].last_added;
Plane p(p_brush->faces[i].vertices[0], p_brush->faces[i].vertices[1], p_brush->faces[i].vertices[2]);
for (int j = 0; j < 3; j++) {
Vector3 v = p_brush->faces[i].vertices[j];
Vector3 normal = p.normal;
if (p_brush->faces[i].smooth) {
Vector3 *ptr = vec_map.getptr(v);
if (ptr) {
normal = ptr->normalized();
}
}
if (p_brush->faces[i].invert) {
normal = -normal;
}
int k = last + order[j];
r_surfaces[idx].verticesw[k] = v;
r_surfaces[idx].uvsw[k] = p_brush->faces[i].uvs[j];
r_surfaces[idx].normalsw[k] = normal;
if (calculate_tangents) {
// zero out our tangents for now
k *= 4;
r_surfaces[idx].tansw[k++] = 0.0;
r_surfaces[idx].tansw[k++] = 0.0;
r_surfaces[idx].tansw[k++] = 0.0;
r_surfaces[idx].tansw[k++] = 0.0;
}
}
r_surfaces.write[idx].last_added += 3;
}
}
}
Ref<ArrayMesh> CSGShape3D::bake_static_mesh() {
Ref<ArrayMesh> baked_mesh;
if (is_root_shape() && root_mesh.is_valid()) {
@ -897,12 +1034,12 @@ void CSGShape3D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (use_collision && is_root_shape()) {
root_collision_shape.instantiate();
root_collision_instance = PhysicsServer3D::get_singleton()->body_create();
PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space());
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
root_collision_body = PhysicsServer3D::get_singleton()->body_create();
PhysicsServer3D::get_singleton()->body_set_mode(root_collision_body, PS3DE::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_state(root_collision_body, PS3DE::BODY_STATE_TRANSFORM, get_global_transform());
PhysicsServer3D::get_singleton()->body_add_shape(root_collision_body, root_collision_shape->get_rid());
PhysicsServer3D::get_singleton()->body_set_space(root_collision_body, get_world_3d()->get_space());
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_body, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
set_collision_priority(collision_priority);
@ -912,17 +1049,17 @@ void CSGShape3D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
PhysicsServer3D::get_singleton()->free_rid(root_collision_instance);
root_collision_instance = RID();
if (use_collision && is_root_shape() && root_collision_body.is_valid()) {
PhysicsServer3D::get_singleton()->free_rid(root_collision_body);
root_collision_body = RID();
root_collision_shape.unref();
_clear_debug_collision_shape();
}
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
if (use_collision && is_root_shape() && root_collision_body.is_valid()) {
PhysicsServer3D::get_singleton()->body_set_state(root_collision_body, PS3DE::BODY_STATE_TRANSFORM, get_global_transform());
}
_on_transform_changed();
} break;
@ -953,6 +1090,19 @@ void CSGShape3D::_validate_property(PropertyInfo &p_property) const {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
if (p_property.name == "smoothing_angle") {
if (!autosmooth || (is_inside_tree() && !is_root_shape())) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
if (p_property.name == "autosmooth") {
if (is_inside_tree() && !is_root_shape()) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
bool is_collision_prefixed = p_property.name.begins_with("collision_");
if ((is_collision_prefixed || p_property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) {
//hide collision if not root
@ -1037,6 +1187,15 @@ void CSGShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("bake_static_mesh"), &CSGShape3D::bake_static_mesh);
ClassDB::bind_method(D_METHOD("set_autosmooth", "autosmooth"), &CSGShape3D::set_autosmooth);
ClassDB::bind_method(D_METHOD("is_autosmooth"), &CSGShape3D::is_autosmooth);
ClassDB::bind_method(D_METHOD("set_smoothing_angle", "smoothing_angle"), &CSGShape3D::set_smoothing_angle);
ClassDB::bind_method(D_METHOD("get_smoothing_angle"), &CSGShape3D::get_smoothing_angle);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autosmooth"), "set_autosmooth", "is_autosmooth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_smoothing_angle", "get_smoothing_angle");
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
#ifndef DISABLE_DEPRECATED
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.000001,1,0.000001,suffix:m", PROPERTY_USAGE_NONE), "set_snap", "get_snap");