feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")

View file

@ -29,6 +29,8 @@
/**************************************************************************/
#include "box_shape_3d.h"
#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const {
@ -47,6 +49,24 @@ Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const {
return lines;
}
Ref<ArrayMesh> BoxShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
Array box_array;
box_array.resize(RS::ARRAY_MAX);
BoxMesh::create_mesh_array(box_array, size);
Vector<Color> colors;
const PackedVector3Array &verts = box_array[RS::ARRAY_VERTEX];
const int32_t verts_size = verts.size();
for (int i = 0; i < verts_size; i++) {
colors.append(p_modulate);
}
Ref<ArrayMesh> box_mesh = memnew(ArrayMesh);
box_array[RS::ARRAY_COLOR] = colors;
box_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
return box_mesh;
}
real_t BoxShape3D::get_enclosing_radius() const {
return size.length() / 2;
}

View file

@ -51,6 +51,7 @@ public:
Vector3 get_size() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
BoxShape3D();

View file

@ -30,6 +30,7 @@
#include "capsule_shape_3d.h"
#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
@ -67,6 +68,24 @@ Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
return points;
}
Ref<ArrayMesh> CapsuleShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
Array capsule_array;
capsule_array.resize(RS::ARRAY_MAX);
CapsuleMesh::create_mesh_array(capsule_array, radius, height, 32, 8);
Vector<Color> colors;
const PackedVector3Array &verts = capsule_array[RS::ARRAY_VERTEX];
const int32_t verts_size = verts.size();
for (int i = 0; i < verts_size; i++) {
colors.append(p_modulate);
}
Ref<ArrayMesh> capsule_mesh = memnew(ArrayMesh);
capsule_array[RS::ARRAY_COLOR] = colors;
capsule_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, capsule_array);
return capsule_mesh;
}
real_t CapsuleShape3D::get_enclosing_radius() const {
return height * 0.5;
}

View file

@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class CapsuleShape3D : public Shape3D {
GDCLASS(CapsuleShape3D, Shape3D);
float radius = 0.5;
@ -50,6 +52,7 @@ public:
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CapsuleShape3D();

View file

@ -30,6 +30,7 @@
#include "concave_polygon_shape_3d.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
@ -59,6 +60,23 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
return points;
}
Ref<ArrayMesh> ConcavePolygonShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
Vector<Color> colors;
for (int i = 0; i < faces.size(); i++) {
colors.push_back(p_modulate);
}
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
Array a;
a.resize(Mesh::ARRAY_MAX);
a[RS::ARRAY_VERTEX] = faces;
a[RS::ARRAY_COLOR] = colors;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
return mesh;
}
real_t ConcavePolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_faces();
const Vector3 *read = data.ptr();

View file

@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class ConcavePolygonShape3D : public Shape3D {
GDCLASS(ConcavePolygonShape3D, Shape3D);
@ -72,6 +74,7 @@ public:
bool is_backface_collision_enabled() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConcavePolygonShape3D();

View file

@ -30,12 +30,13 @@
#include "convex_polygon_shape_3d.h"
#include "core/math/convex_hull.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
Vector<Vector3> poly_points = get_points();
if (poly_points.size() > 3) {
if (poly_points.size() > 1) { // Need at least 2 points for a line.
Vector<Vector3> varr = Variant(poly_points);
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(varr, md);
@ -53,6 +54,44 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
return Vector<Vector3>();
}
Ref<ArrayMesh> ConvexPolygonShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
const Vector<Vector3> hull_points = get_points();
Vector<Vector3> verts;
Vector<Color> colors;
Vector<int> indices;
if (hull_points.size() >= 3) {
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(hull_points, md);
if (err == OK) {
verts = md.vertices;
for (int i = 0; i < verts.size(); i++) {
colors.push_back(p_modulate);
}
for (const Geometry3D::MeshData::Face &face : md.faces) {
const int first_point = face.indices[0];
const int indices_count = face.indices.size();
for (int i = 1; i < indices_count - 1; i++) {
indices.push_back(first_point);
indices.push_back(face.indices[i]);
indices.push_back(face.indices[i + 1]);
}
}
}
}
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
Array a;
a.resize(Mesh::ARRAY_MAX);
a[RS::ARRAY_VERTEX] = verts;
a[RS::ARRAY_COLOR] = colors;
a[RS::ARRAY_INDEX] = indices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
return mesh;
}
real_t ConvexPolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_points();
const Vector3 *read = data.ptr();

View file

@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class ConvexPolygonShape3D : public Shape3D {
GDCLASS(ConvexPolygonShape3D, Shape3D);
Vector<Vector3> points;
@ -47,6 +49,7 @@ public:
Vector<Vector3> get_points() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConvexPolygonShape3D();

View file

@ -30,6 +30,7 @@
#include "cylinder_shape_3d.h"
#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
@ -60,6 +61,24 @@ Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
return points;
}
Ref<ArrayMesh> CylinderShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
Array cylinder_array;
cylinder_array.resize(RS::ARRAY_MAX);
CylinderMesh::create_mesh_array(cylinder_array, radius, radius, height, 32);
Vector<Color> colors;
const PackedVector3Array &verts = cylinder_array[RS::ARRAY_VERTEX];
const int32_t verts_size = verts.size();
for (int i = 0; i < verts_size; i++) {
colors.append(p_modulate);
}
Ref<ArrayMesh> cylinder_mesh = memnew(ArrayMesh);
cylinder_array[RS::ARRAY_COLOR] = colors;
cylinder_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
return cylinder_mesh;
}
real_t CylinderShape3D::get_enclosing_radius() const {
return Vector2(radius, height * 0.5).length();
}

View file

@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class CylinderShape3D : public Shape3D {
GDCLASS(CylinderShape3D, Shape3D);
float radius = 0.5;
@ -49,6 +51,7 @@ public:
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CylinderShape3D();

View file

@ -138,7 +138,7 @@ void FogMaterial::cleanup_shader() {
}
void FogMaterial::_update_shader() {
shader_mutex.lock();
MutexLock shader_lock(shader_mutex);
if (shader.is_null()) {
shader = RS::get_singleton()->shader_create();
@ -165,10 +165,11 @@ void fog() {
}
)");
}
shader_mutex.unlock();
}
FogMaterial::FogMaterial() {
_set_material(RS::get_singleton()->material_create());
set_density(1.0);
set_albedo(Color(1, 1, 1, 1));
set_emission(Color(0, 0, 0, 1));

View file

@ -31,6 +31,7 @@
#include "height_map_shape_3d.h"
#include "core/io/image.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
@ -82,6 +83,60 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
return points;
}
Ref<ArrayMesh> HeightMapShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
Vector<Vector3> verts;
Vector<Color> colors;
Vector<int> indices;
// This will be slow for large maps...
if ((map_width != 0) && (map_depth != 0)) {
Vector2 size = Vector2(map_width - 1, map_depth - 1) * -0.5;
const real_t *r = map_data.ptr();
for (int d = 0; d <= map_depth - 2; d++) {
const int this_row_offset = map_width * d;
const int next_row_offset = this_row_offset + map_width;
for (int w = 0; w <= map_width - 2; w++) {
const float height_tl = r[next_row_offset + w];
const float height_bl = r[this_row_offset + w];
const float height_br = r[this_row_offset + w + 1];
const float height_tr = r[next_row_offset + w + 1];
const int index_offset = verts.size();
verts.push_back(Vector3(size.x + w, height_tl, size.y + d + 1));
verts.push_back(Vector3(size.x + w, height_bl, size.y + d));
verts.push_back(Vector3(size.x + w + 1, height_br, size.y + d));
verts.push_back(Vector3(size.x + w + 1, height_tr, size.y + d + 1));
colors.push_back(p_modulate);
colors.push_back(p_modulate);
colors.push_back(p_modulate);
colors.push_back(p_modulate);
indices.push_back(index_offset);
indices.push_back(index_offset + 1);
indices.push_back(index_offset + 2);
indices.push_back(index_offset);
indices.push_back(index_offset + 2);
indices.push_back(index_offset + 3);
}
}
}
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
Array a;
a.resize(Mesh::ARRAY_MAX);
a[RS::ARRAY_VERTEX] = verts;
a[RS::ARRAY_COLOR] = colors;
a[RS::ARRAY_INDEX] = indices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
return mesh;
}
real_t HeightMapShape3D::get_enclosing_radius() const {
return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();
}
@ -298,8 +353,8 @@ void HeightMapShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_map_data_from_image", "image", "height_min", "height_max"), &HeightMapShape3D::update_map_data_from_image);
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_width", "get_map_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_depth", "get_map_depth");
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_map_width", "get_map_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_map_depth", "get_map_depth");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data");
}

View file

@ -33,6 +33,7 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class Image;
class HeightMapShape3D : public Shape3D {
@ -62,6 +63,7 @@ public:
void update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max);
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
HeightMapShape3D();

View file

@ -33,110 +33,22 @@
#include "core/io/marshalls.h"
#include "core/math/convex_hull.h"
#include "core/math/random_pcg.h"
#include "core/math/static_raycaster.h"
#include "scene/resources/surface_tool.h"
#include <cstdint>
void ImporterMesh::Surface::split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
_split_normals(arrays, p_indices, p_normals);
for (BlendShape &blend_shape : blend_shape_data) {
_split_normals(blend_shape.arrays, p_indices, p_normals);
}
}
void ImporterMesh::Surface::_split_normals(Array &r_arrays, const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
ERR_FAIL_COND(r_arrays.size() != RS::ARRAY_MAX);
const PackedVector3Array &vertices = r_arrays[RS::ARRAY_VERTEX];
int current_vertex_count = vertices.size();
int new_vertex_count = p_indices.size();
int final_vertex_count = current_vertex_count + new_vertex_count;
const int *indices_ptr = p_indices.ptr();
for (int i = 0; i < r_arrays.size(); i++) {
if (i == RS::ARRAY_INDEX) {
continue;
}
if (r_arrays[i].get_type() == Variant::NIL) {
continue;
}
switch (r_arrays[i].get_type()) {
case Variant::PACKED_VECTOR3_ARRAY: {
PackedVector3Array data = r_arrays[i];
data.resize(final_vertex_count);
Vector3 *data_ptr = data.ptrw();
if (i == RS::ARRAY_NORMAL) {
const Vector3 *normals_ptr = p_normals.ptr();
memcpy(&data_ptr[current_vertex_count], normals_ptr, sizeof(Vector3) * new_vertex_count);
} else {
for (int j = 0; j < new_vertex_count; j++) {
data_ptr[current_vertex_count + j] = data_ptr[indices_ptr[j]];
}
}
r_arrays[i] = data;
} break;
case Variant::PACKED_VECTOR2_ARRAY: {
PackedVector2Array data = r_arrays[i];
data.resize(final_vertex_count);
Vector2 *data_ptr = data.ptrw();
for (int j = 0; j < new_vertex_count; j++) {
data_ptr[current_vertex_count + j] = data_ptr[indices_ptr[j]];
}
r_arrays[i] = data;
} break;
case Variant::PACKED_FLOAT32_ARRAY: {
PackedFloat32Array data = r_arrays[i];
int elements = data.size() / current_vertex_count;
data.resize(final_vertex_count * elements);
float *data_ptr = data.ptrw();
for (int j = 0; j < new_vertex_count; j++) {
memcpy(&data_ptr[(current_vertex_count + j) * elements], &data_ptr[indices_ptr[j] * elements], sizeof(float) * elements);
}
r_arrays[i] = data;
} break;
case Variant::PACKED_INT32_ARRAY: {
PackedInt32Array data = r_arrays[i];
int elements = data.size() / current_vertex_count;
data.resize(final_vertex_count * elements);
int32_t *data_ptr = data.ptrw();
for (int j = 0; j < new_vertex_count; j++) {
memcpy(&data_ptr[(current_vertex_count + j) * elements], &data_ptr[indices_ptr[j] * elements], sizeof(int32_t) * elements);
}
r_arrays[i] = data;
} break;
case Variant::PACKED_BYTE_ARRAY: {
PackedByteArray data = r_arrays[i];
int elements = data.size() / current_vertex_count;
data.resize(final_vertex_count * elements);
uint8_t *data_ptr = data.ptrw();
for (int j = 0; j < new_vertex_count; j++) {
memcpy(&data_ptr[(current_vertex_count + j) * elements], &data_ptr[indices_ptr[j] * elements], sizeof(uint8_t) * elements);
}
r_arrays[i] = data;
} break;
case Variant::PACKED_COLOR_ARRAY: {
PackedColorArray data = r_arrays[i];
data.resize(final_vertex_count);
Color *data_ptr = data.ptrw();
for (int j = 0; j < new_vertex_count; j++) {
data_ptr[current_vertex_count + j] = data_ptr[indices_ptr[j]];
}
r_arrays[i] = data;
} break;
default: {
ERR_FAIL_MSG("Unhandled array type.");
} break;
}
String ImporterMesh::validate_blend_shape_name(const String &p_name) {
String name = p_name;
const char *characters = ":";
for (const char *p = characters; *p; p++) {
name = name.replace(String::chr(*p), "_");
}
return name;
}
void ImporterMesh::add_blend_shape(const String &p_name) {
ERR_FAIL_COND(surfaces.size() > 0);
blend_shapes.push_back(p_name);
blend_shapes.push_back(validate_blend_shape_name(p_name));
}
int ImporterMesh::get_blend_shape_count() const {
@ -256,6 +168,117 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_ma
mesh.unref();
}
template <typename T>
static Vector<T> _remap_array(Vector<T> p_array, const Vector<uint32_t> &p_remap, uint32_t p_vertex_count) {
ERR_FAIL_COND_V(p_array.size() % p_remap.size() != 0, p_array);
int num_elements = p_array.size() / p_remap.size();
T *data = p_array.ptrw();
SurfaceTool::remap_vertex_func(data, data, p_remap.size(), sizeof(T) * num_elements, p_remap.ptr());
p_array.resize(p_vertex_count * num_elements);
return p_array;
}
static void _remap_arrays(Array &r_arrays, const Vector<uint32_t> &p_remap, uint32_t p_vertex_count) {
for (int i = 0; i < r_arrays.size(); i++) {
if (i == RS::ARRAY_INDEX) {
continue;
}
switch (r_arrays[i].get_type()) {
case Variant::NIL:
break;
case Variant::PACKED_VECTOR3_ARRAY:
r_arrays[i] = _remap_array<Vector3>(r_arrays[i], p_remap, p_vertex_count);
break;
case Variant::PACKED_VECTOR2_ARRAY:
r_arrays[i] = _remap_array<Vector2>(r_arrays[i], p_remap, p_vertex_count);
break;
case Variant::PACKED_FLOAT32_ARRAY:
r_arrays[i] = _remap_array<float>(r_arrays[i], p_remap, p_vertex_count);
break;
case Variant::PACKED_INT32_ARRAY:
r_arrays[i] = _remap_array<int32_t>(r_arrays[i], p_remap, p_vertex_count);
break;
case Variant::PACKED_BYTE_ARRAY:
r_arrays[i] = _remap_array<uint8_t>(r_arrays[i], p_remap, p_vertex_count);
break;
case Variant::PACKED_COLOR_ARRAY:
r_arrays[i] = _remap_array<Color>(r_arrays[i], p_remap, p_vertex_count);
break;
default:
ERR_FAIL_MSG("Unhandled array type.");
}
}
}
void ImporterMesh::optimize_indices() {
if (!SurfaceTool::optimize_vertex_cache_func) {
return;
}
if (!SurfaceTool::optimize_vertex_fetch_remap_func || !SurfaceTool::remap_vertex_func || !SurfaceTool::remap_index_func) {
return;
}
for (int i = 0; i < surfaces.size(); i++) {
if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) {
continue;
}
Vector<Vector3> vertices = surfaces[i].arrays[RS::ARRAY_VERTEX];
PackedInt32Array indices = surfaces[i].arrays[RS::ARRAY_INDEX];
unsigned int index_count = indices.size();
unsigned int vertex_count = vertices.size();
if (index_count == 0) {
continue;
}
// Optimize indices for vertex cache to establish final triangle order.
int *indices_ptr = indices.ptrw();
SurfaceTool::optimize_vertex_cache_func((unsigned int *)indices_ptr, (const unsigned int *)indices_ptr, index_count, vertex_count);
surfaces.write[i].arrays[RS::ARRAY_INDEX] = indices;
for (int j = 0; j < surfaces[i].lods.size(); ++j) {
Surface::LOD &lod = surfaces.write[i].lods.write[j];
int *lod_indices_ptr = lod.indices.ptrw();
SurfaceTool::optimize_vertex_cache_func((unsigned int *)lod_indices_ptr, (const unsigned int *)lod_indices_ptr, lod.indices.size(), vertex_count);
}
// Concatenate indices for all LODs in the order of coarse->fine; this establishes the effective order of vertices,
// and is important to optimize for vertex fetch (all GPUs) and shading (Mali GPUs)
PackedInt32Array merged_indices;
for (int j = surfaces[i].lods.size() - 1; j >= 0; --j) {
merged_indices.append_array(surfaces[i].lods[j].indices);
}
merged_indices.append_array(indices);
// Generate remap array that establishes optimal vertex order according to the order of indices above.
Vector<uint32_t> remap;
remap.resize(vertex_count);
unsigned int new_vertex_count = SurfaceTool::optimize_vertex_fetch_remap_func(remap.ptrw(), (const unsigned int *)merged_indices.ptr(), merged_indices.size(), vertex_count);
// We need to remap all vertex and index arrays in lockstep according to the remap.
SurfaceTool::remap_index_func((unsigned int *)indices_ptr, (const unsigned int *)indices_ptr, index_count, remap.ptr());
surfaces.write[i].arrays[RS::ARRAY_INDEX] = indices;
for (int j = 0; j < surfaces[i].lods.size(); ++j) {
Surface::LOD &lod = surfaces.write[i].lods.write[j];
int *lod_indices_ptr = lod.indices.ptrw();
SurfaceTool::remap_index_func((unsigned int *)lod_indices_ptr, (const unsigned int *)lod_indices_ptr, lod.indices.size(), remap.ptr());
}
_remap_arrays(surfaces.write[i].arrays, remap, new_vertex_count);
for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) {
_remap_arrays(surfaces.write[i].blend_shape_data.write[j].arrays, remap, new_vertex_count);
}
}
if (shadow_mesh.is_valid()) {
shadow_mesh->optimize_indices();
}
}
#define VERTEX_SKIN_FUNC(bone_count, vert_idx, read_array, write_array, transform_array, bone_array, weight_array) \
Vector3 transformed_vert; \
for (unsigned int weight_idx = 0; weight_idx < bone_count; weight_idx++) { \
@ -269,16 +292,13 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_ma
} \
write_array[vert_idx] = transformed_vert;
void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_bone_transform_array) {
void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transform_array) {
if (!SurfaceTool::simplify_scale_func) {
return;
}
if (!SurfaceTool::simplify_with_attrib_func) {
return;
}
if (!SurfaceTool::optimize_vertex_cache_func) {
return;
}
LocalVector<Transform3D> bone_transform_vector;
for (int i = 0; i < p_bone_transform_array.size(); i++) {
@ -342,8 +362,6 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
float normal_merge_threshold = Math::cos(Math::deg_to_rad(p_normal_merge_angle));
float normal_pre_split_threshold = Math::cos(Math::deg_to_rad(MIN(180.0f, p_normal_split_angle * 2.0f)));
float normal_split_threshold = Math::cos(Math::deg_to_rad(p_normal_split_angle));
const Vector3 *normals_ptr = normals.ptr();
HashMap<Vector3, LocalVector<Pair<int, int>>> unique_vertices;
@ -432,21 +450,6 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
unsigned int index_target = 12; // Start with the smallest target, 4 triangles
unsigned int last_index_count = 0;
int split_vertex_count = vertex_count;
LocalVector<Vector3> split_vertex_normals;
LocalVector<int> split_vertex_indices;
split_vertex_normals.reserve(index_count / 3);
split_vertex_indices.reserve(index_count / 3);
RandomPCG pcg;
pcg.seed(123456789); // Keep seed constant across imports
Ref<StaticRaycaster> raycaster = StaticRaycaster::create();
if (raycaster.is_valid()) {
raycaster->add_mesh(vertices, indices, 0);
raycaster->commit();
}
const float max_mesh_error = FLT_MAX; // We don't want to limit by error, just by index target
float mesh_error = 0.0f;
@ -465,6 +468,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
merged_normals_f32.ptr(),
sizeof(float) * 3, // Attribute stride
normal_weights, 3,
nullptr, // Vertex lock
index_target,
max_mesh_error,
simplify_options,
@ -488,174 +492,10 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
new_indices.resize(new_index_count);
LocalVector<LocalVector<int>> vertex_corners;
vertex_corners.resize(vertex_count);
{
int *ptrw = new_indices.ptrw();
for (unsigned int j = 0; j < new_index_count; j++) {
const int &remapped = vertex_inverse_remap[ptrw[j]];
vertex_corners[remapped].push_back(j);
ptrw[j] = remapped;
}
}
if (raycaster.is_valid()) {
float error_factor = 1.0f / (scale * MAX(mesh_error, 0.15));
const float ray_bias = 0.05;
float ray_length = ray_bias + mesh_error * scale * 3.0f;
Vector<StaticRaycaster::Ray> rays;
LocalVector<Vector2> ray_uvs;
int32_t *new_indices_ptr = new_indices.ptrw();
int current_ray_count = 0;
for (unsigned int j = 0; j < new_index_count; j += 3) {
const Vector3 &v0 = vertices_ptr[new_indices_ptr[j + 0]];
const Vector3 &v1 = vertices_ptr[new_indices_ptr[j + 1]];
const Vector3 &v2 = vertices_ptr[new_indices_ptr[j + 2]];
Vector3 face_normal = vec3_cross(v0 - v2, v0 - v1);
float face_area = face_normal.length(); // Actually twice the face area, since it's the same error_factor on all faces, we don't care
if (!Math::is_finite(face_area) || face_area == 0) {
WARN_PRINT_ONCE("Ignoring face with non-finite normal in LOD generation.");
continue;
}
Vector3 dir = face_normal / face_area;
int ray_count = CLAMP(5.0 * face_area * error_factor, 16, 64);
rays.resize(current_ray_count + ray_count);
StaticRaycaster::Ray *rays_ptr = rays.ptrw();
ray_uvs.resize(current_ray_count + ray_count);
Vector2 *ray_uvs_ptr = ray_uvs.ptr();
for (int k = 0; k < ray_count; k++) {
float u = pcg.randf();
float v = pcg.randf();
if (u + v >= 1.0f) {
u = 1.0f - u;
v = 1.0f - v;
}
u = 0.9f * u + 0.05f / 3.0f; // Give barycentric coordinates some padding, we don't want to sample right on the edge
v = 0.9f * v + 0.05f / 3.0f; // v = (v - one_third) * 0.95f + one_third;
float w = 1.0f - u - v;
Vector3 org = v0 * w + v1 * u + v2 * v;
org -= dir * ray_bias;
rays_ptr[current_ray_count + k] = StaticRaycaster::Ray(org, dir, 0.0f, ray_length);
rays_ptr[current_ray_count + k].id = j / 3;
ray_uvs_ptr[current_ray_count + k] = Vector2(u, v);
}
current_ray_count += ray_count;
}
raycaster->intersect(rays);
LocalVector<Vector3> ray_normals;
LocalVector<real_t> ray_normal_weights;
ray_normals.resize(new_index_count);
ray_normal_weights.resize(new_index_count);
for (unsigned int j = 0; j < new_index_count; j++) {
ray_normal_weights[j] = 0.0f;
}
const StaticRaycaster::Ray *rp = rays.ptr();
for (int j = 0; j < rays.size(); j++) {
if (rp[j].geomID != 0) { // Ray missed
continue;
}
if (rp[j].normal.normalized().dot(rp[j].dir) > 0.0f) { // Hit a back face.
continue;
}
const float &u = rp[j].u;
const float &v = rp[j].v;
const float w = 1.0f - u - v;
const unsigned int &hit_tri_id = rp[j].primID;
const unsigned int &orig_tri_id = rp[j].id;
const Vector3 &n0 = normals_ptr[indices_ptr[hit_tri_id * 3 + 0]];
const Vector3 &n1 = normals_ptr[indices_ptr[hit_tri_id * 3 + 1]];
const Vector3 &n2 = normals_ptr[indices_ptr[hit_tri_id * 3 + 2]];
Vector3 normal = n0 * w + n1 * u + n2 * v;
Vector2 orig_uv = ray_uvs[j];
const real_t orig_bary[3] = { 1.0f - orig_uv.x - orig_uv.y, orig_uv.x, orig_uv.y };
for (int k = 0; k < 3; k++) {
int idx = orig_tri_id * 3 + k;
real_t weight = orig_bary[k];
ray_normals[idx] += normal * weight;
ray_normal_weights[idx] += weight;
}
}
for (unsigned int j = 0; j < new_index_count; j++) {
if (ray_normal_weights[j] < 1.0f) { // Not enough data, the new normal would be just a bad guess
ray_normals[j] = Vector3();
} else {
ray_normals[j] /= ray_normal_weights[j];
}
}
LocalVector<LocalVector<int>> normal_group_indices;
LocalVector<Vector3> normal_group_averages;
normal_group_indices.reserve(24);
normal_group_averages.reserve(24);
for (unsigned int j = 0; j < vertex_count; j++) {
const LocalVector<int> &corners = vertex_corners[j];
const Vector3 &vertex_normal = normals_ptr[j];
for (const int &corner_idx : corners) {
const Vector3 &ray_normal = ray_normals[corner_idx];
if (ray_normal.length_squared() < CMP_EPSILON2) {
continue;
}
bool found = false;
for (unsigned int l = 0; l < normal_group_indices.size(); l++) {
LocalVector<int> &group_indices = normal_group_indices[l];
Vector3 n = normal_group_averages[l] / group_indices.size();
if (n.dot(ray_normal) > normal_pre_split_threshold) {
found = true;
group_indices.push_back(corner_idx);
normal_group_averages[l] += ray_normal;
break;
}
}
if (!found) {
normal_group_indices.push_back({ corner_idx });
normal_group_averages.push_back(ray_normal);
}
}
for (unsigned int k = 0; k < normal_group_indices.size(); k++) {
LocalVector<int> &group_indices = normal_group_indices[k];
Vector3 n = normal_group_averages[k] / group_indices.size();
if (vertex_normal.dot(n) < normal_split_threshold) {
split_vertex_indices.push_back(j);
split_vertex_normals.push_back(n);
int new_idx = split_vertex_count++;
for (const int &index : group_indices) {
new_indices_ptr[index] = new_idx;
}
}
}
normal_group_indices.clear();
normal_group_averages.clear();
ptrw[j] = vertex_inverse_remap[ptrw[j]];
}
}
@ -671,17 +511,15 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
surfaces.write[i].split_normals(split_vertex_indices, split_vertex_normals);
surfaces.write[i].lods.sort_custom<Surface::LODComparator>();
for (int j = 0; j < surfaces.write[i].lods.size(); j++) {
Surface::LOD &lod = surfaces.write[i].lods.write[j];
unsigned int *lod_indices_ptr = (unsigned int *)lod.indices.ptrw();
SurfaceTool::optimize_vertex_cache_func(lod_indices_ptr, lod_indices_ptr, lod.indices.size(), split_vertex_count);
}
}
}
void ImporterMesh::_generate_lods_bind(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array) {
// p_normal_split_angle is unused, but kept for compatibility
generate_lods(p_normal_merge_angle, p_skin_pose_transform_array);
}
bool ImporterMesh::has_mesh() const {
return mesh.is_valid();
}
@ -1062,9 +900,12 @@ Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() {
}
HashMap<Vector3, int> unique_vertices;
LocalVector<int> face_indices;
Vector<Vector<int>> face_polygons;
face_polygons.resize(faces.size());
for (int i = 0; i < faces.size(); i++) {
Vector<int> face_indices;
face_indices.resize(3);
for (int j = 0; j < 3; j++) {
Vector3 v = faces[i].vertex[j];
int idx;
@ -1074,8 +915,9 @@ Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() {
idx = unique_vertices.size();
unique_vertices[v] = idx;
}
face_indices.push_back(idx);
face_indices.write[j] = idx;
}
face_polygons.write[i] = face_indices;
}
Vector<Vector3> vertices;
@ -1086,16 +928,7 @@ Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() {
Ref<NavigationMesh> nm;
nm.instantiate();
nm->set_vertices(vertices);
Vector<int> v3;
v3.resize(3);
for (uint32_t i = 0; i < face_indices.size(); i += 3) {
v3.write[0] = face_indices[i + 0];
v3.write[1] = face_indices[i + 1];
v3.write[2] = face_indices[i + 2];
nm->add_polygon(v3);
}
nm->set_data(vertices, face_polygons);
return nm;
}
@ -1367,7 +1200,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle", "bone_transform_array"), &ImporterMesh::generate_lods);
ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle", "bone_transform_array"), &ImporterMesh::_generate_lods_bind);
ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);
@ -1377,5 +1210,5 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &ImporterMesh::set_lightmap_size_hint);
ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &ImporterMesh::get_lightmap_size_hint);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}

View file

@ -32,7 +32,6 @@
#define IMPORTER_MESH_H
#include "core/io/resource.h"
#include "core/templates/local_vector.h"
#include "scene/resources/3d/concave_polygon_shape_3d.h"
#include "scene/resources/3d/convex_polygon_shape_3d.h"
#include "scene/resources/mesh.h"
@ -68,9 +67,6 @@ class ImporterMesh : public Resource {
return l.distance < r.distance;
}
};
void split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals);
static void _split_normals(Array &r_arrays, const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals);
};
Vector<Surface> surfaces;
Vector<String> blend_shapes;
@ -86,6 +82,8 @@ protected:
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
void _generate_lods_bind(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array);
static void _bind_methods();
public:
@ -93,6 +91,8 @@ public:
int get_blend_shape_count() const;
String get_blend_shape_name(int p_blend_shape) const;
static String validate_blend_shape_name(const String &p_name);
void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String(), const uint64_t p_flags = 0);
int get_surface_count() const;
@ -112,7 +112,9 @@ public:
void set_surface_material(int p_surface, const Ref<Material> &p_material);
void generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array);
void optimize_indices();
void generate_lods(float p_normal_merge_angle, Array p_skin_pose_transform_array);
void create_shadow_mesh();
Ref<ImporterMesh> get_shadow_mesh() const;

View file

@ -47,6 +47,24 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
set_item_mesh(idx, p_value);
} else if (what == "mesh_transform") {
set_item_mesh_transform(idx, p_value);
} else if (what == "mesh_cast_shadow") {
switch ((int)p_value) {
case 0: {
set_item_mesh_cast_shadow(idx, RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_OFF);
} break;
case 1: {
set_item_mesh_cast_shadow(idx, RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_ON);
} break;
case 2: {
set_item_mesh_cast_shadow(idx, RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_DOUBLE_SIDED);
} break;
case 3: {
set_item_mesh_cast_shadow(idx, RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_SHADOWS_ONLY);
} break;
default: {
set_item_mesh_cast_shadow(idx, RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_ON);
} break;
}
} else if (what == "shape") {
Vector<ShapeData> shapes;
ShapeData sd;
@ -91,6 +109,8 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_item_mesh(idx);
} else if (what == "mesh_transform") {
r_ret = get_item_mesh_transform(idx);
} else if (what == "mesh_cast_shadow") {
r_ret = (int)get_item_mesh_cast_shadow(idx);
} else if (what == "shapes") {
r_ret = _get_item_shapes(idx);
} else if (what == "navigation_mesh") {
@ -120,6 +140,7 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + PNAME("name")));
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
p_list->push_back(PropertyInfo(Variant::INT, prop_name + PNAME("mesh_cast_shadow"), PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"));
p_list->push_back(PropertyInfo(Variant::ARRAY, prop_name + PNAME("shapes")));
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("navigation_mesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("navigation_mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
@ -154,6 +175,12 @@ void MeshLibrary::set_item_mesh_transform(int p_item, const Transform3D &p_trans
emit_changed();
}
void MeshLibrary::set_item_mesh_cast_shadow(int p_item, RS::ShadowCastingSetting p_shadow_casting_setting) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].mesh_cast_shadow = p_shadow_casting_setting;
emit_changed();
}
void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].shapes = p_shapes;
@ -200,6 +227,11 @@ Transform3D MeshLibrary::get_item_mesh_transform(int p_item) const {
return item_map[p_item].mesh_transform;
}
RS::ShadowCastingSetting MeshLibrary::get_item_mesh_cast_shadow(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_ON, "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].mesh_cast_shadow;
}
Vector<MeshLibrary::ShapeData> MeshLibrary::get_item_shapes(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Vector<ShapeData>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].shapes;
@ -328,6 +360,7 @@ void MeshLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name);
ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh);
ClassDB::bind_method(D_METHOD("set_item_mesh_transform", "id", "mesh_transform"), &MeshLibrary::set_item_mesh_transform);
ClassDB::bind_method(D_METHOD("set_item_mesh_cast_shadow", "id", "shadow_casting_setting"), &MeshLibrary::set_item_mesh_cast_shadow);
ClassDB::bind_method(D_METHOD("set_item_navigation_mesh", "id", "navigation_mesh"), &MeshLibrary::set_item_navigation_mesh);
ClassDB::bind_method(D_METHOD("set_item_navigation_mesh_transform", "id", "navigation_mesh"), &MeshLibrary::set_item_navigation_mesh_transform);
ClassDB::bind_method(D_METHOD("set_item_navigation_layers", "id", "navigation_layers"), &MeshLibrary::set_item_navigation_layers);
@ -336,6 +369,7 @@ void MeshLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name);
ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh);
ClassDB::bind_method(D_METHOD("get_item_mesh_transform", "id"), &MeshLibrary::get_item_mesh_transform);
ClassDB::bind_method(D_METHOD("get_item_mesh_cast_shadow", "id"), &MeshLibrary::get_item_mesh_cast_shadow);
ClassDB::bind_method(D_METHOD("get_item_navigation_mesh", "id"), &MeshLibrary::get_item_navigation_mesh);
ClassDB::bind_method(D_METHOD("get_item_navigation_mesh_transform", "id"), &MeshLibrary::get_item_navigation_mesh_transform);
ClassDB::bind_method(D_METHOD("get_item_navigation_layers", "id"), &MeshLibrary::get_item_navigation_layers);

View file

@ -33,8 +33,9 @@
#include "core/io/resource.h"
#include "core/templates/rb_map.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h"
#include "servers/rendering_server.h"
#include "shape_3d.h"
class MeshLibrary : public Resource {
@ -50,6 +51,7 @@ public:
String name;
Ref<Mesh> mesh;
Transform3D mesh_transform;
RS::ShadowCastingSetting mesh_cast_shadow = RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_ON;
Vector<ShapeData> shapes;
Ref<Texture2D> preview;
Ref<NavigationMesh> navigation_mesh;
@ -75,6 +77,7 @@ public:
void set_item_name(int p_item, const String &p_name);
void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh);
void set_item_mesh_transform(int p_item, const Transform3D &p_transform);
void set_item_mesh_cast_shadow(int p_item, RS::ShadowCastingSetting p_shadow_casting_setting);
void set_item_navigation_mesh(int p_item, const Ref<NavigationMesh> &p_navigation_mesh);
void set_item_navigation_mesh_transform(int p_item, const Transform3D &p_transform);
void set_item_navigation_layers(int p_item, uint32_t p_navigation_layers);
@ -83,6 +86,7 @@ public:
String get_item_name(int p_item) const;
Ref<Mesh> get_item_mesh(int p_item) const;
Transform3D get_item_mesh_transform(int p_item) const;
RS::ShadowCastingSetting get_item_mesh_cast_shadow(int p_item) const;
Ref<NavigationMesh> get_item_navigation_mesh(int p_item) const;
Transform3D get_item_navigation_mesh_transform(int p_item) const;
uint32_t get_item_navigation_layers(int p_item) const;

View file

@ -33,6 +33,7 @@
void NavigationMeshSourceGeometryData3D::set_vertices(const Vector<float> &p_vertices) {
RWLockWrite write_lock(geometry_rwlock);
vertices = p_vertices;
bounds_dirty = true;
}
const Vector<float> &NavigationMeshSourceGeometryData3D::get_vertices() const {
@ -44,6 +45,7 @@ void NavigationMeshSourceGeometryData3D::set_indices(const Vector<int> &p_indice
ERR_FAIL_COND(vertices.size() < p_indices.size());
RWLockWrite write_lock(geometry_rwlock);
indices = p_indices;
bounds_dirty = true;
}
const Vector<int> &NavigationMeshSourceGeometryData3D::get_indices() const {
@ -63,23 +65,26 @@ void NavigationMeshSourceGeometryData3D::append_arrays(const Vector<float> &p_ve
for (int64_t i = number_of_indices_before_merge; i < indices.size(); i++) {
indices.set(i, indices[i] + number_of_vertices_before_merge / 3);
}
bounds_dirty = true;
}
bool NavigationMeshSourceGeometryData3D::has_data() {
RWLockRead read_lock(geometry_rwlock);
return vertices.size() && indices.size();
};
}
void NavigationMeshSourceGeometryData3D::clear() {
RWLockWrite write_lock(geometry_rwlock);
vertices.clear();
indices.clear();
_projected_obstructions.clear();
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::clear_projected_obstructions() {
RWLockWrite write_lock(geometry_rwlock);
_projected_obstructions.clear();
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::_add_vertex(const Vector3 &p_vec3) {
@ -190,7 +195,7 @@ void NavigationMeshSourceGeometryData3D::_add_faces(const PackedVector3Array &p_
}
void NavigationMeshSourceGeometryData3D::add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {
ERR_FAIL_COND(!p_mesh.is_valid());
ERR_FAIL_COND(p_mesh.is_null());
#ifdef DEBUG_ENABLED
if (!Engine::get_singleton()->is_editor_hint()) {
@ -207,16 +212,18 @@ void NavigationMeshSourceGeometryData3D::add_mesh_array(const Array &p_mesh_arra
ERR_FAIL_COND(p_mesh_array.size() != Mesh::ARRAY_MAX);
RWLockWrite write_lock(geometry_rwlock);
_add_mesh_array(p_mesh_array, root_node_transform * p_xform);
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {
ERR_FAIL_COND(p_faces.size() % 3 != 0);
RWLockWrite write_lock(geometry_rwlock);
_add_faces(p_faces, root_node_transform * p_xform);
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::merge(const Ref<NavigationMeshSourceGeometryData3D> &p_other_geometry) {
ERR_FAIL_NULL(p_other_geometry);
ERR_FAIL_COND(p_other_geometry.is_null());
Vector<float> other_vertices;
Vector<int> other_indices;
@ -236,6 +243,7 @@ void NavigationMeshSourceGeometryData3D::merge(const Ref<NavigationMeshSourceGeo
}
_projected_obstructions.append_array(other_projected_obstructions);
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::add_projected_obstruction(const Vector<Vector3> &p_vertices, float p_elevation, float p_height, bool p_carve) {
@ -259,6 +267,7 @@ void NavigationMeshSourceGeometryData3D::add_projected_obstruction(const Vector<
RWLockWrite write_lock(geometry_rwlock);
_projected_obstructions.push_back(projected_obstruction);
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::set_projected_obstructions(const Array &p_array) {
@ -285,6 +294,7 @@ void NavigationMeshSourceGeometryData3D::set_projected_obstructions(const Array
RWLockWrite write_lock(geometry_rwlock);
_projected_obstructions.push_back(projected_obstruction);
bounds_dirty = true;
}
}
@ -336,6 +346,7 @@ void NavigationMeshSourceGeometryData3D::set_data(const Vector<float> &p_vertice
vertices = p_vertices;
indices = p_indices;
_projected_obstructions = p_projected_obstructions;
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::get_data(Vector<float> &r_vertices, Vector<int> &r_indices, Vector<ProjectedObstruction> &r_projected_obstructions) {
@ -345,6 +356,45 @@ void NavigationMeshSourceGeometryData3D::get_data(Vector<float> &r_vertices, Vec
r_projected_obstructions = _projected_obstructions;
}
AABB NavigationMeshSourceGeometryData3D::get_bounds() {
geometry_rwlock.read_lock();
if (bounds_dirty) {
geometry_rwlock.read_unlock();
RWLockWrite write_lock(geometry_rwlock);
bounds_dirty = false;
bounds = AABB();
bool first_vertex = true;
for (int i = 0; i < vertices.size() / 3; i++) {
const Vector3 vertex = Vector3(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
if (first_vertex) {
first_vertex = false;
bounds.position = vertex;
} else {
bounds.expand_to(vertex);
}
}
for (const ProjectedObstruction &projected_obstruction : _projected_obstructions) {
for (int i = 0; i < projected_obstruction.vertices.size() / 3; i++) {
const Vector3 vertex = Vector3(projected_obstruction.vertices[i * 3], projected_obstruction.vertices[i * 3 + 1], projected_obstruction.vertices[i * 3 + 2]);
if (first_vertex) {
first_vertex = false;
bounds.position = vertex;
} else {
bounds.expand_to(vertex);
}
}
}
} else {
geometry_rwlock.read_unlock();
}
RWLockRead read_lock(geometry_rwlock);
return bounds;
}
void NavigationMeshSourceGeometryData3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMeshSourceGeometryData3D::set_vertices);
ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMeshSourceGeometryData3D::get_vertices);
@ -367,6 +417,8 @@ void NavigationMeshSourceGeometryData3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_projected_obstructions", "projected_obstructions"), &NavigationMeshSourceGeometryData3D::set_projected_obstructions);
ClassDB::bind_method(D_METHOD("get_projected_obstructions"), &NavigationMeshSourceGeometryData3D::get_projected_obstructions);
ClassDB::bind_method(D_METHOD("get_bounds"), &NavigationMeshSourceGeometryData3D::get_bounds);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_indices", "get_indices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "projected_obstructions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_projected_obstructions", "get_projected_obstructions");

View file

@ -41,6 +41,9 @@ class NavigationMeshSourceGeometryData3D : public Resource {
Vector<float> vertices;
Vector<int> indices;
AABB bounds;
bool bounds_dirty = true;
public:
struct ProjectedObstruction;
@ -101,6 +104,8 @@ public:
void set_data(const Vector<float> &p_vertices, const Vector<int> &p_indices, Vector<ProjectedObstruction> &p_projected_obstructions);
void get_data(Vector<float> &r_vertices, Vector<int> &r_indices, Vector<ProjectedObstruction> &r_projected_obstructions);
AABB get_bounds();
NavigationMeshSourceGeometryData3D() {}
~NavigationMeshSourceGeometryData3D() { clear(); }
};

View file

@ -31,6 +31,7 @@
#include "primitive_meshes.h"
#include "core/config/project_settings.h"
#include "core/math/math_funcs.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
@ -261,6 +262,9 @@ void PrimitiveMesh::_bind_methods() {
}
void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
if (p_material == material) {
return;
}
material = p_material;
if (!pending_request) {
// just apply it, else it'll happen when _update is called.
@ -279,6 +283,9 @@ Array PrimitiveMesh::get_mesh_arrays() const {
}
void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) {
if (p_custom.is_equal_approx(custom_aabb)) {
return;
}
custom_aabb = p_custom;
RS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
emit_changed();
@ -289,6 +296,9 @@ AABB PrimitiveMesh::get_custom_aabb() const {
}
void PrimitiveMesh::set_flip_faces(bool p_enable) {
if (p_enable == flip_faces) {
return;
}
flip_faces = p_enable;
request_update();
}
@ -298,12 +308,18 @@ bool PrimitiveMesh::get_flip_faces() const {
}
void PrimitiveMesh::set_add_uv2(bool p_enable) {
if (p_enable == add_uv2) {
return;
}
add_uv2 = p_enable;
_update_lightmap_size();
request_update();
}
void PrimitiveMesh::set_uv2_padding(float p_padding) {
if (Math::is_equal_approx(p_padding, uv2_padding)) {
return;
}
uv2_padding = p_padding;
_update_lightmap_size();
request_update();
@ -324,22 +340,43 @@ Vector2 PrimitiveMesh::get_uv2_scale(Vector2 p_margin_scale) const {
}
float PrimitiveMesh::get_lightmap_texel_size() const {
float texel_size = GLOBAL_GET("rendering/lightmapping/primitive_meshes/texel_size");
if (texel_size <= 0.0) {
texel_size = 0.2;
}
return texel_size;
}
void PrimitiveMesh::_on_settings_changed() {
float new_texel_size = float(GLOBAL_GET("rendering/lightmapping/primitive_meshes/texel_size"));
if (new_texel_size <= 0.0) {
new_texel_size = 0.2;
}
if (texel_size == new_texel_size) {
return;
}
texel_size = new_texel_size;
_update_lightmap_size();
request_update();
}
PrimitiveMesh::PrimitiveMesh() {
ERR_FAIL_NULL(RenderingServer::get_singleton());
mesh = RenderingServer::get_singleton()->mesh_create();
ERR_FAIL_NULL(ProjectSettings::get_singleton());
texel_size = float(GLOBAL_GET("rendering/lightmapping/primitive_meshes/texel_size"));
if (texel_size <= 0.0) {
texel_size = 0.2;
}
ProjectSettings *project_settings = ProjectSettings::get_singleton();
project_settings->connect("settings_changed", callable_mp(this, &PrimitiveMesh::_on_settings_changed));
}
PrimitiveMesh::~PrimitiveMesh() {
ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(mesh);
ERR_FAIL_NULL(ProjectSettings::get_singleton());
ProjectSettings *project_settings = ProjectSettings::get_singleton();
project_settings->disconnect("settings_changed", callable_mp(this, &PrimitiveMesh::_on_settings_changed));
}
/**
@ -350,7 +387,6 @@ void CapsuleMesh::_update_lightmap_size() {
if (get_add_uv2()) {
// size must have changed, update lightmap size hint
Size2i _lightmap_size_hint;
float texel_size = get_lightmap_texel_size();
float padding = get_uv2_padding();
float radial_length = radius * Math_PI * 0.5; // circumference of 90 degree bend
@ -365,7 +401,6 @@ void CapsuleMesh::_update_lightmap_size() {
void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
bool _add_uv2 = get_add_uv2();
float texel_size = get_lightmap_texel_size();
float _uv2_padding = get_uv2_padding() * texel_size;
create_mesh_array(p_arr, radius, height, radial_segments, rings, _add_uv2, _uv2_padding);
@ -408,19 +443,29 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
v = j;
v /= (rings + 1);
w = sin(0.5 * Math_PI * v);
y = radius * cos(0.5 * Math_PI * v);
if (j == (rings + 1)) {
w = 1.0;
y = 0.0;
} else {
w = Math::sin(0.5 * Math_PI * v);
y = Math::cos(0.5 * Math_PI * v);
}
for (i = 0; i <= radial_segments; i++) {
u = i;
u /= radial_segments;
x = -sin(u * Math_TAU);
z = cos(u * Math_TAU);
if (i == radial_segments) {
x = 0.0;
z = 1.0;
} else {
x = -Math::sin(u * Math_TAU);
z = Math::cos(u * Math_TAU);
}
Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, 0.5 * height - radius, 0.0));
normals.push_back(p.normalized());
Vector3 p = Vector3(x * w, y, -z * w);
points.push_back(p * radius + Vector3(0.0, 0.5 * height - radius, 0.0));
normals.push_back(p);
ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * onethird));
if (p_add_uv2) {
@ -457,8 +502,13 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
u = i;
u /= radial_segments;
x = -sin(u * Math_TAU);
z = cos(u * Math_TAU);
if (i == radial_segments) {
x = 0.0;
z = 1.0;
} else {
x = -Math::sin(u * Math_TAU);
z = Math::cos(u * Math_TAU);
}
Vector3 p = Vector3(x * radius, y, -z * radius);
points.push_back(p);
@ -492,24 +542,33 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
v = j;
v /= (rings + 1);
v += 1.0;
w = sin(0.5 * Math_PI * v);
y = radius * cos(0.5 * Math_PI * v);
if (j == (rings + 1)) {
w = 0.0;
y = -1.0;
} else {
w = Math::cos(0.5 * Math_PI * v);
y = -Math::sin(0.5 * Math_PI * v);
}
for (i = 0; i <= radial_segments; i++) {
u = i;
u /= radial_segments;
x = -sin(u * Math_TAU);
z = cos(u * Math_TAU);
if (i == radial_segments) {
x = 0.0;
z = 1.0;
} else {
x = -Math::sin(u * Math_TAU);
z = Math::cos(u * Math_TAU);
}
Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, -0.5 * height + radius, 0.0));
normals.push_back(p.normalized());
Vector3 p = Vector3(x * w, y, -z * w);
points.push_back(p * radius + Vector3(0.0, -0.5 * height + radius, 0.0));
normals.push_back(p);
ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird)));
uvs.push_back(Vector2(u, twothirds + v * onethird));
if (p_add_uv2) {
uv2s.push_back(Vector2(u * radial_h, radial_v + height_v + ((v - 1.0) * radial_v)));
uv2s.push_back(Vector2(u * radial_h, radial_v + height_v + v * radial_v));
}
point++;
@ -559,6 +618,10 @@ void CapsuleMesh::_bind_methods() {
}
void CapsuleMesh::set_radius(const float p_radius) {
if (Math::is_equal_approx(radius, p_radius)) {
return;
}
radius = p_radius;
if (radius > height * 0.5) {
height = radius * 2.0;
@ -572,6 +635,10 @@ float CapsuleMesh::get_radius() const {
}
void CapsuleMesh::set_height(const float p_height) {
if (Math::is_equal_approx(height, p_height)) {
return;
}
height = p_height;
if (radius > height * 0.5) {
radius = height * 0.5;
@ -585,6 +652,10 @@ float CapsuleMesh::get_height() const {
}
void CapsuleMesh::set_radial_segments(const int p_segments) {
if (radial_segments == p_segments) {
return;
}
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@ -594,6 +665,10 @@ int CapsuleMesh::get_radial_segments() const {
}
void CapsuleMesh::set_rings(const int p_rings) {
if (rings == p_rings) {
return;
}
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@ -613,7 +688,6 @@ void BoxMesh::_update_lightmap_size() {
if (get_add_uv2()) {
// size must have changed, update lightmap size hint
Size2i _lightmap_size_hint;
float texel_size = get_lightmap_texel_size();
float padding = get_uv2_padding();
float width = (size.x + size.z) / texel_size;
@ -632,7 +706,6 @@ void BoxMesh::_create_mesh_array(Array &p_arr) const {
// With 3 faces along the width and 2 along the height of the texture we need to adjust our scale
// accordingly.
bool _add_uv2 = get_add_uv2();
float texel_size = get_lightmap_texel_size();
float _uv2_padding = get_uv2_padding() * texel_size;
BoxMesh::create_mesh_array(p_arr, size, subdivide_w, subdivide_h, subdivide_d, _add_uv2, _uv2_padding);
@ -891,6 +964,10 @@ void BoxMesh::_bind_methods() {
}
void BoxMesh::set_size(const Vector3 &p_size) {
if (p_size.is_equal_approx(size)) {
return;
}
size = p_size;
_update_lightmap_size();
request_update();
@ -901,6 +978,10 @@ Vector3 BoxMesh::get_size() const {
}
void BoxMesh::set_subdivide_width(const int p_divisions) {
if (p_divisions == subdivide_w) {
return;
}
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -910,6 +991,10 @@ int BoxMesh::get_subdivide_width() const {
}
void BoxMesh::set_subdivide_height(const int p_divisions) {
if (p_divisions == subdivide_h) {
return;
}
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -919,6 +1004,10 @@ int BoxMesh::get_subdivide_height() const {
}
void BoxMesh::set_subdivide_depth(const int p_divisions) {
if (p_divisions == subdivide_d) {
return;
}
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -937,7 +1026,6 @@ void CylinderMesh::_update_lightmap_size() {
if (get_add_uv2()) {
// size must have changed, update lightmap size hint
Size2i _lightmap_size_hint;
float texel_size = get_lightmap_texel_size();
float padding = get_uv2_padding();
float top_circumference = top_radius * Math_PI * 2.0;
@ -957,7 +1045,6 @@ void CylinderMesh::_update_lightmap_size() {
void CylinderMesh::_create_mesh_array(Array &p_arr) const {
bool _add_uv2 = get_add_uv2();
float texel_size = get_lightmap_texel_size();
float _uv2_padding = get_uv2_padding() * texel_size;
create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom, _add_uv2, _uv2_padding);
@ -974,11 +1061,11 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
float height_v = height / vertical_length;
float padding_v = p_uv2_padding / vertical_length;
float horizonal_length = MAX(MAX(2.0 * (top_radius + bottom_radius + p_uv2_padding), top_circumference + p_uv2_padding), bottom_circumference + p_uv2_padding);
float center_h = 0.5 * (horizonal_length - p_uv2_padding) / horizonal_length;
float top_h = top_circumference / horizonal_length;
float bottom_h = bottom_circumference / horizonal_length;
float padding_h = p_uv2_padding / horizonal_length;
float horizontal_length = MAX(MAX(2.0 * (top_radius + bottom_radius + p_uv2_padding), top_circumference + p_uv2_padding), bottom_circumference + p_uv2_padding);
float center_h = 0.5 * (horizontal_length - p_uv2_padding) / horizontal_length;
float top_h = top_circumference / horizontal_length;
float bottom_h = bottom_circumference / horizontal_length;
float padding_h = p_uv2_padding / horizontal_length;
Vector<Vector3> points;
Vector<Vector3> normals;
@ -1011,8 +1098,13 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
u = i;
u /= radial_segments;
x = sin(u * Math_TAU);
z = cos(u * Math_TAU);
if (i == radial_segments) {
x = 0.0;
z = 1.0;
} else {
x = Math::sin(u * Math_TAU);
z = Math::cos(u * Math_TAU);
}
Vector3 p = Vector3(x * radius, y, z * radius);
points.push_back(p);
@ -1040,9 +1132,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
}
// Adjust for bottom section, only used if we calculate UV2s.
top_h = top_radius / horizonal_length;
top_h = top_radius / horizontal_length;
float top_v = top_radius / vertical_length;
bottom_h = bottom_radius / horizonal_length;
bottom_h = bottom_radius / horizontal_length;
float bottom_v = bottom_radius / vertical_length;
// Add top.
@ -1063,8 +1155,13 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
float r = i;
r /= radial_segments;
x = sin(r * Math_TAU);
z = cos(r * Math_TAU);
if (i == radial_segments) {
x = 0.0;
z = 1.0;
} else {
x = Math::sin(r * Math_TAU);
z = Math::cos(r * Math_TAU);
}
u = ((x + 1.0) * 0.25);
v = 0.5 + ((z + 1.0) * 0.25);
@ -1105,8 +1202,13 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
float r = i;
r /= radial_segments;
x = sin(r * Math_TAU);
z = cos(r * Math_TAU);
if (i == radial_segments) {
x = 0.0;
z = 1.0;
} else {
x = Math::sin(r * Math_TAU);
z = Math::cos(r * Math_TAU);
}
u = 0.5 + ((x + 1.0) * 0.25);
v = 1.0 - ((z + 1.0) * 0.25);
@ -1168,6 +1270,10 @@ void CylinderMesh::_bind_methods() {
}
void CylinderMesh::set_top_radius(const float p_radius) {
if (Math::is_equal_approx(p_radius, top_radius)) {
return;
}
top_radius = p_radius;
_update_lightmap_size();
request_update();
@ -1178,6 +1284,10 @@ float CylinderMesh::get_top_radius() const {
}
void CylinderMesh::set_bottom_radius(const float p_radius) {
if (Math::is_equal_approx(p_radius, bottom_radius)) {
return;
}
bottom_radius = p_radius;
_update_lightmap_size();
request_update();
@ -1188,6 +1298,10 @@ float CylinderMesh::get_bottom_radius() const {
}
void CylinderMesh::set_height(const float p_height) {
if (Math::is_equal_approx(p_height, height)) {
return;
}
height = p_height;
_update_lightmap_size();
request_update();
@ -1198,6 +1312,10 @@ float CylinderMesh::get_height() const {
}
void CylinderMesh::set_radial_segments(const int p_segments) {
if (p_segments == radial_segments) {
return;
}
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@ -1207,6 +1325,10 @@ int CylinderMesh::get_radial_segments() const {
}
void CylinderMesh::set_rings(const int p_rings) {
if (p_rings == rings) {
return;
}
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@ -1217,6 +1339,10 @@ int CylinderMesh::get_rings() const {
}
void CylinderMesh::set_cap_top(bool p_cap_top) {
if (p_cap_top == cap_top) {
return;
}
cap_top = p_cap_top;
request_update();
}
@ -1226,6 +1352,10 @@ bool CylinderMesh::is_cap_top() const {
}
void CylinderMesh::set_cap_bottom(bool p_cap_bottom) {
if (p_cap_bottom == cap_bottom) {
return;
}
cap_bottom = p_cap_bottom;
request_update();
}
@ -1244,7 +1374,6 @@ void PlaneMesh::_update_lightmap_size() {
if (get_add_uv2()) {
// size must have changed, update lightmap size hint
Size2i _lightmap_size_hint;
float texel_size = get_lightmap_texel_size();
float padding = get_uv2_padding();
_lightmap_size_hint.x = MAX(1.0, (size.x / texel_size) + padding);
@ -1361,6 +1490,9 @@ void PlaneMesh::_bind_methods() {
}
void PlaneMesh::set_size(const Size2 &p_size) {
if (p_size == size) {
return;
}
size = p_size;
_update_lightmap_size();
request_update();
@ -1371,6 +1503,9 @@ Size2 PlaneMesh::get_size() const {
}
void PlaneMesh::set_subdivide_width(const int p_divisions) {
if (p_divisions == subdivide_w || (subdivide_w == 0 && p_divisions < 0)) {
return;
}
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -1380,6 +1515,9 @@ int PlaneMesh::get_subdivide_width() const {
}
void PlaneMesh::set_subdivide_depth(const int p_divisions) {
if (p_divisions == subdivide_d || (subdivide_d == 0 && p_divisions < 0)) {
return;
}
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -1389,6 +1527,9 @@ int PlaneMesh::get_subdivide_depth() const {
}
void PlaneMesh::set_center_offset(const Vector3 p_offset) {
if (p_offset.is_equal_approx(center_offset)) {
return;
}
center_offset = p_offset;
request_update();
}
@ -1398,6 +1539,9 @@ Vector3 PlaneMesh::get_center_offset() const {
}
void PlaneMesh::set_orientation(const Orientation p_orientation) {
if (p_orientation == orientation) {
return;
}
orientation = p_orientation;
request_update();
}
@ -1416,7 +1560,6 @@ void PrismMesh::_update_lightmap_size() {
if (get_add_uv2()) {
// size must have changed, update lightmap size hint
Size2i _lightmap_size_hint;
float texel_size = get_lightmap_texel_size();
float padding = get_uv2_padding();
// left_to_right does not effect the surface area of the prism so we ignore that.
@ -1440,7 +1583,6 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
// Only used if we calculate UV2
bool _add_uv2 = get_add_uv2();
float texel_size = get_lightmap_texel_size();
float _uv2_padding = get_uv2_padding() * texel_size;
float horizontal_total = size.x + size.z + 2.0 * _uv2_padding;
@ -1707,6 +1849,9 @@ void PrismMesh::_bind_methods() {
}
void PrismMesh::set_left_to_right(const float p_left_to_right) {
if (Math::is_equal_approx(p_left_to_right, left_to_right)) {
return;
}
left_to_right = p_left_to_right;
request_update();
}
@ -1716,6 +1861,9 @@ float PrismMesh::get_left_to_right() const {
}
void PrismMesh::set_size(const Vector3 &p_size) {
if (p_size.is_equal_approx(size)) {
return;
}
size = p_size;
_update_lightmap_size();
request_update();
@ -1726,6 +1874,9 @@ Vector3 PrismMesh::get_size() const {
}
void PrismMesh::set_subdivide_width(const int p_divisions) {
if (p_divisions == subdivide_w || (p_divisions < 0 && subdivide_w == 0)) {
return;
}
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -1735,6 +1886,9 @@ int PrismMesh::get_subdivide_width() const {
}
void PrismMesh::set_subdivide_height(const int p_divisions) {
if (p_divisions == subdivide_h || (p_divisions < 0 && subdivide_h == 0)) {
return;
}
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -1744,6 +1898,9 @@ int PrismMesh::get_subdivide_height() const {
}
void PrismMesh::set_subdivide_depth(const int p_divisions) {
if (p_divisions == subdivide_d || (p_divisions < 0 && subdivide_d == 0)) {
return;
}
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@ -1762,7 +1919,6 @@ void SphereMesh::_update_lightmap_size() {
if (get_add_uv2()) {
// size must have changed, update lightmap size hint
Size2i _lightmap_size_hint;
float texel_size = get_lightmap_texel_size();
float padding = get_uv2_padding();
float _width = radius * Math_TAU;
@ -1776,7 +1932,6 @@ void SphereMesh::_update_lightmap_size() {
void SphereMesh::_create_mesh_array(Array &p_arr) const {
bool _add_uv2 = get_add_uv2();
float texel_size = get_lightmap_texel_size();
float _uv2_padding = get_uv2_padding() * texel_size;
create_mesh_array(p_arr, radius, height, radial_segments, rings, is_hemisphere, _add_uv2, _uv2_padding);
@ -1786,14 +1941,14 @@ void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int
int i, j, prevrow, thisrow, point;
float x, y, z;
float scale = height * (is_hemisphere ? 1.0 : 0.5);
float scale = height / radius * (is_hemisphere ? 1.0 : 0.5);
// Only used if we calculate UV2
float circumference = radius * Math_TAU;
float horizontal_length = circumference + p_uv2_padding;
float center_h = 0.5 * circumference / horizontal_length;
float height_v = scale * Math_PI / ((scale * Math_PI) + p_uv2_padding);
float height_v = scale * Math_PI / ((scale * Math_PI) + p_uv2_padding / radius);
// set our bounding box
@ -1818,23 +1973,33 @@ void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int
float w;
v /= (rings + 1);
w = sin(Math_PI * v);
y = scale * cos(Math_PI * v);
if (j == (rings + 1)) {
w = 0.0;
y = -1.0;
} else {
w = Math::sin(Math_PI * v);
y = Math::cos(Math_PI * v);
}
for (i = 0; i <= radial_segments; i++) {
float u = i;
u /= radial_segments;
x = sin(u * Math_TAU);
z = cos(u * Math_TAU);
if (i == radial_segments) {
x = 0.0;
z = 1.0;
} else {
x = Math::sin(u * Math_TAU);
z = Math::cos(u * Math_TAU);
}
if (is_hemisphere && y < 0.0) {
points.push_back(Vector3(x * radius * w, 0.0, z * radius * w));
normals.push_back(Vector3(0.0, -1.0, 0.0));
} else {
Vector3 p = Vector3(x * radius * w, y, z * radius * w);
points.push_back(p);
Vector3 normal = Vector3(x * w * scale, radius * (y / scale), z * w * scale);
Vector3 p = Vector3(x * w, y * scale, z * w);
points.push_back(p * radius);
Vector3 normal = Vector3(x * w * scale, y, z * w * scale);
normals.push_back(normal.normalized());
}
ADD_TANGENT(z, 0.0, -x, 1.0)
@ -1892,6 +2057,9 @@ void SphereMesh::_bind_methods() {
}
void SphereMesh::set_radius(const float p_radius) {
if (Math::is_equal_approx(p_radius, radius)) {
return;
}
radius = p_radius;
_update_lightmap_size();
request_update();
@ -1902,6 +2070,9 @@ float SphereMesh::get_radius() const {
}
void SphereMesh::set_height(const float p_height) {
if (Math::is_equal_approx(height, p_height)) {
return;
}
height = p_height;
_update_lightmap_size();
request_update();
@ -1912,6 +2083,9 @@ float SphereMesh::get_height() const {
}
void SphereMesh::set_radial_segments(const int p_radial_segments) {
if (p_radial_segments == radial_segments || (radial_segments == 4 && p_radial_segments < 4)) {
return;
}
radial_segments = p_radial_segments > 4 ? p_radial_segments : 4;
request_update();
}
@ -1921,6 +2095,9 @@ int SphereMesh::get_radial_segments() const {
}
void SphereMesh::set_rings(const int p_rings) {
if (p_rings == rings) {
return;
}
ERR_FAIL_COND(p_rings < 1);
rings = p_rings;
request_update();
@ -1931,6 +2108,9 @@ int SphereMesh::get_rings() const {
}
void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) {
if (p_is_hemisphere == is_hemisphere) {
return;
}
is_hemisphere = p_is_hemisphere;
_update_lightmap_size();
request_update();
@ -1950,7 +2130,6 @@ void TorusMesh::_update_lightmap_size() {
if (get_add_uv2()) {
// size must have changed, update lightmap size hint
Size2i _lightmap_size_hint;
float texel_size = get_lightmap_texel_size();
float padding = get_uv2_padding();
float min_radius = inner_radius;
@ -2000,7 +2179,6 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
// Only used if we calculate UV2
bool _add_uv2 = get_add_uv2();
float texel_size = get_lightmap_texel_size();
float _uv2_padding = get_uv2_padding() * texel_size;
float horizontal_total = max_radius * Math_TAU + _uv2_padding;
@ -2015,13 +2193,13 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
float inci = float(i) / rings;
float angi = inci * Math_TAU;
Vector2 normali = Vector2(-Math::sin(angi), -Math::cos(angi));
Vector2 normali = (i == rings) ? Vector2(0.0, -1.0) : Vector2(-Math::sin(angi), -Math::cos(angi));
for (int j = 0; j <= ring_segments; j++) {
float incj = float(j) / ring_segments;
float angj = incj * Math_TAU;
Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj));
Vector2 normalj = (j == ring_segments) ? Vector2(-1.0, 0.0) : Vector2(-Math::cos(angj), Math::sin(angj));
Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0);
float offset_h = 0.5 * (1.0 - normalj.x) * delta_h;
@ -2030,7 +2208,7 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
points.push_back(Vector3(normali.x * normalk.x, normalk.y, normali.y * normalk.x));
normals.push_back(Vector3(normali.x * normalj.x, normalj.y, normali.y * normalj.x));
ADD_TANGENT(-Math::cos(angi), 0.0, Math::sin(angi), 1.0);
ADD_TANGENT(normali.y, 0.0, -normali.x, 1.0);
uvs.push_back(Vector2(inci, incj));
if (_add_uv2) {
uv2s.push_back(Vector2(offset_h + inci * adj_h, incj * height_v));
@ -2078,6 +2256,9 @@ void TorusMesh::_bind_methods() {
}
void TorusMesh::set_inner_radius(const float p_inner_radius) {
if (Math::is_equal_approx(p_inner_radius, inner_radius)) {
return;
}
inner_radius = p_inner_radius;
request_update();
}
@ -2087,6 +2268,9 @@ float TorusMesh::get_inner_radius() const {
}
void TorusMesh::set_outer_radius(const float p_outer_radius) {
if (Math::is_equal_approx(p_outer_radius, outer_radius)) {
return;
}
outer_radius = p_outer_radius;
request_update();
}
@ -2096,6 +2280,9 @@ float TorusMesh::get_outer_radius() const {
}
void TorusMesh::set_rings(const int p_rings) {
if (p_rings == rings) {
return;
}
ERR_FAIL_COND(p_rings < 3);
rings = p_rings;
request_update();
@ -2106,6 +2293,9 @@ int TorusMesh::get_rings() const {
}
void TorusMesh::set_ring_segments(const int p_ring_segments) {
if (p_ring_segments == ring_segments) {
return;
}
ERR_FAIL_COND(p_ring_segments < 3);
ring_segments = p_ring_segments;
request_update();
@ -2135,6 +2325,9 @@ PointMesh::PointMesh() {
// TUBE TRAIL
void TubeTrailMesh::set_radius(const float p_radius) {
if (Math::is_equal_approx(p_radius, radius)) {
return;
}
radius = p_radius;
request_update();
}
@ -2143,6 +2336,9 @@ float TubeTrailMesh::get_radius() const {
}
void TubeTrailMesh::set_radial_steps(const int p_radial_steps) {
if (p_radial_steps == radial_steps) {
return;
}
ERR_FAIL_COND(p_radial_steps < 3 || p_radial_steps > 128);
radial_steps = p_radial_steps;
request_update();
@ -2152,6 +2348,9 @@ int TubeTrailMesh::get_radial_steps() const {
}
void TubeTrailMesh::set_sections(const int p_sections) {
if (p_sections == sections) {
return;
}
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@ -2161,6 +2360,9 @@ int TubeTrailMesh::get_sections() const {
}
void TubeTrailMesh::set_section_length(float p_section_length) {
if (p_section_length == section_length) {
return;
}
section_length = p_section_length;
request_update();
}
@ -2169,6 +2371,9 @@ float TubeTrailMesh::get_section_length() const {
}
void TubeTrailMesh::set_section_rings(const int p_section_rings) {
if (p_section_rings == section_rings) {
return;
}
ERR_FAIL_COND(p_section_rings < 1 || p_section_rings > 1024);
section_rings = p_section_rings;
request_update();
@ -2178,6 +2383,9 @@ int TubeTrailMesh::get_section_rings() const {
}
void TubeTrailMesh::set_cap_top(bool p_cap_top) {
if (p_cap_top == cap_top) {
return;
}
cap_top = p_cap_top;
request_update();
}
@ -2187,6 +2395,9 @@ bool TubeTrailMesh::is_cap_top() const {
}
void TubeTrailMesh::set_cap_bottom(bool p_cap_bottom) {
if (p_cap_bottom == cap_bottom) {
return;
}
cap_bottom = p_cap_bottom;
request_update();
}
@ -2272,8 +2483,12 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
if (curve.is_valid() && curve->get_point_count() > 0) {
r *= curve->sample_baked(v);
}
float x = sin(u * Math_TAU);
float z = cos(u * Math_TAU);
float x = 0.0;
float z = 1.0;
if (i < radial_steps) {
x = Math::sin(u * Math_TAU);
z = Math::cos(u * Math_TAU);
}
Vector3 p = Vector3(x * r, y, z * r);
points.push_back(p);
@ -2341,8 +2556,12 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
float r = i;
r /= radial_steps;
float x = sin(r * Math_TAU);
float z = cos(r * Math_TAU);
float x = 0.0;
float z = 1.0;
if (i < radial_steps) {
x = Math::sin(r * Math_TAU);
z = Math::cos(r * Math_TAU);
}
float u = ((x + 1.0) * 0.25);
float v = 0.5 + ((z + 1.0) * 0.25);
@ -2406,8 +2625,12 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
float r = i;
r /= radial_steps;
float x = sin(r * Math_TAU);
float z = cos(r * Math_TAU);
float x = 0.0;
float z = 1.0;
if (i < radial_steps) {
x = Math::sin(r * Math_TAU);
z = Math::cos(r * Math_TAU);
}
float u = 0.5 + ((x + 1.0) * 0.25);
float v = 1.0 - ((z + 1.0) * 0.25);
@ -2493,6 +2716,9 @@ TubeTrailMesh::TubeTrailMesh() {
// RIBBON TRAIL
void RibbonTrailMesh::set_shape(Shape p_shape) {
if (p_shape == shape) {
return;
}
shape = p_shape;
request_update();
}
@ -2501,6 +2727,9 @@ RibbonTrailMesh::Shape RibbonTrailMesh::get_shape() const {
}
void RibbonTrailMesh::set_size(const float p_size) {
if (Math::is_equal_approx(p_size, size)) {
return;
}
size = p_size;
request_update();
}
@ -2509,6 +2738,9 @@ float RibbonTrailMesh::get_size() const {
}
void RibbonTrailMesh::set_sections(const int p_sections) {
if (p_sections == sections) {
return;
}
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@ -2518,6 +2750,9 @@ int RibbonTrailMesh::get_sections() const {
}
void RibbonTrailMesh::set_section_length(float p_section_length) {
if (p_section_length == section_length) {
return;
}
section_length = p_section_length;
request_update();
}
@ -2526,6 +2761,9 @@ float RibbonTrailMesh::get_section_length() const {
}
void RibbonTrailMesh::set_section_segments(const int p_section_segments) {
if (p_section_segments == section_segments) {
return;
}
ERR_FAIL_COND(p_section_segments < 1 || p_section_segments > 1024);
section_segments = p_section_segments;
request_update();
@ -3468,13 +3706,13 @@ Ref<Font> TextMesh::_get_font_or_default() const {
}
StringName theme_name = "font";
List<StringName> theme_types;
ThemeDB::get_singleton()->get_native_type_dependencies(get_class_name(), &theme_types);
Vector<StringName> theme_types;
ThemeDB::get_singleton()->get_native_type_dependencies(get_class_name(), theme_types);
ThemeContext *global_context = ThemeDB::get_singleton()->get_default_theme_context();
List<Ref<Theme>> themes = global_context->get_themes();
Vector<Ref<Theme>> themes = global_context->get_themes();
if (Engine::get_singleton()->is_editor_hint()) {
themes.push_front(ThemeDB::get_singleton()->get_project_theme());
themes.insert(0, ThemeDB::get_singleton()->get_project_theme());
}
for (const Ref<Theme> &theme : themes) {

View file

@ -67,6 +67,9 @@ protected:
// assume primitive triangles as the type, correct for all but one and it will change this :)
Mesh::PrimitiveType primitive_type = Mesh::PRIMITIVE_TRIANGLES;
// Copy of our texel_size project setting.
float texel_size = 0.2;
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const {}
@ -74,7 +77,9 @@ protected:
Vector2 get_uv2_scale(Vector2 p_margin_scale = Vector2(1.0, 1.0)) const;
float get_lightmap_texel_size() const;
virtual void _update_lightmap_size(){};
virtual void _update_lightmap_size() {}
void _on_settings_changed();
public:
virtual int get_surface_count() const override;
@ -536,17 +541,17 @@ private:
Vector2 point;
bool sharp = false;
ContourPoint(){};
ContourPoint() {}
ContourPoint(const Vector2 &p_pt, bool p_sharp) {
point = p_pt;
sharp = p_sharp;
};
}
};
struct ContourInfo {
real_t length = 0.0;
bool ccw = true;
ContourInfo(){};
ContourInfo() {}
ContourInfo(real_t p_len, bool p_ccw) {
length = p_len;
ccw = p_ccw;

View file

@ -30,6 +30,7 @@
#include "separation_ray_shape_3d.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> SeparationRayShape3D::get_debug_mesh_lines() const {
@ -41,6 +42,10 @@ Vector<Vector3> SeparationRayShape3D::get_debug_mesh_lines() const {
return points;
}
Ref<ArrayMesh> SeparationRayShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
return memnew(ArrayMesh);
}
real_t SeparationRayShape3D::get_enclosing_radius() const {
return length;
}

View file

@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class SeparationRayShape3D : public Shape3D {
GDCLASS(SeparationRayShape3D, Shape3D);
float length = 1.0;
@ -50,6 +52,7 @@ public:
bool get_slide_on_slope() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SeparationRayShape3D();

View file

@ -30,7 +30,6 @@
#include "shape_3d.h"
#include "core/os/os.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
@ -66,6 +65,38 @@ void Shape3D::set_margin(real_t p_margin) {
PhysicsServer3D::get_singleton()->shape_set_margin(shape, margin);
}
void Shape3D::set_debug_color(const Color &p_color) {
if (p_color == debug_color) {
return;
}
debug_color = p_color;
#ifdef DEBUG_ENABLED
debug_properties_edited = true;
#endif // DEBUG_ENABLED
_update_shape();
}
Color Shape3D::get_debug_color() const {
return debug_color;
}
void Shape3D::set_debug_fill(bool p_fill) {
if (p_fill == debug_fill) {
return;
}
debug_fill = p_fill;
#ifdef DEBUG_ENABLED
debug_properties_edited = true;
#endif // DEBUG_ENABLED
_update_shape();
}
bool Shape3D::get_debug_fill() const {
return debug_fill;
}
Ref<ArrayMesh> Shape3D::get_debug_mesh() {
if (debug_mesh_cache.is_valid()) {
return debug_mesh_cache;
@ -73,35 +104,66 @@ Ref<ArrayMesh> Shape3D::get_debug_mesh() {
Vector<Vector3> lines = get_debug_mesh_lines();
debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh));
debug_mesh_cache.instantiate();
if (!lines.is_empty()) {
//make mesh
Vector<Vector3> array;
array.resize(lines.size());
{
Vector3 *w = array.ptrw();
for (int i = 0; i < lines.size(); i++) {
w[i] = lines[i];
}
Vector3 *v = array.ptrw();
Vector<Color> arraycol;
arraycol.resize(lines.size());
Color *c = arraycol.ptrw();
for (int i = 0; i < lines.size(); i++) {
v[i] = lines[i];
c[i] = debug_color;
}
Array arr;
arr.resize(Mesh::ARRAY_MAX);
arr[Mesh::ARRAY_VERTEX] = array;
Array lines_array;
lines_array.resize(Mesh::ARRAY_MAX);
lines_array[Mesh::ARRAY_VERTEX] = array;
lines_array[Mesh::ARRAY_COLOR] = arraycol;
SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
Ref<StandardMaterial3D> material = get_debug_collision_material();
debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, lines_array);
debug_mesh_cache->surface_set_material(0, material);
if (st) {
debug_mesh_cache->surface_set_material(0, st->get_debug_collision_material());
if (debug_fill) {
Ref<ArrayMesh> array_mesh = get_debug_arraymesh_faces(debug_color * Color(1.0, 1.0, 1.0, 0.0625));
if (array_mesh.is_valid() && array_mesh->get_surface_count() > 0) {
Array solid_array = array_mesh->surface_get_arrays(0);
debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, solid_array);
debug_mesh_cache->surface_set_material(1, material);
}
}
}
return debug_mesh_cache;
}
Ref<Material> Shape3D::get_debug_collision_material() {
if (collision_material.is_valid()) {
return collision_material;
}
Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
material->set_albedo(Color(1.0, 1.0, 1.0));
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
material->set_cull_mode(StandardMaterial3D::CULL_BACK);
material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
collision_material = material;
return collision_material;
}
void Shape3D::_update_shape() {
emit_changed();
debug_mesh_cache.unref();

View file

@ -34,6 +34,7 @@
#include "core/io/resource.h"
class ArrayMesh;
class Material;
class Shape3D : public Resource {
GDCLASS(Shape3D, Resource);
@ -44,6 +45,14 @@ class Shape3D : public Resource {
real_t margin = 0.04;
Ref<ArrayMesh> debug_mesh_cache;
Ref<Material> collision_material;
// Not wrapped in `#ifdef DEBUG_ENABLED` as it is used for rendering.
Color debug_color = Color(0.0, 0.0, 0.0, 0.0);
bool debug_fill = true;
#ifdef DEBUG_ENABLED
bool debug_properties_edited = false;
#endif // DEBUG_ENABLED
protected:
static void _bind_methods();
@ -51,6 +60,8 @@ protected:
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape3D(RID p_shape);
Ref<Material> get_debug_collision_material();
virtual void _update_shape();
public:
@ -58,6 +69,7 @@ public:
Ref<ArrayMesh> get_debug_mesh();
virtual Vector<Vector3> get_debug_mesh_lines() const = 0; // { return Vector<Vector3>(); }
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const = 0;
/// Returns the radius of a sphere that fully enclose this shape
virtual real_t get_enclosing_radius() const = 0;
@ -69,6 +81,16 @@ public:
real_t get_margin() const;
void set_margin(real_t p_margin);
void set_debug_color(const Color &p_color);
Color get_debug_color() const;
void set_debug_fill(bool p_fill);
bool get_debug_fill() const;
#ifdef DEBUG_ENABLED
_FORCE_INLINE_ bool are_debug_properties_edited() const { return debug_properties_edited; }
#endif // DEBUG_ENABLED
Shape3D();
~Shape3D();
};

View file

@ -269,7 +269,7 @@ void ProceduralSkyMaterial::cleanup_shader() {
}
void ProceduralSkyMaterial::_update_shader() {
shader_mutex.lock();
MutexLock shader_lock(shader_mutex);
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = RS::get_singleton()->shader_create();
@ -354,10 +354,10 @@ void sky() {
i ? "render_mode use_debanding;" : ""));
}
}
shader_mutex.unlock();
}
ProceduralSkyMaterial::ProceduralSkyMaterial() {
_set_material(RS::get_singleton()->material_create());
set_sky_top_color(Color(0.385, 0.454, 0.55));
set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_sky_curve(0.15);
@ -463,7 +463,7 @@ void PanoramaSkyMaterial::cleanup_shader() {
}
void PanoramaSkyMaterial::_update_shader() {
shader_mutex.lock();
MutexLock shader_lock(shader_mutex);
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = RS::get_singleton()->shader_create();
@ -484,11 +484,10 @@ void sky() {
i ? "filter_linear" : "filter_nearest"));
}
}
shader_mutex.unlock();
}
PanoramaSkyMaterial::PanoramaSkyMaterial() {
_set_material(RS::get_singleton()->material_create());
set_energy_multiplier(1.0);
}
@ -692,7 +691,7 @@ void PhysicalSkyMaterial::cleanup_shader() {
}
void PhysicalSkyMaterial::_update_shader() {
shader_mutex.lock();
MutexLock shader_lock(shader_mutex);
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = RS::get_singleton()->shader_create();
@ -785,11 +784,10 @@ void sky() {
i ? "render_mode use_debanding;" : ""));
}
}
shader_mutex.unlock();
}
PhysicalSkyMaterial::PhysicalSkyMaterial() {
_set_material(RS::get_singleton()->material_create());
set_rayleigh_coefficient(2.0);
set_rayleigh_color(Color(0.3, 0.405, 0.6));
set_mie_coefficient(0.005);

View file

@ -30,6 +30,7 @@
#include "sphere_shape_3d.h"
#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
@ -54,6 +55,24 @@ Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
return points;
}
Ref<ArrayMesh> SphereShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
Array sphere_array;
sphere_array.resize(RS::ARRAY_MAX);
SphereMesh::create_mesh_array(sphere_array, radius, radius * 2, 32);
Vector<Color> colors;
const PackedVector3Array &verts = sphere_array[RS::ARRAY_VERTEX];
const int32_t verts_size = verts.size();
for (int i = 0; i < verts_size; i++) {
colors.append(p_modulate);
}
Ref<ArrayMesh> sphere_mesh = memnew(ArrayMesh);
sphere_array[RS::ARRAY_COLOR] = colors;
sphere_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, sphere_array);
return sphere_mesh;
}
real_t SphereShape3D::get_enclosing_radius() const {
return radius;
}

View file

@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class SphereShape3D : public Shape3D {
GDCLASS(SphereShape3D, Shape3D);
float radius = 0.5f;
@ -47,6 +49,7 @@ public:
float get_radius() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SphereShape3D();

View file

@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/visible_on_screen_notifier_3d.h"
#include "scene/resources/camera_attributes.h"
#include "scene/resources/environment.h"
#include "servers/navigation_server_3d.h"

View file

@ -30,6 +30,7 @@
#include "world_boundary_shape_3d.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const {
@ -61,6 +62,53 @@ Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const {
return points;
}
Ref<ArrayMesh> WorldBoundaryShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
Plane p = get_plane();
Vector3 n1 = p.get_any_perpendicular_normal();
Vector3 n2 = p.normal.cross(n1).normalized();
Vector3 pface[4] = {
p.normal * p.d + n1 * 10.0 + n2 * 10.0,
p.normal * p.d + n1 * 10.0 + n2 * -10.0,
p.normal * p.d + n1 * -10.0 + n2 * -10.0,
p.normal * p.d + n1 * -10.0 + n2 * 10.0,
};
Vector<Vector3> points = {
pface[0],
pface[1],
pface[2],
pface[3],
};
Vector<Color> colors = {
p_modulate,
p_modulate,
p_modulate,
p_modulate,
};
Vector<int> indices = {
0,
1,
2,
0,
2,
3,
};
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
Array a;
a.resize(Mesh::ARRAY_MAX);
a[RS::ARRAY_VERTEX] = points;
a[RS::ARRAY_COLOR] = colors;
a[RS::ARRAY_INDEX] = indices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
return mesh;
}
void WorldBoundaryShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane);
Shape3D::_update_shape();

View file

@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class WorldBoundaryShape3D : public Shape3D {
GDCLASS(WorldBoundaryShape3D, Shape3D);
Plane plane;
@ -46,6 +48,7 @@ public:
const Plane &get_plane() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override {
// Should be infinite?
return 0;