feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue