initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled

This commit is contained in:
2025-09-16 20:46:46 -04:00
commit 9d30169a8d
13378 changed files with 7050105 additions and 0 deletions

28
scene/resources/3d/SCsub Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
env.add_source_files(env.scene_sources, "fog_material.cpp")
env.add_source_files(env.scene_sources, "importer_mesh.cpp")
env.add_source_files(env.scene_sources, "mesh_library.cpp")
env.add_source_files(env.scene_sources, "primitive_meshes.cpp")
env.add_source_files(env.scene_sources, "skin.cpp")
env.add_source_files(env.scene_sources, "sky_material.cpp")
env.add_source_files(env.scene_sources, "world_3d.cpp")
env.add_source_files(env.scene_sources, "skeleton/*.cpp")
if not env["disable_physics_3d"]:
env.add_source_files(env.scene_sources, "box_shape_3d.cpp")
env.add_source_files(env.scene_sources, "capsule_shape_3d.cpp")
env.add_source_files(env.scene_sources, "circle_shape_3d.cpp")
env.add_source_files(env.scene_sources, "concave_polygon_shape_3d.cpp")
env.add_source_files(env.scene_sources, "convex_polygon_shape_3d.cpp")
env.add_source_files(env.scene_sources, "cylinder_shape_3d.cpp")
env.add_source_files(env.scene_sources, "height_map_shape_3d.cpp")
env.add_source_files(env.scene_sources, "separation_ray_shape_3d.cpp")
env.add_source_files(env.scene_sources, "shape_3d.cpp")
env.add_source_files(env.scene_sources, "sphere_shape_3d.cpp")
env.add_source_files(env.scene_sources, "world_boundary_shape_3d.cpp")
if not env["disable_navigation_3d"]:
env.add_source_files(env.scene_sources, "navigation_mesh_source_geometry_data_3d.cpp")

View File

@@ -0,0 +1,120 @@
/**************************************************************************/
/* box_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
Vector<Vector3> lines;
AABB aabb;
aabb.position = -size / 2;
aabb.size = size;
for (int i = 0; i < 12; i++) {
Vector3 a, b;
aabb.get_edge(i, a, b);
lines.push_back(a);
lines.push_back(b);
}
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;
}
void BoxShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), size / 2);
Shape3D::_update_shape();
}
#ifndef DISABLE_DEPRECATED
bool BoxShape3D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "extents") { // Compatibility with Godot 3.x.
// Convert to `size`, twice as big.
set_size((Vector3)p_value * 2);
return true;
}
return false;
}
bool BoxShape3D::_get(const StringName &p_name, Variant &r_property) const {
if (p_name == "extents") { // Compatibility with Godot 3.x.
// Convert to `extents`, half as big.
r_property = size / 2;
return true;
}
return false;
}
#endif // DISABLE_DEPRECATED
void BoxShape3D::set_size(const Vector3 &p_size) {
ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0 || p_size.z < 0, "BoxShape3D size cannot be negative.");
size = p_size;
_update_shape();
emit_changed();
}
Vector3 BoxShape3D::get_size() const {
return size;
}
void BoxShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxShape3D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &BoxShape3D::get_size);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
}
BoxShape3D::BoxShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_BOX)) {
set_size(Vector3(1, 1, 1));
}

View File

@@ -0,0 +1,57 @@
/**************************************************************************/
/* box_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class BoxShape3D : public Shape3D {
GDCLASS(BoxShape3D, Shape3D);
Vector3 size;
protected:
static void _bind_methods();
#ifndef DISABLE_DEPRECATED
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_property) const;
#endif // DISABLE_DEPRECATED
virtual void _update_shape() override;
public:
void set_size(const Vector3 &p_size);
Vector3 get_size() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
BoxShape3D();
};

View File

@@ -0,0 +1,158 @@
/**************************************************************************/
/* capsule_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
float c_radius = get_radius();
float c_height = get_height();
Vector<Vector3> points;
Vector3 d(0, c_height * 0.5f - c_radius, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg_to_rad((float)i);
float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * c_radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * c_radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
points.push_back(Vector3(b.x, 0, b.y) - d);
if (i % 90 == 0) {
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
}
Vector3 dud = i < 180 ? d : -d;
points.push_back(Vector3(0, a.x, a.y) + dud);
points.push_back(Vector3(0, b.x, b.y) + dud);
points.push_back(Vector3(a.y, a.x, 0) + dud);
points.push_back(Vector3(b.y, b.x, 0) + dud);
}
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.5f;
}
void CapsuleShape3D::_update_shape() {
Dictionary d;
d["radius"] = radius;
d["height"] = height;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void CapsuleShape3D::set_radius(float p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0.0f, "CapsuleShape3D radius cannot be negative.");
radius = p_radius;
if (height < radius * 2.0f) {
height = radius * 2.0f;
}
_update_shape();
emit_changed();
}
float CapsuleShape3D::get_radius() const {
return radius;
}
void CapsuleShape3D::set_height(float p_height) {
ERR_FAIL_COND_MSG(p_height < 0.0f, "CapsuleShape3D height cannot be negative.");
height = p_height;
if (radius > height * 0.5f) {
radius = height * 0.5f;
}
_update_shape();
emit_changed();
}
float CapsuleShape3D::get_height() const {
return height;
}
void CapsuleShape3D::set_mid_height(real_t p_mid_height) {
ERR_FAIL_COND_MSG(p_mid_height < 0.0f, "CapsuleShape3D mid-height cannot be negative.");
height = p_mid_height + radius * 2.0f;
_update_shape();
emit_changed();
}
real_t CapsuleShape3D::get_mid_height() const {
return height - radius * 2.0f;
}
void CapsuleShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleShape3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleShape3D::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape3D::get_height);
ClassDB::bind_method(D_METHOD("set_mid_height", "mid_height"), &CapsuleShape3D::set_mid_height);
ClassDB::bind_method(D_METHOD("get_mid_height"), &CapsuleShape3D::get_mid_height);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mid_height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m", PROPERTY_USAGE_NONE), "set_mid_height", "get_mid_height");
ADD_LINKED_PROPERTY("radius", "height");
ADD_LINKED_PROPERTY("height", "radius");
}
CapsuleShape3D::CapsuleShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CAPSULE)) {
_update_shape();
}

View File

@@ -0,0 +1,60 @@
/**************************************************************************/
/* capsule_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class CapsuleShape3D : public Shape3D {
GDCLASS(CapsuleShape3D, Shape3D);
float radius = 0.5;
float height = 2.0;
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_radius(float p_radius);
float get_radius() const;
void set_height(float p_height);
float get_height() const;
void set_mid_height(real_t p_mid_height);
real_t get_mid_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CapsuleShape3D();
};

View File

@@ -0,0 +1,136 @@
/**************************************************************************/
/* concave_polygon_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
HashSet<DrawEdge, DrawEdge> edges;
int index_count = faces.size();
ERR_FAIL_COND_V((index_count % 3) != 0, Vector<Vector3>());
const Vector3 *r = faces.ptr();
for (int i = 0; i < index_count; i += 3) {
for (int j = 0; j < 3; j++) {
DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]);
edges.insert(de);
}
}
Vector<Vector3> points;
points.resize(edges.size() * 2);
int idx = 0;
for (const DrawEdge &E : edges) {
points.write[idx + 0] = E.a;
points.write[idx + 1] = E.b;
idx += 2;
}
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();
real_t r = 0.0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
return Math::sqrt(r);
}
void ConcavePolygonShape3D::_update_shape() {
Dictionary d;
d["faces"] = faces;
d["backface_collision"] = backface_collision;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) {
faces = p_faces;
_update_shape();
emit_changed();
}
Vector<Vector3> ConcavePolygonShape3D::get_faces() const {
return faces;
}
void ConcavePolygonShape3D::set_backface_collision_enabled(bool p_enabled) {
backface_collision = p_enabled;
if (!faces.is_empty()) {
_update_shape();
emit_changed();
}
}
bool ConcavePolygonShape3D::is_backface_collision_enabled() const {
return backface_collision;
}
void ConcavePolygonShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape3D::set_faces);
ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape3D::get_faces);
ClassDB::bind_method(D_METHOD("set_backface_collision_enabled", "enabled"), &ConcavePolygonShape3D::set_backface_collision_enabled);
ClassDB::bind_method(D_METHOD("is_backface_collision_enabled"), &ConcavePolygonShape3D::is_backface_collision_enabled);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "backface_collision"), "set_backface_collision_enabled", "is_backface_collision_enabled");
}
ConcavePolygonShape3D::ConcavePolygonShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON)) {
//set_planes(Vector3(1,1,1));
}

View File

@@ -0,0 +1,80 @@
/**************************************************************************/
/* concave_polygon_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class ConcavePolygonShape3D : public Shape3D {
GDCLASS(ConcavePolygonShape3D, Shape3D);
Vector<Vector3> faces;
bool backface_collision = false;
struct DrawEdge {
Vector3 a;
Vector3 b;
static uint32_t hash(const DrawEdge &p_edge) {
uint32_t h = hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.a));
return hash_murmur3_one_32(HashMapHasherDefault::hash(p_edge.b), h);
}
bool operator==(const DrawEdge &p_edge) const {
return (a == p_edge.a && b == p_edge.b);
}
DrawEdge(const Vector3 &p_a = Vector3(), const Vector3 &p_b = Vector3()) {
a = p_a;
b = p_b;
if (a < b) {
SWAP(a, b);
}
}
};
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_faces(const Vector<Vector3> &p_faces);
Vector<Vector3> get_faces() const;
void set_backface_collision_enabled(bool p_enabled);
bool is_backface_collision_enabled() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConcavePolygonShape3D();
};

View File

@@ -0,0 +1,129 @@
/**************************************************************************/
/* convex_polygon_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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() > 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);
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
for (uint32_t i = 0; i < md.edges.size(); i++) {
lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
}
return lines;
}
}
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();
real_t r = 0.0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
return Math::sqrt(r);
}
void ConvexPolygonShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), points);
Shape3D::_update_shape();
}
void ConvexPolygonShape3D::set_points(const Vector<Vector3> &p_points) {
points = p_points;
_update_shape();
emit_changed();
}
Vector<Vector3> ConvexPolygonShape3D::get_points() const {
return points;
}
void ConvexPolygonShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_points", "points"), &ConvexPolygonShape3D::set_points);
ClassDB::bind_method(D_METHOD("get_points"), &ConvexPolygonShape3D::get_points);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "points"), "set_points", "get_points");
}
ConvexPolygonShape3D::ConvexPolygonShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON)) {
}

View File

@@ -0,0 +1,55 @@
/**************************************************************************/
/* convex_polygon_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class ConvexPolygonShape3D : public Shape3D {
GDCLASS(ConvexPolygonShape3D, Shape3D);
Vector<Vector3> points;
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_points(const Vector<Vector3> &p_points);
Vector<Vector3> get_points() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConvexPolygonShape3D();
};

View File

@@ -0,0 +1,129 @@
/**************************************************************************/
/* cylinder_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
float c_radius = get_radius();
float c_height = get_height();
Vector<Vector3> points;
Vector3 d(0, c_height * 0.5, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg_to_rad((float)i);
float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * c_radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * c_radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
points.push_back(Vector3(b.x, 0, b.y) - d);
if (i % 90 == 0) {
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
}
}
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();
}
void CylinderShape3D::_update_shape() {
Dictionary d;
d["radius"] = radius;
d["height"] = height;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void CylinderShape3D::set_radius(float p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0, "CylinderShape3D radius cannot be negative.");
radius = p_radius;
_update_shape();
emit_changed();
}
float CylinderShape3D::get_radius() const {
return radius;
}
void CylinderShape3D::set_height(float p_height) {
ERR_FAIL_COND_MSG(p_height < 0, "CylinderShape3D height cannot be negative.");
height = p_height;
_update_shape();
emit_changed();
}
float CylinderShape3D::get_height() const {
return height;
}
void CylinderShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape3D::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape3D::get_height);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
CylinderShape3D::CylinderShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CYLINDER)) {
_update_shape();
}

View File

@@ -0,0 +1,57 @@
/**************************************************************************/
/* cylinder_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class CylinderShape3D : public Shape3D {
GDCLASS(CylinderShape3D, Shape3D);
float radius = 0.5;
float height = 2.0;
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_radius(float p_radius);
float get_radius() const;
void set_height(float p_height);
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CylinderShape3D();
};

View File

@@ -0,0 +1,183 @@
/**************************************************************************/
/* fog_material.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "fog_material.h"
#include "core/version.h"
Mutex FogMaterial::shader_mutex;
RID FogMaterial::shader;
void FogMaterial::set_density(float p_density) {
density = p_density;
RS::get_singleton()->material_set_param(_get_material(), "density", density);
}
float FogMaterial::get_density() const {
return density;
}
void FogMaterial::set_albedo(Color p_albedo) {
albedo = p_albedo;
RS::get_singleton()->material_set_param(_get_material(), "albedo", albedo);
}
Color FogMaterial::get_albedo() const {
return albedo;
}
void FogMaterial::set_emission(Color p_emission) {
emission = p_emission;
RS::get_singleton()->material_set_param(_get_material(), "emission", emission);
}
Color FogMaterial::get_emission() const {
return emission;
}
void FogMaterial::set_height_falloff(float p_falloff) {
height_falloff = MAX(p_falloff, 0.0f);
RS::get_singleton()->material_set_param(_get_material(), "height_falloff", height_falloff);
}
float FogMaterial::get_height_falloff() const {
return height_falloff;
}
void FogMaterial::set_edge_fade(float p_edge_fade) {
edge_fade = MAX(p_edge_fade, 0.0f);
RS::get_singleton()->material_set_param(_get_material(), "edge_fade", edge_fade);
}
float FogMaterial::get_edge_fade() const {
return edge_fade;
}
void FogMaterial::set_density_texture(const Ref<Texture3D> &p_texture) {
density_texture = p_texture;
Variant tex_rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
RS::get_singleton()->material_set_param(_get_material(), "density_texture", tex_rid);
}
Ref<Texture3D> FogMaterial::get_density_texture() const {
return density_texture;
}
Shader::Mode FogMaterial::get_shader_mode() const {
return Shader::MODE_FOG;
}
RID FogMaterial::get_shader_rid() const {
_update_shader();
return shader;
}
RID FogMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader);
shader_set = true;
}
return _get_material();
}
void FogMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_density", "density"), &FogMaterial::set_density);
ClassDB::bind_method(D_METHOD("get_density"), &FogMaterial::get_density);
ClassDB::bind_method(D_METHOD("set_albedo", "albedo"), &FogMaterial::set_albedo);
ClassDB::bind_method(D_METHOD("get_albedo"), &FogMaterial::get_albedo);
ClassDB::bind_method(D_METHOD("set_emission", "emission"), &FogMaterial::set_emission);
ClassDB::bind_method(D_METHOD("get_emission"), &FogMaterial::get_emission);
ClassDB::bind_method(D_METHOD("set_height_falloff", "height_falloff"), &FogMaterial::set_height_falloff);
ClassDB::bind_method(D_METHOD("get_height_falloff"), &FogMaterial::get_height_falloff);
ClassDB::bind_method(D_METHOD("set_edge_fade", "edge_fade"), &FogMaterial::set_edge_fade);
ClassDB::bind_method(D_METHOD("get_edge_fade"), &FogMaterial::get_edge_fade);
ClassDB::bind_method(D_METHOD("set_density_texture", "density_texture"), &FogMaterial::set_density_texture);
ClassDB::bind_method(D_METHOD("get_density_texture"), &FogMaterial::get_density_texture);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "-8.0,8.0,0.0001,or_greater,or_less"), "set_density", "get_density");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo", PROPERTY_HINT_COLOR_NO_ALPHA), "set_albedo", "get_albedo");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_falloff", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_height_falloff", "get_height_falloff");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_fade", PROPERTY_HINT_EXP_EASING), "set_edge_fade", "get_edge_fade");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "density_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_density_texture", "get_density_texture");
}
void FogMaterial::cleanup_shader() {
if (shader.is_valid()) {
ERR_FAIL_NULL(RenderingServer::get_singleton());
RS::get_singleton()->free(shader);
}
}
void FogMaterial::_update_shader() {
MutexLock shader_lock(shader_mutex);
if (shader.is_null()) {
shader = RS::get_singleton()->shader_create();
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader, R"(
// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s FogMaterial.
shader_type fog;
uniform float density : hint_range(0, 1, 0.0001) = 1.0;
uniform vec4 albedo : source_color = vec4(1.0);
uniform vec4 emission : source_color = vec4(0, 0, 0, 1);
uniform float height_falloff = 0.0;
uniform float edge_fade = 0.1;
uniform sampler3D density_texture: hint_default_white;
void fog() {
DENSITY = density * clamp(exp2(-height_falloff * (WORLD_POSITION.y - OBJECT_POSITION.y)), 0.0, 1.0);
DENSITY *= texture(density_texture, UVW).r;
DENSITY *= pow(clamp(-2.0 * SDF / min(min(SIZE.x, SIZE.y), SIZE.z), 0.0, 1.0), edge_fade);
ALBEDO = albedo.rgb;
EMISSION = emission.rgb;
}
)");
}
}
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));
set_height_falloff(0.0);
set_edge_fade(0.1);
}
FogMaterial::~FogMaterial() {
RS::get_singleton()->material_set_shader(_get_material(), RID());
}

View File

@@ -0,0 +1,84 @@
/**************************************************************************/
/* fog_material.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/material.h"
class FogMaterial : public Material {
GDCLASS(FogMaterial, Material);
private:
float density = 1.0;
Color albedo = Color(1, 1, 1, 1);
Color emission = Color(0, 0, 0, 0);
float height_falloff = 0.0;
float edge_fade = 0.1;
Ref<Texture3D> density_texture;
static Mutex shader_mutex;
static RID shader;
static void _update_shader();
mutable bool shader_set = false;
protected:
static void _bind_methods();
public:
void set_density(float p_density);
float get_density() const;
void set_albedo(Color p_color);
Color get_albedo() const;
void set_emission(Color p_color);
Color get_emission() const;
void set_height_falloff(float p_falloff);
float get_height_falloff() const;
void set_edge_fade(float p_edge_fade);
float get_edge_fade() const;
void set_density_texture(const Ref<Texture3D> &p_texture);
Ref<Texture3D> get_density_texture() const;
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
static void cleanup_shader();
FogMaterial();
virtual ~FogMaterial();
};

View File

@@ -0,0 +1,371 @@
/**************************************************************************/
/* height_map_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
Vector<Vector3> points;
if ((map_width != 0) && (map_depth != 0)) {
// This will be slow for large maps...
// also we'll have to figure out how well bullet centers this shape...
Vector2 size(map_width - 1, map_depth - 1);
Vector2 start = size * -0.5;
const real_t *r = map_data.ptr();
// reserve some memory for our points..
points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2) + ((map_width - 1) * (map_depth - 1) * 2));
// now set our points
int r_offset = 0;
int w_offset = 0;
for (int d = 0; d < map_depth; d++) {
Vector3 height(start.x, 0.0, start.y);
for (int w = 0; w < map_width; w++) {
height.y = r[r_offset++];
if (w != map_width - 1) {
points.write[w_offset++] = height;
points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
}
if (d != map_depth - 1) {
points.write[w_offset++] = height;
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
}
if ((w != map_width - 1) && (d != map_depth - 1)) {
points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
}
height.x += 1.0;
}
start.y += 1.0;
}
}
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();
}
void HeightMapShape3D::_update_shape() {
Dictionary d;
d["width"] = map_width;
d["depth"] = map_depth;
d["heights"] = map_data;
d["min_height"] = min_height;
d["max_height"] = max_height;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void HeightMapShape3D::set_map_width(int p_new) {
if (p_new < 1) {
// ignore
} else if (map_width != p_new) {
int was_size = map_width * map_depth;
map_width = p_new;
int new_size = map_width * map_depth;
map_data.resize(map_width * map_depth);
real_t *w = map_data.ptrw();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
_update_shape();
emit_changed();
}
}
int HeightMapShape3D::get_map_width() const {
return map_width;
}
void HeightMapShape3D::set_map_depth(int p_new) {
if (p_new < 1) {
// ignore
} else if (map_depth != p_new) {
int was_size = map_width * map_depth;
map_depth = p_new;
int new_size = map_width * map_depth;
map_data.resize(new_size);
real_t *w = map_data.ptrw();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
_update_shape();
emit_changed();
}
}
int HeightMapShape3D::get_map_depth() const {
return map_depth;
}
void HeightMapShape3D::set_map_data(Vector<real_t> p_new) {
int size = (map_width * map_depth);
if (p_new.size() != size) {
// fail
return;
}
// copy
real_t *w = map_data.ptrw();
const real_t *r = p_new.ptr();
for (int i = 0; i < size; i++) {
real_t val = r[i];
w[i] = val;
if (i == 0) {
min_height = val;
max_height = val;
} else {
if (min_height > val) {
min_height = val;
}
if (max_height < val) {
max_height = val;
}
}
}
_update_shape();
emit_changed();
}
Vector<real_t> HeightMapShape3D::get_map_data() const {
return map_data;
}
real_t HeightMapShape3D::get_min_height() const {
return min_height;
}
real_t HeightMapShape3D::get_max_height() const {
return max_height;
}
void HeightMapShape3D::update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max) {
ERR_FAIL_COND_MSG(p_image.is_null(), "Heightmap update image requires a valid Image reference.");
ERR_FAIL_COND_MSG(p_image->get_format() != Image::FORMAT_RF && p_image->get_format() != Image::FORMAT_RH && p_image->get_format() != Image::FORMAT_R8, "Heightmap update image requires Image in format FORMAT_RF (32 bit), FORMAT_RH (16 bit), or FORMAT_R8 (8 bit).");
ERR_FAIL_COND_MSG(p_image->get_width() < 2, "Heightmap update image requires a minimum Image width of 2.");
ERR_FAIL_COND_MSG(p_image->get_height() < 2, "Heightmap update image requires a minimum Image height of 2.");
ERR_FAIL_COND_MSG(p_height_min > p_height_max, "Heightmap update image requires height_max to be greater than height_min.");
map_width = p_image->get_width();
map_depth = p_image->get_height();
map_data.resize(map_width * map_depth);
real_t new_min_height = FLT_MAX;
real_t new_max_height = -FLT_MAX;
float remap_height_min = float(p_height_min);
float remap_height_max = float(p_height_max);
real_t *map_data_ptrw = map_data.ptrw();
switch (p_image->get_format()) {
case Image::FORMAT_RF: {
const float *image_data_ptr = (float *)p_image->get_data().ptr();
for (int i = 0; i < map_data.size(); i++) {
float pixel_value = image_data_ptr[i];
DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
if (height_value < new_min_height) {
new_min_height = height_value;
}
if (height_value > new_max_height) {
new_max_height = height_value;
}
map_data_ptrw[i] = height_value;
}
} break;
case Image::FORMAT_RH: {
const uint16_t *image_data_ptr = (uint16_t *)p_image->get_data().ptr();
for (int i = 0; i < map_data.size(); i++) {
float pixel_value = Math::half_to_float(image_data_ptr[i]);
DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
if (height_value < new_min_height) {
new_min_height = height_value;
}
if (height_value > new_max_height) {
new_max_height = height_value;
}
map_data_ptrw[i] = height_value;
}
} break;
case Image::FORMAT_R8: {
const uint8_t *image_data_ptr = (uint8_t *)p_image->get_data().ptr();
for (int i = 0; i < map_data.size(); i++) {
float pixel_value = float(image_data_ptr[i] / 255.0);
DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0);
real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max);
if (height_value < new_min_height) {
new_min_height = height_value;
}
if (height_value > new_max_height) {
new_max_height = height_value;
}
map_data_ptrw[i] = height_value;
}
} break;
default: {
return;
}
}
min_height = new_min_height;
max_height = new_max_height;
_update_shape();
emit_changed();
}
void HeightMapShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape3D::set_map_width);
ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape3D::get_map_width);
ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape3D::set_map_depth);
ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape3D::get_map_depth);
ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape3D::set_map_data);
ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape3D::get_map_data);
ClassDB::bind_method(D_METHOD("get_min_height"), &HeightMapShape3D::get_min_height);
ClassDB::bind_method(D_METHOD("get_max_height"), &HeightMapShape3D::get_max_height);
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, "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");
}
HeightMapShape3D::HeightMapShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) {
map_data.resize(map_width * map_depth);
real_t *w = map_data.ptrw();
w[0] = 0.0;
w[1] = 0.0;
w[2] = 0.0;
w[3] = 0.0;
_update_shape();
}

View File

@@ -0,0 +1,69 @@
/**************************************************************************/
/* height_map_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class Image;
class HeightMapShape3D : public Shape3D {
GDCLASS(HeightMapShape3D, Shape3D);
int map_width = 2;
int map_depth = 2;
Vector<real_t> map_data;
real_t min_height = 0.0;
real_t max_height = 0.0;
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_map_width(int p_new);
int get_map_width() const;
void set_map_depth(int p_new);
int get_map_depth() const;
void set_map_data(Vector<real_t> p_new);
Vector<real_t> get_map_data() const;
real_t get_min_height() const;
real_t get_max_height() const;
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();
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
/**************************************************************************/
/* importer_mesh.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/io/resource.h"
#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h"
#ifndef PHYSICS_3D_DISABLED
#include "scene/resources/3d/concave_polygon_shape_3d.h"
#include "scene/resources/3d/convex_polygon_shape_3d.h"
#endif // PHYSICS_3D_DISABLED
// The following classes are used by importers instead of ArrayMesh and MeshInstance3D
// so the data is not registered (hence, quality loss), importing happens faster and
// its easier to modify before saving
class ImporterMesh : public Resource {
GDCLASS(ImporterMesh, Resource)
struct Surface {
Mesh::PrimitiveType primitive;
Array arrays;
struct BlendShape {
Array arrays;
};
Vector<BlendShape> blend_shape_data;
struct LOD {
Vector<int> indices;
float distance = 0.0f;
};
Vector<LOD> lods;
Ref<Material> material;
String name;
uint64_t flags = 0;
struct LODComparator {
_FORCE_INLINE_ bool operator()(const LOD &l, const LOD &r) const {
return l.distance < r.distance;
}
};
};
Vector<Surface> surfaces;
Vector<String> blend_shapes;
Mesh::BlendShapeMode blend_shape_mode = Mesh::BLEND_SHAPE_MODE_NORMALIZED;
Ref<ArrayMesh> mesh;
Ref<ImporterMesh> shadow_mesh;
Size2i lightmap_size_hint;
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:
void add_blend_shape(const String &p_name);
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;
void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode);
Mesh::BlendShapeMode get_blend_shape_mode() const;
Mesh::PrimitiveType get_surface_primitive_type(int p_surface);
String get_surface_name(int p_surface) const;
void set_surface_name(int p_surface, const String &p_name);
Array get_surface_arrays(int p_surface) const;
Array get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const;
int get_surface_lod_count(int p_surface) const;
Vector<int> get_surface_lod_indices(int p_surface, int p_lod) const;
float get_surface_lod_size(int p_surface, int p_lod) const;
Ref<Material> get_surface_material(int p_surface) const;
uint64_t get_surface_format(int p_surface) const;
void set_surface_material(int p_surface, const Ref<Material> &p_material);
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;
Vector<Face3> get_faces() const;
#ifndef PHYSICS_3D_DISABLED
Vector<Ref<Shape3D>> convex_decompose(const Ref<MeshConvexDecompositionSettings> &p_settings) const;
Ref<ConvexPolygonShape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
Ref<ConcavePolygonShape3D> create_trimesh_shape() const;
#endif // PHYSICS_3D_DISABLED
Ref<NavigationMesh> create_navigation_mesh();
Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache);
void set_lightmap_size_hint(const Size2i &p_size);
Size2i get_lightmap_size_hint() const;
bool has_mesh() const;
Ref<ArrayMesh> get_mesh(const Ref<ArrayMesh> &p_base = Ref<ArrayMesh>());
void clear();
};

View File

@@ -0,0 +1,406 @@
/**************************************************************************/
/* mesh_library.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "mesh_library.h"
#ifndef PHYSICS_3D_DISABLED
#include "box_shape_3d.h"
#endif // PHYSICS_3D_DISABLED
bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
String prop_name = p_name;
if (prop_name.begins_with("item/")) {
int idx = prop_name.get_slicec('/', 1).to_int();
String what = prop_name.get_slicec('/', 2);
if (!item_map.has(idx)) {
create_item(idx);
}
if (what == "name") {
set_item_name(idx, p_value);
} else if (what == "mesh") {
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;
}
#ifndef PHYSICS_3D_DISABLED
} else if (what == "shape") {
Vector<ShapeData> shapes;
ShapeData sd;
sd.shape = p_value;
shapes.push_back(sd);
set_item_shapes(idx, shapes);
} else if (what == "shapes") {
_set_item_shapes(idx, p_value);
#endif // PHYSICS_3D_DISABLED
} else if (what == "preview") {
set_item_preview(idx, p_value);
} else if (what == "navigation_mesh") {
set_item_navigation_mesh(idx, p_value);
} else if (what == "navigation_mesh_transform") {
set_item_navigation_mesh_transform(idx, p_value);
#ifndef DISABLE_DEPRECATED
} else if (what == "navmesh") { // Renamed in 4.0 beta 9.
set_item_navigation_mesh(idx, p_value);
} else if (what == "navmesh_transform") { // Renamed in 4.0 beta 9.
set_item_navigation_mesh_transform(idx, p_value);
#endif // DISABLE_DEPRECATED
} else if (what == "navigation_layers") {
set_item_navigation_layers(idx, p_value);
} else {
return false;
}
return true;
}
return false;
}
bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
String prop_name = p_name;
int idx = prop_name.get_slicec('/', 1).to_int();
ERR_FAIL_COND_V(!item_map.has(idx), false);
String what = prop_name.get_slicec('/', 2);
if (what == "name") {
r_ret = get_item_name(idx);
} else if (what == "mesh") {
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);
#ifndef PHYSICS_3D_DISABLED
} else if (what == "shapes") {
r_ret = _get_item_shapes(idx);
#endif // PHYSICS_3D_DISABLED
} else if (what == "navigation_mesh") {
r_ret = get_item_navigation_mesh(idx);
} else if (what == "navigation_mesh_transform") {
r_ret = get_item_navigation_mesh_transform(idx);
#ifndef DISABLE_DEPRECATED
} else if (what == "navmesh") { // Renamed in 4.0 beta 9.
r_ret = get_item_navigation_mesh(idx);
} else if (what == "navmesh_transform") { // Renamed in 4.0 beta 9.
r_ret = get_item_navigation_mesh_transform(idx);
#endif // DISABLE_DEPRECATED
} else if (what == "navigation_layers") {
r_ret = get_item_navigation_layers(idx);
} else if (what == "preview") {
r_ret = get_item_preview(idx);
} else {
return false;
}
return true;
}
void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
for (const KeyValue<int, Item> &E : item_map) {
String prop_name = vformat("%s/%d/", PNAME("item"), E.key);
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"));
p_list->push_back(PropertyInfo(Variant::INT, prop_name + PNAME("navigation_layers"), PROPERTY_HINT_LAYERS_3D_NAVIGATION));
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT));
}
}
void MeshLibrary::create_item(int p_item) {
ERR_FAIL_COND(p_item < 0);
ERR_FAIL_COND(item_map.has(p_item));
item_map[p_item] = Item();
emit_changed();
notify_property_list_changed();
}
void MeshLibrary::set_item_name(int p_item, const String &p_name) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].name = p_name;
emit_changed();
}
void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].mesh = p_mesh;
emit_changed();
}
void MeshLibrary::set_item_mesh_transform(int p_item, const Transform3D &p_transform) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].mesh_transform = p_transform;
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();
}
#ifndef PHYSICS_3D_DISABLED
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;
emit_changed();
notify_property_list_changed();
}
#endif // PHYSICS_3D_DISABLED
void MeshLibrary::set_item_navigation_mesh(int p_item, const Ref<NavigationMesh> &p_navigation_mesh) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navigation_mesh = p_navigation_mesh;
emit_changed();
}
void MeshLibrary::set_item_navigation_mesh_transform(int p_item, const Transform3D &p_transform) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navigation_mesh_transform = p_transform;
emit_changed();
}
void MeshLibrary::set_item_navigation_layers(int p_item, uint32_t p_navigation_layers) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navigation_layers = p_navigation_layers;
emit_changed();
}
void MeshLibrary::set_item_preview(int p_item, const Ref<Texture2D> &p_preview) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].preview = p_preview;
emit_changed();
}
String MeshLibrary::get_item_name(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), "", "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].name;
}
Ref<Mesh> MeshLibrary::get_item_mesh(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<Mesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].mesh;
}
Transform3D MeshLibrary::get_item_mesh_transform(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
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;
}
#ifndef PHYSICS_3D_DISABLED
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;
}
#endif // PHYSICS_3D_DISABLED
Ref<NavigationMesh> MeshLibrary::get_item_navigation_mesh(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<NavigationMesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].navigation_mesh;
}
Transform3D MeshLibrary::get_item_navigation_mesh_transform(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].navigation_mesh_transform;
}
uint32_t MeshLibrary::get_item_navigation_layers(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), 0, "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].navigation_layers;
}
Ref<Texture2D> MeshLibrary::get_item_preview(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<Texture2D>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].preview;
}
bool MeshLibrary::has_item(int p_item) const {
return item_map.has(p_item);
}
void MeshLibrary::remove_item(int p_item) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map.erase(p_item);
notify_property_list_changed();
emit_changed();
}
void MeshLibrary::clear() {
item_map.clear();
notify_property_list_changed();
emit_changed();
}
Vector<int> MeshLibrary::get_item_list() const {
Vector<int> ret;
ret.resize(item_map.size());
int idx = 0;
for (const KeyValue<int, Item> &E : item_map) {
ret.write[idx++] = E.key;
}
return ret;
}
int MeshLibrary::find_item_by_name(const String &p_name) const {
for (const KeyValue<int, Item> &E : item_map) {
if (E.value.name == p_name) {
return E.key;
}
}
return -1;
}
int MeshLibrary::get_last_unused_item_id() const {
if (!item_map.size()) {
return 0;
} else {
return item_map.back()->key() + 1;
}
}
#ifndef PHYSICS_3D_DISABLED
void MeshLibrary::_set_item_shapes(int p_item, const Array &p_shapes) {
Array arr_shapes = p_shapes;
int size = p_shapes.size();
if (size & 1) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
int prev_size = item_map[p_item].shapes.size() * 2;
if (prev_size < size) {
// Check if last element is a shape.
Ref<Shape3D> shape = arr_shapes[size - 1];
if (shape.is_null()) {
Ref<BoxShape3D> box_shape;
box_shape.instantiate();
arr_shapes[size - 1] = box_shape;
}
// Make sure the added element is a Transform3D.
arr_shapes.push_back(Transform3D());
size++;
} else {
size--;
arr_shapes.resize(size);
}
}
Vector<ShapeData> shapes;
for (int i = 0; i < size; i += 2) {
ShapeData sd;
sd.shape = arr_shapes[i + 0];
sd.local_transform = arr_shapes[i + 1];
if (sd.shape.is_valid()) {
shapes.push_back(sd);
}
}
set_item_shapes(p_item, shapes);
}
Array MeshLibrary::_get_item_shapes(int p_item) const {
Vector<ShapeData> shapes = get_item_shapes(p_item);
Array ret;
for (int i = 0; i < shapes.size(); i++) {
ret.push_back(shapes[i].shape);
ret.push_back(shapes[i].local_transform);
}
return ret;
}
#endif // PHYSICS_3D_DISABLED
void MeshLibrary::reset_state() {
clear();
}
void MeshLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item);
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);
#ifndef PHYSICS_3D_DISABLED
ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes);
#endif // PHYSICS_3D_DISABLED
ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview);
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);
#ifndef PHYSICS_3D_DISABLED
ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes);
#endif // PHYSICS_3D_DISABLED
ClassDB::bind_method(D_METHOD("get_item_preview", "id"), &MeshLibrary::get_item_preview);
ClassDB::bind_method(D_METHOD("remove_item", "id"), &MeshLibrary::remove_item);
ClassDB::bind_method(D_METHOD("find_item_by_name", "name"), &MeshLibrary::find_item_by_name);
ClassDB::bind_method(D_METHOD("clear"), &MeshLibrary::clear);
ClassDB::bind_method(D_METHOD("get_item_list"), &MeshLibrary::get_item_list);
ClassDB::bind_method(D_METHOD("get_last_unused_item_id"), &MeshLibrary::get_last_unused_item_id);
}
MeshLibrary::MeshLibrary() {
}
MeshLibrary::~MeshLibrary() {
}

View File

@@ -0,0 +1,120 @@
/**************************************************************************/
/* mesh_library.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/io/resource.h"
#include "core/templates/rb_map.h"
#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h"
#include "servers/rendering_server.h"
#ifndef PHYSICS_3D_DISABLED
#include "shape_3d.h"
#endif // PHYSICS_3D_DISABLED
class MeshLibrary : public Resource {
GDCLASS(MeshLibrary, Resource);
RES_BASE_EXTENSION("meshlib");
public:
#ifndef PHYSICS_3D_DISABLED
struct ShapeData {
Ref<Shape3D> shape;
Transform3D local_transform;
};
#endif // PHYSICS_3D_DISABLED
struct Item {
String name;
Ref<Mesh> mesh;
Transform3D mesh_transform;
RS::ShadowCastingSetting mesh_cast_shadow = RS::ShadowCastingSetting::SHADOW_CASTING_SETTING_ON;
#ifndef PHYSICS_3D_DISABLED
Vector<ShapeData> shapes;
#endif // PHYSICS_3D_DISABLED
Ref<Texture2D> preview;
Ref<NavigationMesh> navigation_mesh;
Transform3D navigation_mesh_transform;
uint32_t navigation_layers = 1;
};
RBMap<int, Item> item_map;
#ifndef PHYSICS_3D_DISABLED
void _set_item_shapes(int p_item, const Array &p_shapes);
Array _get_item_shapes(int p_item) const;
#endif // PHYSICS_3D_DISABLED
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
virtual void reset_state() override;
static void _bind_methods();
public:
void create_item(int p_item);
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);
#ifndef PHYSICS_3D_DISABLED
void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes);
#endif // PHYSICS_3D_DISABLED
void set_item_preview(int p_item, const Ref<Texture2D> &p_preview);
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;
#ifndef PHYSICS_3D_DISABLED
Vector<ShapeData> get_item_shapes(int p_item) const;
#endif // PHYSICS_3D_DISABLED
Ref<Texture2D> get_item_preview(int p_item) const;
void remove_item(int p_item);
bool has_item(int p_item) const;
void clear();
int find_item_by_name(const String &p_name) const;
Vector<int> get_item_list() const;
int get_last_unused_item_id() const;
MeshLibrary();
~MeshLibrary();
};

View File

@@ -0,0 +1,425 @@
/**************************************************************************/
/* navigation_mesh_source_geometry_data_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "navigation_mesh_source_geometry_data_3d.h"
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 {
RWLockRead read_lock(geometry_rwlock);
return vertices;
}
void NavigationMeshSourceGeometryData3D::set_indices(const Vector<int> &p_indices) {
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 {
RWLockRead read_lock(geometry_rwlock);
return indices;
}
void NavigationMeshSourceGeometryData3D::append_arrays(const Vector<float> &p_vertices, const Vector<int> &p_indices) {
RWLockWrite write_lock(geometry_rwlock);
const int64_t number_of_vertices_before_merge = vertices.size();
const int64_t number_of_indices_before_merge = indices.size();
vertices.append_array(p_vertices);
indices.append_array(p_indices);
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) {
vertices.push_back(p_vec3.x);
vertices.push_back(p_vec3.y);
vertices.push_back(p_vec3.z);
}
void NavigationMeshSourceGeometryData3D::_add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {
int current_vertex_count;
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
current_vertex_count = vertices.size() / 3;
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
continue;
}
int index_count = 0;
if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
index_count = p_mesh->surface_get_array_index_len(i);
} else {
index_count = p_mesh->surface_get_array_len(i);
}
ERR_CONTINUE((index_count == 0 || (index_count % 3) != 0));
int face_count = index_count / 3;
Array a = p_mesh->surface_get_arrays(i);
ERR_CONTINUE(a.is_empty() || (a.size() != Mesh::ARRAY_MAX));
Vector<Vector3> mesh_vertices = a[Mesh::ARRAY_VERTEX];
ERR_CONTINUE(mesh_vertices.is_empty());
const Vector3 *vr = mesh_vertices.ptr();
if (p_mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
Vector<int> mesh_indices = a[Mesh::ARRAY_INDEX];
ERR_CONTINUE(mesh_indices.is_empty() || (mesh_indices.size() != index_count));
const int *ir = mesh_indices.ptr();
for (int j = 0; j < mesh_vertices.size(); j++) {
_add_vertex(p_xform.xform(vr[j]));
}
for (int j = 0; j < face_count; j++) {
// CCW
indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
}
} else {
ERR_CONTINUE(mesh_vertices.size() != index_count);
face_count = mesh_vertices.size() / 3;
for (int j = 0; j < face_count; j++) {
_add_vertex(p_xform.xform(vr[j * 3 + 0]));
_add_vertex(p_xform.xform(vr[j * 3 + 2]));
_add_vertex(p_xform.xform(vr[j * 3 + 1]));
indices.push_back(current_vertex_count + (j * 3 + 0));
indices.push_back(current_vertex_count + (j * 3 + 1));
indices.push_back(current_vertex_count + (j * 3 + 2));
}
}
}
}
void NavigationMeshSourceGeometryData3D::_add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {
ERR_FAIL_COND(p_mesh_array.size() != Mesh::ARRAY_MAX);
Vector<Vector3> mesh_vertices = p_mesh_array[Mesh::ARRAY_VERTEX];
ERR_FAIL_COND(mesh_vertices.is_empty());
const Vector3 *vr = mesh_vertices.ptr();
Vector<int> mesh_indices = p_mesh_array[Mesh::ARRAY_INDEX];
ERR_FAIL_COND(mesh_indices.is_empty());
const int *ir = mesh_indices.ptr();
const int face_count = mesh_indices.size() / 3;
const int current_vertex_count = vertices.size() / 3;
for (int j = 0; j < mesh_vertices.size(); j++) {
_add_vertex(p_xform.xform(vr[j]));
}
for (int j = 0; j < face_count; j++) {
// CCW
indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
}
}
void NavigationMeshSourceGeometryData3D::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform) {
ERR_FAIL_COND(p_faces.is_empty());
ERR_FAIL_COND(p_faces.size() % 3 != 0);
int face_count = p_faces.size() / 3;
int current_vertex_count = vertices.size() / 3;
for (int j = 0; j < face_count; j++) {
_add_vertex(p_xform.xform(p_faces[j * 3 + 0]));
_add_vertex(p_xform.xform(p_faces[j * 3 + 1]));
_add_vertex(p_xform.xform(p_faces[j * 3 + 2]));
indices.push_back(current_vertex_count + (j * 3 + 0));
indices.push_back(current_vertex_count + (j * 3 + 2));
indices.push_back(current_vertex_count + (j * 3 + 1));
}
}
void NavigationMeshSourceGeometryData3D::add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform) {
ERR_FAIL_COND(p_mesh.is_null());
#ifdef DEBUG_ENABLED
if (!Engine::get_singleton()->is_editor_hint()) {
WARN_PRINT_ONCE("Source geometry parsing for navigation mesh baking had to parse RenderingServer meshes at runtime.\n\
This poses a significant performance issues as visual meshes store geometry data on the GPU and transferring this data back to the CPU blocks the rendering.\n\
For runtime (re)baking navigation meshes use and parse collision shapes as source geometry or create geometry data procedurally in scripts.");
}
#endif
_add_mesh(p_mesh, root_node_transform * p_xform);
}
void NavigationMeshSourceGeometryData3D::add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform) {
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_COND(p_other_geometry.is_null());
Vector<float> other_vertices;
Vector<int> other_indices;
Vector<ProjectedObstruction> other_projected_obstructions;
p_other_geometry->get_data(other_vertices, other_indices, other_projected_obstructions);
RWLockWrite write_lock(geometry_rwlock);
const int64_t number_of_vertices_before_merge = vertices.size();
const int64_t number_of_indices_before_merge = indices.size();
vertices.append_array(other_vertices);
indices.append_array(other_indices);
for (int64_t i = number_of_indices_before_merge; i < indices.size(); i++) {
indices.set(i, indices[i] + number_of_vertices_before_merge / 3);
}
_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) {
ERR_FAIL_COND(p_vertices.size() < 3);
ERR_FAIL_COND(p_height < 0.0);
ProjectedObstruction projected_obstruction;
projected_obstruction.vertices.resize(p_vertices.size() * 3);
projected_obstruction.elevation = p_elevation;
projected_obstruction.height = p_height;
projected_obstruction.carve = p_carve;
float *obstruction_vertices_ptrw = projected_obstruction.vertices.ptrw();
int vertex_index = 0;
for (const Vector3 &vertex : p_vertices) {
obstruction_vertices_ptrw[vertex_index++] = vertex.x;
obstruction_vertices_ptrw[vertex_index++] = vertex.y;
obstruction_vertices_ptrw[vertex_index++] = vertex.z;
}
RWLockWrite write_lock(geometry_rwlock);
_projected_obstructions.push_back(projected_obstruction);
bounds_dirty = true;
}
void NavigationMeshSourceGeometryData3D::set_projected_obstructions(const Array &p_array) {
clear_projected_obstructions();
for (int i = 0; i < p_array.size(); i++) {
Dictionary data = p_array[i];
ERR_FAIL_COND(!data.has("version"));
uint32_t po_version = data["version"];
if (po_version == 1) {
ERR_FAIL_COND(!data.has("vertices"));
ERR_FAIL_COND(!data.has("elevation"));
ERR_FAIL_COND(!data.has("height"));
ERR_FAIL_COND(!data.has("carve"));
}
ProjectedObstruction projected_obstruction;
projected_obstruction.vertices = Vector<float>(data["vertices"]);
projected_obstruction.elevation = data["elevation"];
projected_obstruction.height = data["height"];
projected_obstruction.carve = data["carve"];
RWLockWrite write_lock(geometry_rwlock);
_projected_obstructions.push_back(projected_obstruction);
bounds_dirty = true;
}
}
Vector<NavigationMeshSourceGeometryData3D::ProjectedObstruction> NavigationMeshSourceGeometryData3D::_get_projected_obstructions() const {
RWLockRead read_lock(geometry_rwlock);
return _projected_obstructions;
}
Array NavigationMeshSourceGeometryData3D::get_projected_obstructions() const {
RWLockRead read_lock(geometry_rwlock);
Array ret;
ret.resize(_projected_obstructions.size());
for (int i = 0; i < _projected_obstructions.size(); i++) {
const ProjectedObstruction &projected_obstruction = _projected_obstructions[i];
Dictionary data;
data["version"] = (int)ProjectedObstruction::VERSION;
data["vertices"] = projected_obstruction.vertices;
data["elevation"] = projected_obstruction.elevation;
data["height"] = projected_obstruction.height;
data["carve"] = projected_obstruction.carve;
ret[i] = data;
}
return ret;
}
bool NavigationMeshSourceGeometryData3D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "projected_obstructions") {
set_projected_obstructions(p_value);
return true;
}
return false;
}
bool NavigationMeshSourceGeometryData3D::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "projected_obstructions") {
r_ret = get_projected_obstructions();
return true;
}
return false;
}
void NavigationMeshSourceGeometryData3D::set_data(const Vector<float> &p_vertices, const Vector<int> &p_indices, Vector<ProjectedObstruction> &p_projected_obstructions) {
RWLockWrite write_lock(geometry_rwlock);
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) {
RWLockRead read_lock(geometry_rwlock);
r_vertices = vertices;
r_indices = indices;
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);
ClassDB::bind_method(D_METHOD("set_indices", "indices"), &NavigationMeshSourceGeometryData3D::set_indices);
ClassDB::bind_method(D_METHOD("get_indices"), &NavigationMeshSourceGeometryData3D::get_indices);
ClassDB::bind_method(D_METHOD("append_arrays", "vertices", "indices"), &NavigationMeshSourceGeometryData3D::append_arrays);
ClassDB::bind_method(D_METHOD("clear"), &NavigationMeshSourceGeometryData3D::clear);
ClassDB::bind_method(D_METHOD("has_data"), &NavigationMeshSourceGeometryData3D::has_data);
ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh);
ClassDB::bind_method(D_METHOD("add_mesh_array", "mesh_array", "xform"), &NavigationMeshSourceGeometryData3D::add_mesh_array);
ClassDB::bind_method(D_METHOD("add_faces", "faces", "xform"), &NavigationMeshSourceGeometryData3D::add_faces);
ClassDB::bind_method(D_METHOD("merge", "other_geometry"), &NavigationMeshSourceGeometryData3D::merge);
ClassDB::bind_method(D_METHOD("add_projected_obstruction", "vertices", "elevation", "height", "carve"), &NavigationMeshSourceGeometryData3D::add_projected_obstruction);
ClassDB::bind_method(D_METHOD("clear_projected_obstructions"), &NavigationMeshSourceGeometryData3D::clear_projected_obstructions);
ClassDB::bind_method(D_METHOD("set_projected_obstructions", "projected_obstructions"), &NavigationMeshSourceGeometryData3D::set_projected_obstructions);
ClassDB::bind_method(D_METHOD("get_projected_obstructions"), &NavigationMeshSourceGeometryData3D::get_projected_obstructions);
ClassDB::bind_method(D_METHOD("get_bounds"), &NavigationMeshSourceGeometryData3D::get_bounds);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_indices", "get_indices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "projected_obstructions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_projected_obstructions", "get_projected_obstructions");
}

View File

@@ -0,0 +1,109 @@
/**************************************************************************/
/* navigation_mesh_source_geometry_data_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/os/rw_lock.h"
#include "scene/resources/mesh.h"
class NavigationMeshSourceGeometryData3D : public Resource {
GDCLASS(NavigationMeshSourceGeometryData3D, Resource);
RWLock geometry_rwlock;
Vector<float> vertices;
Vector<int> indices;
AABB bounds;
bool bounds_dirty = true;
public:
struct ProjectedObstruction;
private:
Vector<ProjectedObstruction> _projected_obstructions;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
static void _bind_methods();
private:
void _add_vertex(const Vector3 &p_vec3);
void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform);
void _add_mesh_array(const Array &p_array, const Transform3D &p_xform);
void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform);
public:
struct ProjectedObstruction {
static inline uint32_t VERSION = 1; // Increase when format changes so we can detect outdated formats and provide compatibility.
Vector<float> vertices;
float elevation = 0.0;
float height = 0.0;
bool carve = false;
};
// kept root node transform here on the geometry data
// if we add this transform to all exposed functions we need to break comp on all functions later
// when navmesh changes from global transform to relative to navregion
// but if it stays here we can just remove it and change the internal functions only
Transform3D root_node_transform;
void set_vertices(const Vector<float> &p_vertices);
const Vector<float> &get_vertices() const;
void set_indices(const Vector<int> &p_indices);
const Vector<int> &get_indices() const;
void append_arrays(const Vector<float> &p_vertices, const Vector<int> &p_indices);
bool has_data();
void clear();
void clear_projected_obstructions();
void add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform);
void add_mesh_array(const Array &p_mesh_array, const Transform3D &p_xform);
void add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform);
void merge(const Ref<NavigationMeshSourceGeometryData3D> &p_other_geometry);
void add_projected_obstruction(const Vector<Vector3> &p_vertices, float p_elevation, float p_height, bool p_carve);
Vector<ProjectedObstruction> _get_projected_obstructions() const;
void set_projected_obstructions(const Array &p_array);
Array get_projected_obstructions() const;
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() { clear(); }
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,678 @@
/**************************************************************************/
/* primitive_meshes.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/font.h"
#include "scene/resources/mesh.h"
#include "servers/text_server.h"
///@TODO probably should change a few integers to unsigned integers...
/**
Base class for all the classes in this file, handles a number of code functions that are shared among all meshes.
This class is set apart that it assumes a single surface is always generated for our mesh.
*/
class PrimitiveMesh : public Mesh {
GDCLASS(PrimitiveMesh, Mesh);
private:
RID mesh;
mutable AABB aabb;
AABB custom_aabb;
mutable int array_len = 0;
mutable int index_array_len = 0;
Ref<Material> material;
bool flip_faces = false;
bool add_uv2 = false;
float uv2_padding = 2.0;
// make sure we do an update after we've finished constructing our object
mutable bool pending_request = true;
void _update() const;
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 {}
GDVIRTUAL0RC(Array, _create_mesh_array)
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() {}
void _on_settings_changed();
public:
virtual int get_surface_count() const override;
virtual int surface_get_array_len(int p_idx) const override;
virtual int surface_get_array_index_len(int p_idx) const override;
virtual Array surface_get_arrays(int p_surface) const override;
virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
virtual Dictionary surface_get_lods(int p_surface) const override;
virtual BitField<ArrayFormat> surface_get_format(int p_idx) const override;
virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const override;
virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) override;
virtual Ref<Material> surface_get_material(int p_idx) const override;
virtual int get_blend_shape_count() const override;
virtual StringName get_blend_shape_name(int p_index) const override;
virtual void set_blend_shape_name(int p_index, const StringName &p_name) override;
virtual AABB get_aabb() const override;
virtual RID get_rid() const override;
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
Array get_mesh_arrays() const;
void set_custom_aabb(const AABB &p_custom);
AABB get_custom_aabb() const;
void set_flip_faces(bool p_enable);
bool get_flip_faces() const;
void set_add_uv2(bool p_enable);
bool get_add_uv2() const { return add_uv2; }
void set_uv2_padding(float p_padding);
float get_uv2_padding() const { return uv2_padding; }
void request_update();
PrimitiveMesh();
~PrimitiveMesh();
};
/**
Mesh for a simple capsule
*/
class CapsuleMesh : public PrimitiveMesh {
GDCLASS(CapsuleMesh, PrimitiveMesh);
private:
float radius = 0.5;
float height = 2.0;
int radial_segments = 64;
int rings = 8;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
virtual void _update_lightmap_size() override;
public:
static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 8, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_radius(const float p_radius);
float get_radius() const;
void set_height(const float p_height);
float get_height() const;
void set_radial_segments(const int p_segments);
int get_radial_segments() const;
void set_rings(const int p_rings);
int get_rings() const;
};
/**
A box
*/
class BoxMesh : public PrimitiveMesh {
GDCLASS(BoxMesh, PrimitiveMesh);
private:
Vector3 size = Vector3(1, 1, 1);
int subdivide_w = 0;
int subdivide_h = 0;
int subdivide_d = 0;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
virtual void _update_lightmap_size() override;
public:
static void create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w = 0, int subdivide_h = 0, int subdivide_d = 0, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_size(const Vector3 &p_size);
Vector3 get_size() const;
void set_subdivide_width(const int p_divisions);
int get_subdivide_width() const;
void set_subdivide_height(const int p_divisions);
int get_subdivide_height() const;
void set_subdivide_depth(const int p_divisions);
int get_subdivide_depth() const;
};
/**
A cylinder
*/
class CylinderMesh : public PrimitiveMesh {
GDCLASS(CylinderMesh, PrimitiveMesh);
private:
float top_radius = 0.5;
float bottom_radius = 0.5;
float height = 2.0;
int radial_segments = 64;
int rings = 4;
bool cap_top = true;
bool cap_bottom = true;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
virtual void _update_lightmap_size() override;
public:
static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4, bool cap_top = true, bool cap_bottom = true, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_top_radius(const float p_radius);
float get_top_radius() const;
void set_bottom_radius(const float p_radius);
float get_bottom_radius() const;
void set_height(const float p_height);
float get_height() const;
void set_radial_segments(const int p_segments);
int get_radial_segments() const;
void set_rings(const int p_rings);
int get_rings() const;
void set_cap_top(bool p_cap_top);
bool is_cap_top() const;
void set_cap_bottom(bool p_cap_bottom);
bool is_cap_bottom() const;
};
/*
A flat rectangle, can be used as quad or heightmap.
*/
class PlaneMesh : public PrimitiveMesh {
GDCLASS(PlaneMesh, PrimitiveMesh);
public:
enum Orientation {
FACE_X,
FACE_Y,
FACE_Z,
};
private:
Size2 size = Size2(2.0, 2.0);
int subdivide_w = 0;
int subdivide_d = 0;
Vector3 center_offset;
Orientation orientation = FACE_Y;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
virtual void _update_lightmap_size() override;
public:
void set_size(const Size2 &p_size);
Size2 get_size() const;
void set_subdivide_width(const int p_divisions);
int get_subdivide_width() const;
void set_subdivide_depth(const int p_divisions);
int get_subdivide_depth() const;
void set_center_offset(const Vector3 p_offset);
Vector3 get_center_offset() const;
void set_orientation(const Orientation p_orientation);
Orientation get_orientation() const;
};
VARIANT_ENUM_CAST(PlaneMesh::Orientation)
/*
A flat rectangle, inherits from PlaneMesh but defaults to facing the Z-plane.
*/
class QuadMesh : public PlaneMesh {
GDCLASS(QuadMesh, PlaneMesh);
public:
QuadMesh() {
set_orientation(FACE_Z);
set_size(Size2(1, 1));
}
};
/**
A prism shapen, handy for ramps, triangles, etc.
*/
class PrismMesh : public PrimitiveMesh {
GDCLASS(PrismMesh, PrimitiveMesh);
private:
float left_to_right = 0.5;
Vector3 size = Vector3(1.0, 1.0, 1.0);
int subdivide_w = 0;
int subdivide_h = 0;
int subdivide_d = 0;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
virtual void _update_lightmap_size() override;
public:
void set_left_to_right(const float p_left_to_right);
float get_left_to_right() const;
void set_size(const Vector3 &p_size);
Vector3 get_size() const;
void set_subdivide_width(const int p_divisions);
int get_subdivide_width() const;
void set_subdivide_height(const int p_divisions);
int get_subdivide_height() const;
void set_subdivide_depth(const int p_divisions);
int get_subdivide_depth() const;
};
/**
A sphere..
*/
class SphereMesh : public PrimitiveMesh {
GDCLASS(SphereMesh, PrimitiveMesh);
private:
float radius = 0.5;
float height = 1.0;
int radial_segments = 64;
int rings = 32;
bool is_hemisphere = false;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
virtual void _update_lightmap_size() override;
public:
static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 32, bool is_hemisphere = false, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_radius(const float p_radius);
float get_radius() const;
void set_height(const float p_height);
float get_height() const;
void set_radial_segments(const int p_radial_segments);
int get_radial_segments() const;
void set_rings(const int p_rings);
int get_rings() const;
void set_is_hemisphere(const bool p_is_hemisphere);
bool get_is_hemisphere() const;
};
/**
Big donut
*/
class TorusMesh : public PrimitiveMesh {
GDCLASS(TorusMesh, PrimitiveMesh);
private:
float inner_radius = 0.5;
float outer_radius = 1.0;
int rings = 64;
int ring_segments = 32;
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
virtual void _update_lightmap_size() override;
public:
void set_inner_radius(const float p_inner_radius);
float get_inner_radius() const;
void set_outer_radius(const float p_outer_radius);
float get_outer_radius() const;
void set_rings(const int p_rings);
int get_rings() const;
void set_ring_segments(const int p_ring_segments);
int get_ring_segments() const;
};
/**
A single point for use in particle systems
*/
class PointMesh : public PrimitiveMesh {
GDCLASS(PointMesh, PrimitiveMesh)
protected:
virtual void _create_mesh_array(Array &p_arr) const override;
public:
PointMesh();
};
class TubeTrailMesh : public PrimitiveMesh {
GDCLASS(TubeTrailMesh, PrimitiveMesh);
private:
float radius = 0.5;
int radial_steps = 8;
int sections = 5;
float section_length = 0.2;
int section_rings = 3;
bool cap_top = true;
bool cap_bottom = true;
Ref<Curve> curve;
void _curve_changed();
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
public:
void set_radius(const float p_radius);
float get_radius() const;
void set_radial_steps(const int p_radial_steps);
int get_radial_steps() const;
void set_sections(const int p_sections);
int get_sections() const;
void set_section_length(float p_sectionlength);
float get_section_length() const;
void set_section_rings(const int p_section_rings);
int get_section_rings() const;
void set_cap_top(bool p_cap_top);
bool is_cap_top() const;
void set_cap_bottom(bool p_cap_bottom);
bool is_cap_bottom() const;
void set_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_curve() const;
virtual int get_builtin_bind_pose_count() const override;
virtual Transform3D get_builtin_bind_pose(int p_index) const override;
TubeTrailMesh();
};
class RibbonTrailMesh : public PrimitiveMesh {
GDCLASS(RibbonTrailMesh, PrimitiveMesh);
public:
enum Shape {
SHAPE_FLAT,
SHAPE_CROSS
};
private:
float size = 1.0;
int sections = 5;
float section_length = 0.2;
int section_segments = 3;
Shape shape = SHAPE_CROSS;
Ref<Curve> curve;
void _curve_changed();
protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
public:
void set_shape(Shape p_shape);
Shape get_shape() const;
void set_size(const float p_size);
float get_size() const;
void set_sections(const int p_sections);
int get_sections() const;
void set_section_length(float p_sectionlength);
float get_section_length() const;
void set_section_segments(const int p_section_segments);
int get_section_segments() const;
void set_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_curve() const;
virtual int get_builtin_bind_pose_count() const override;
virtual Transform3D get_builtin_bind_pose(int p_index) const override;
RibbonTrailMesh();
};
/**
Text...
*/
class TextMesh : public PrimitiveMesh {
GDCLASS(TextMesh, PrimitiveMesh);
private:
struct ContourPoint {
Vector2 point;
bool sharp = false;
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(real_t p_len, bool p_ccw) {
length = p_len;
ccw = p_ccw;
}
};
struct GlyphMeshKey {
uint64_t font_id;
uint32_t gl_id;
bool operator==(const GlyphMeshKey &p_b) const {
return (font_id == p_b.font_id) && (gl_id == p_b.gl_id);
}
GlyphMeshKey(uint64_t p_font_id, uint32_t p_gl_id) {
font_id = p_font_id;
gl_id = p_gl_id;
}
};
struct GlyphMeshKeyHasher {
_FORCE_INLINE_ static uint32_t hash(const GlyphMeshKey &p_a) {
return hash_murmur3_buffer(&p_a, sizeof(GlyphMeshKey));
}
};
struct GlyphMeshData {
Vector<Vector2> triangles;
Vector<Vector<ContourPoint>> contours;
Vector<ContourInfo> contours_info;
Vector2 min_p = Vector2(Math::INF, Math::INF);
Vector2 max_p = Vector2(-Math::INF, -Math::INF);
};
mutable HashMap<GlyphMeshKey, GlyphMeshData, GlyphMeshKeyHasher> cache;
RID text_rid;
mutable Vector<RID> lines_rid;
String text;
String xl_text;
int font_size = 16;
Ref<Font> font_override;
TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF;
BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE;
float width = 500.0;
float line_spacing = 0.f;
Point2 lbl_offset;
HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_CENTER;
bool uppercase = false;
String language;
TextServer::Direction text_direction = TextServer::DIRECTION_AUTO;
TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
Array st_args;
real_t depth = 0.05;
real_t pixel_size = 0.01;
real_t curve_step = 0.5;
mutable bool dirty_lines = true;
mutable bool dirty_text = true;
mutable bool dirty_font = true;
mutable bool dirty_cache = true;
void _generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_glyph) const;
void _font_changed();
protected:
static void _bind_methods();
void _notification(int p_what);
virtual void _create_mesh_array(Array &p_arr) const override;
public:
GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
TextMesh();
~TextMesh();
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
void set_vertical_alignment(VerticalAlignment p_alignment);
VerticalAlignment get_vertical_alignment() const;
void set_text(const String &p_string);
String get_text() const;
void set_font(const Ref<Font> &p_font);
Ref<Font> get_font() const;
Ref<Font> _get_font_or_default() const;
void set_font_size(int p_size);
int get_font_size() const;
void set_line_spacing(float p_size);
float get_line_spacing() const;
void set_autowrap_mode(TextServer::AutowrapMode p_mode);
TextServer::AutowrapMode get_autowrap_mode() const;
void set_justification_flags(BitField<TextServer::JustificationFlag> p_flags);
BitField<TextServer::JustificationFlag> get_justification_flags() const;
void set_text_direction(TextServer::Direction p_text_direction);
TextServer::Direction get_text_direction() const;
void set_language(const String &p_language);
String get_language() const;
void set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser);
TextServer::StructuredTextParser get_structured_text_bidi_override() const;
void set_structured_text_bidi_override_options(Array p_args);
Array get_structured_text_bidi_override_options() const;
void set_uppercase(bool p_uppercase);
bool is_uppercase() const;
void set_width(real_t p_width);
real_t get_width() const;
void set_depth(real_t p_depth);
real_t get_depth() const;
void set_curve_step(real_t p_step);
real_t get_curve_step() const;
void set_pixel_size(real_t p_amount);
real_t get_pixel_size() const;
void set_offset(const Point2 &p_offset);
Point2 get_offset() const;
};
VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)

View File

@@ -0,0 +1,97 @@
/**************************************************************************/
/* separation_ray_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
Vector<Vector3> points = {
Vector3(),
Vector3(0, 0, get_length())
};
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;
}
void SeparationRayShape3D::_update_shape() {
Dictionary d;
d["length"] = length;
d["slide_on_slope"] = slide_on_slope;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void SeparationRayShape3D::set_length(float p_length) {
length = p_length;
_update_shape();
emit_changed();
}
float SeparationRayShape3D::get_length() const {
return length;
}
void SeparationRayShape3D::set_slide_on_slope(bool p_active) {
slide_on_slope = p_active;
_update_shape();
emit_changed();
}
bool SeparationRayShape3D::get_slide_on_slope() const {
return slide_on_slope;
}
void SeparationRayShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_length", "length"), &SeparationRayShape3D::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &SeparationRayShape3D::get_length);
ClassDB::bind_method(D_METHOD("set_slide_on_slope", "active"), &SeparationRayShape3D::set_slide_on_slope);
ClassDB::bind_method(D_METHOD("get_slide_on_slope"), &SeparationRayShape3D::get_slide_on_slope);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_slope"), "set_slide_on_slope", "get_slide_on_slope");
}
SeparationRayShape3D::SeparationRayShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SEPARATION_RAY)) {
/* Code copied from setters to prevent the use of uninitialized variables */
_update_shape();
emit_changed();
}

View File

@@ -0,0 +1,58 @@
/**************************************************************************/
/* separation_ray_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class SeparationRayShape3D : public Shape3D {
GDCLASS(SeparationRayShape3D, Shape3D);
float length = 1.0;
bool slide_on_slope = false;
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_length(float p_length);
float get_length() const;
void set_slide_on_slope(bool p_active);
bool get_slide_on_slope() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SeparationRayShape3D();
};

View File

@@ -0,0 +1,169 @@
/**************************************************************************/
/* shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "shape_3d.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
void Shape3D::add_vertices_to_array(Vector<Vector3> &array, const Transform3D &p_xform) {
Vector<Vector3> toadd = get_debug_mesh_lines();
if (toadd.size()) {
int base = array.size();
array.resize(base + toadd.size());
Vector3 *w = array.ptrw();
for (int i = 0; i < toadd.size(); i++) {
w[i + base] = p_xform.xform(toadd[i]);
}
}
}
void Shape3D::set_custom_solver_bias(real_t p_bias) {
custom_bias = p_bias;
PhysicsServer3D::get_singleton()->shape_set_custom_solver_bias(shape, custom_bias);
}
real_t Shape3D::get_custom_solver_bias() const {
return custom_bias;
}
real_t Shape3D::get_margin() const {
return margin;
}
void Shape3D::set_margin(real_t p_margin) {
margin = 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;
}
Vector<Vector3> lines = get_debug_mesh_lines();
debug_mesh_cache.instantiate();
if (!lines.is_empty()) {
Vector<Color> colors;
colors.resize(lines.size());
colors.fill(debug_color);
Array lines_array;
lines_array.resize(Mesh::ARRAY_MAX);
lines_array[Mesh::ARRAY_VERTEX] = lines;
lines_array[Mesh::ARRAY_COLOR] = colors;
debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, lines_array);
SceneTree *scene_tree = SceneTree::get_singleton();
if (scene_tree) {
debug_mesh_cache->surface_set_material(0, scene_tree->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);
if (scene_tree) {
debug_mesh_cache->surface_set_material(1, scene_tree->get_debug_collision_material());
}
}
}
}
return debug_mesh_cache;
}
void Shape3D::_update_shape() {
emit_changed();
debug_mesh_cache.unref();
}
void Shape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_solver_bias", "bias"), &Shape3D::set_custom_solver_bias);
ClassDB::bind_method(D_METHOD("get_custom_solver_bias"), &Shape3D::get_custom_solver_bias);
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape3D::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &Shape3D::get_margin);
ClassDB::bind_method(D_METHOD("get_debug_mesh"), &Shape3D::get_debug_mesh);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater,suffix:m"), "set_margin", "get_margin");
}
Shape3D::Shape3D() {
ERR_PRINT("Default constructor must not be called!");
}
Shape3D::Shape3D(RID p_shape) :
shape(p_shape) {}
Shape3D::~Shape3D() {
ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(shape);
}

View File

@@ -0,0 +1,92 @@
/**************************************************************************/
/* shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/io/resource.h"
class ArrayMesh;
class Material;
class Shape3D : public Resource {
GDCLASS(Shape3D, Resource);
OBJ_SAVE_TYPE(Shape3D);
RES_BASE_EXTENSION("shape");
RID shape;
real_t custom_bias = 0.0;
real_t margin = 0.04;
Ref<ArrayMesh> debug_mesh_cache;
// 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();
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape3D(RID p_shape);
virtual void _update_shape();
public:
virtual RID get_rid() const override { return shape; }
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;
void add_vertices_to_array(Vector<Vector3> &array, const Transform3D &p_xform);
void set_custom_solver_bias(real_t p_bias);
real_t get_custom_solver_bias() const;
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();
};

162
scene/resources/3d/skin.cpp Normal file
View File

@@ -0,0 +1,162 @@
/**************************************************************************/
/* skin.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "skin.h"
void Skin::set_bind_count(int p_size) {
ERR_FAIL_COND(p_size < 0);
binds.resize(p_size);
binds_ptr = binds.ptrw();
bind_count = p_size;
emit_changed();
}
void Skin::add_bind(int p_bone, const Transform3D &p_pose) {
uint32_t index = bind_count;
set_bind_count(bind_count + 1);
set_bind_bone(index, p_bone);
set_bind_pose(index, p_pose);
}
void Skin::add_named_bind(const String &p_name, const Transform3D &p_pose) {
uint32_t index = bind_count;
set_bind_count(bind_count + 1);
set_bind_name(index, p_name);
set_bind_pose(index, p_pose);
}
void Skin::set_bind_name(int p_index, const StringName &p_name) {
ERR_FAIL_INDEX(p_index, bind_count);
bool notify_change = (binds_ptr[p_index].name != StringName()) != (p_name != StringName());
binds_ptr[p_index].name = p_name;
emit_changed();
if (notify_change) {
notify_property_list_changed();
}
}
void Skin::set_bind_bone(int p_index, int p_bone) {
ERR_FAIL_INDEX(p_index, bind_count);
binds_ptr[p_index].bone = p_bone;
emit_changed();
}
void Skin::set_bind_pose(int p_index, const Transform3D &p_pose) {
ERR_FAIL_INDEX(p_index, bind_count);
binds_ptr[p_index].pose = p_pose;
emit_changed();
}
void Skin::clear_binds() {
binds.clear();
binds_ptr = nullptr;
bind_count = 0;
emit_changed();
}
void Skin::reset_state() {
clear_binds();
}
bool Skin::_set(const StringName &p_name, const Variant &p_value) {
String prop_name = p_name;
if (prop_name == "bind_count") {
set_bind_count(p_value);
return true;
} else if (prop_name.begins_with("bind/")) {
int index = prop_name.get_slicec('/', 1).to_int();
String what = prop_name.get_slicec('/', 2);
if (what == "bone") {
set_bind_bone(index, p_value);
return true;
} else if (what == "name") {
set_bind_name(index, p_value);
return true;
} else if (what == "pose") {
set_bind_pose(index, p_value);
return true;
}
}
return false;
}
bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
String prop_name = p_name;
if (prop_name == "bind_count") {
r_ret = get_bind_count();
return true;
} else if (prop_name.begins_with("bind/")) {
int index = prop_name.get_slicec('/', 1).to_int();
String what = prop_name.get_slicec('/', 2);
if (what == "bone") {
r_ret = get_bind_bone(index);
return true;
} else if (what == "name") {
r_ret = get_bind_name(index);
return true;
} else if (what == "pose") {
r_ret = get_bind_pose(index);
return true;
}
}
return false;
}
void Skin::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT, PNAME("bind_count"), PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
for (int i = 0; i < get_bind_count(); i++) {
const String prefix = vformat("%s/%d/", PNAME("bind"), i);
p_list->push_back(PropertyInfo(Variant::STRING_NAME, prefix + PNAME("name")));
p_list->push_back(PropertyInfo(Variant::INT, prefix + PNAME("bone"), PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NO_EDITOR : PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prefix + PNAME("pose")));
}
}
void Skin::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bind_count", "bind_count"), &Skin::set_bind_count);
ClassDB::bind_method(D_METHOD("get_bind_count"), &Skin::get_bind_count);
ClassDB::bind_method(D_METHOD("add_bind", "bone", "pose"), &Skin::add_bind);
ClassDB::bind_method(D_METHOD("add_named_bind", "name", "pose"), &Skin::add_named_bind);
ClassDB::bind_method(D_METHOD("set_bind_pose", "bind_index", "pose"), &Skin::set_bind_pose);
ClassDB::bind_method(D_METHOD("get_bind_pose", "bind_index"), &Skin::get_bind_pose);
ClassDB::bind_method(D_METHOD("set_bind_name", "bind_index", "name"), &Skin::set_bind_name);
ClassDB::bind_method(D_METHOD("get_bind_name", "bind_index"), &Skin::get_bind_name);
ClassDB::bind_method(D_METHOD("set_bind_bone", "bind_index", "bone"), &Skin::set_bind_bone);
ClassDB::bind_method(D_METHOD("get_bind_bone", "bind_index"), &Skin::get_bind_bone);
ClassDB::bind_method(D_METHOD("clear_binds"), &Skin::clear_binds);
}
Skin::Skin() {
}

86
scene/resources/3d/skin.h Normal file
View File

@@ -0,0 +1,86 @@
/**************************************************************************/
/* skin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/io/resource.h"
class Skin : public Resource {
GDCLASS(Skin, Resource)
struct Bind {
int bone = -1;
StringName name;
Transform3D pose;
};
Vector<Bind> binds;
Bind *binds_ptr = nullptr;
int bind_count = 0;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
virtual void reset_state() override;
static void _bind_methods();
public:
void set_bind_count(int p_size);
inline int get_bind_count() const { return bind_count; }
void add_bind(int p_bone, const Transform3D &p_pose);
void add_named_bind(const String &p_name, const Transform3D &p_pose);
void set_bind_bone(int p_index, int p_bone);
void set_bind_pose(int p_index, const Transform3D &p_pose);
void set_bind_name(int p_index, const StringName &p_name);
inline int get_bind_bone(int p_index) const {
ERR_FAIL_INDEX_V(p_index, bind_count, -1);
return binds_ptr[p_index].bone;
}
inline StringName get_bind_name(int p_index) const {
ERR_FAIL_INDEX_V(p_index, bind_count, StringName());
return binds_ptr[p_index].name;
}
inline Transform3D get_bind_pose(int p_index) const {
ERR_FAIL_INDEX_V(p_index, bind_count, Transform3D());
return binds_ptr[p_index].pose;
}
void clear_binds();
Skin();
};

View File

@@ -0,0 +1,838 @@
/**************************************************************************/
/* sky_material.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "sky_material.h"
#include "core/config/project_settings.h"
#include "core/version.h"
Mutex ProceduralSkyMaterial::shader_mutex;
RID ProceduralSkyMaterial::shader_cache[4];
void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {
sky_top_color = p_sky_top;
RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);
}
Color ProceduralSkyMaterial::get_sky_top_color() const {
return sky_top_color;
}
void ProceduralSkyMaterial::set_sky_horizon_color(const Color &p_sky_horizon) {
sky_horizon_color = p_sky_horizon;
RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);
}
Color ProceduralSkyMaterial::get_sky_horizon_color() const {
return sky_horizon_color;
}
void ProceduralSkyMaterial::set_sky_curve(float p_curve) {
sky_curve = p_curve;
// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be
// in calculated in angles and now uses cosines.
RS::get_singleton()->material_set_param(_get_material(), "inv_sky_curve", 0.6 / sky_curve);
}
float ProceduralSkyMaterial::get_sky_curve() const {
return sky_curve;
}
void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) {
sky_energy_multiplier = p_multiplier;
RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color * sky_energy_multiplier);
RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color * sky_energy_multiplier);
RS::get_singleton()->material_set_param(_get_material(), "sky_cover_modulate", Color(sky_cover_modulate.r, sky_cover_modulate.g, sky_cover_modulate.b, sky_cover_modulate.a * sky_energy_multiplier));
}
float ProceduralSkyMaterial::get_sky_energy_multiplier() const {
return sky_energy_multiplier;
}
void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) {
sky_cover = p_sky_cover;
if (p_sky_cover.is_valid()) {
RS::get_singleton()->material_set_param(_get_material(), "sky_cover", p_sky_cover->get_rid());
} else {
RS::get_singleton()->material_set_param(_get_material(), "sky_cover", Variant());
}
_update_shader(use_debanding, sky_cover.is_valid());
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
}
}
Ref<Texture2D> ProceduralSkyMaterial::get_sky_cover() const {
return sky_cover;
}
void ProceduralSkyMaterial::set_sky_cover_modulate(const Color &p_sky_cover_modulate) {
sky_cover_modulate = p_sky_cover_modulate;
RS::get_singleton()->material_set_param(_get_material(), "sky_cover_modulate", Color(sky_cover_modulate.r, sky_cover_modulate.g, sky_cover_modulate.b, sky_cover_modulate.a * sky_energy_multiplier));
}
Color ProceduralSkyMaterial::get_sky_cover_modulate() const {
return sky_cover_modulate;
}
void ProceduralSkyMaterial::set_ground_bottom_color(const Color &p_ground_bottom) {
ground_bottom_color = p_ground_bottom;
RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);
}
Color ProceduralSkyMaterial::get_ground_bottom_color() const {
return ground_bottom_color;
}
void ProceduralSkyMaterial::set_ground_horizon_color(const Color &p_ground_horizon) {
ground_horizon_color = p_ground_horizon;
RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);
}
Color ProceduralSkyMaterial::get_ground_horizon_color() const {
return ground_horizon_color;
}
void ProceduralSkyMaterial::set_ground_curve(float p_curve) {
ground_curve = p_curve;
// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be
// in calculated in angles and now uses cosines.
RS::get_singleton()->material_set_param(_get_material(), "inv_ground_curve", 0.6 / ground_curve);
}
float ProceduralSkyMaterial::get_ground_curve() const {
return ground_curve;
}
void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) {
ground_energy_multiplier = p_multiplier;
RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color * ground_energy_multiplier);
RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color * ground_energy_multiplier);
}
float ProceduralSkyMaterial::get_ground_energy_multiplier() const {
return ground_energy_multiplier;
}
void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {
sun_angle_max = p_angle;
RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::cos(Math::deg_to_rad(sun_angle_max)));
}
float ProceduralSkyMaterial::get_sun_angle_max() const {
return sun_angle_max;
}
void ProceduralSkyMaterial::set_sun_curve(float p_curve) {
sun_curve = p_curve;
// Actual curve passed to shader includes an ad hoc adjustment because the curve used to be
// in calculated in angles and now uses cosines.
RS::get_singleton()->material_set_param(_get_material(), "inv_sun_curve", 1.6f / Math::pow(sun_curve, 1.4f));
}
float ProceduralSkyMaterial::get_sun_curve() const {
return sun_curve;
}
void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
use_debanding = p_use_debanding;
_update_shader(use_debanding, sky_cover.is_valid());
// Only set if shader already compiled
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
}
}
bool ProceduralSkyMaterial::get_use_debanding() const {
return use_debanding;
}
void ProceduralSkyMaterial::set_energy_multiplier(float p_multiplier) {
global_energy_multiplier = p_multiplier;
RS::get_singleton()->material_set_param(_get_material(), "exposure", global_energy_multiplier);
}
float ProceduralSkyMaterial::get_energy_multiplier() const {
return global_energy_multiplier;
}
Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
// Internal function to grab the current shader RID.
// Must only be called if the shader is initialized.
RID ProceduralSkyMaterial::get_shader_cache() const {
return shader_cache[int(use_debanding) + (sky_cover.is_valid() ? 2 : 0)];
}
RID ProceduralSkyMaterial::get_rid() const {
_update_shader(use_debanding, sky_cover.is_valid());
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
shader_set = true;
}
return _get_material();
}
RID ProceduralSkyMaterial::get_shader_rid() const {
_update_shader(use_debanding, sky_cover.is_valid());
return get_shader_cache();
}
void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color);
ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color);
ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSkyMaterial::set_sky_horizon_color);
ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSkyMaterial::get_sky_horizon_color);
ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);
ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);
ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier);
ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover);
ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover);
ClassDB::bind_method(D_METHOD("set_sky_cover_modulate", "color"), &ProceduralSkyMaterial::set_sky_cover_modulate);
ClassDB::bind_method(D_METHOD("get_sky_cover_modulate"), &ProceduralSkyMaterial::get_sky_cover_modulate);
ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSkyMaterial::set_ground_bottom_color);
ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSkyMaterial::get_ground_bottom_color);
ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSkyMaterial::set_ground_horizon_color);
ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSkyMaterial::get_ground_horizon_color);
ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);
ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);
ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier);
ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);
ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);
ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);
ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);
ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding);
ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding);
ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_energy_multiplier);
ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &ProceduralSkyMaterial::get_energy_multiplier);
ADD_GROUP("Sky", "sky_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_sky_cover", "get_sky_cover");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate");
ADD_GROUP("Ground", "ground_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier");
ADD_GROUP("Sun", "sun_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");
ADD_GROUP("", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
}
void ProceduralSkyMaterial::cleanup_shader() {
for (int i = 0; i < 4; i++) {
if (shader_cache[i].is_valid()) {
RS::get_singleton()->free(shader_cache[i]);
}
}
}
void ProceduralSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_sky_cover) {
MutexLock shader_lock(shader_mutex);
int index = int(p_use_debanding) + int(p_use_sky_cover) * 2;
if (shader_cache[index].is_null()) {
shader_cache[index] = RS::get_singleton()->shader_create();
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(
// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.
shader_type sky;
%s
uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
uniform float inv_sky_curve : hint_range(1, 100) = 4.0;
uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);
uniform vec4 ground_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
uniform float inv_ground_curve : hint_range(1, 100) = 30.0;
uniform float sun_angle_max = 0.877;
uniform float inv_sun_curve : hint_range(1, 100) = 22.78;
uniform float exposure : hint_range(0, 128) = 1.0;
uniform sampler2D sky_cover : filter_linear, source_color, hint_default_black;
uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);
void sky() {
float v_angle = clamp(EYEDIR.y, -1.0, 1.0);
vec3 sky = mix(sky_top_color.rgb, sky_horizon_color.rgb, clamp(pow(1.0 - v_angle, inv_sky_curve), 0.0, 1.0));
if (LIGHT0_ENABLED) {
float sun_angle = dot(LIGHT0_DIRECTION, EYEDIR);
float sun_size = cos(LIGHT0_SIZE);
if (sun_angle > sun_size) {
sky = LIGHT0_COLOR * LIGHT0_ENERGY;
} else if (sun_angle > sun_angle_max) {
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
sky = mix(sky, LIGHT0_COLOR * LIGHT0_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
}
}
if (LIGHT1_ENABLED) {
float sun_angle = dot(LIGHT1_DIRECTION, EYEDIR);
float sun_size = cos(LIGHT1_SIZE);
if (sun_angle > sun_size) {
sky = LIGHT1_COLOR * LIGHT1_ENERGY;
} else if (sun_angle > sun_angle_max) {
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
sky = mix(sky, LIGHT1_COLOR * LIGHT1_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
}
}
if (LIGHT2_ENABLED) {
float sun_angle = dot(LIGHT2_DIRECTION, EYEDIR);
float sun_size = cos(LIGHT2_SIZE);
if (sun_angle > sun_size) {
sky = LIGHT2_COLOR * LIGHT2_ENERGY;
} else if (sun_angle > sun_angle_max) {
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
sky = mix(sky, LIGHT2_COLOR * LIGHT2_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
}
}
if (LIGHT3_ENABLED) {
float sun_angle = dot(LIGHT3_DIRECTION, EYEDIR);
float sun_size = cos(LIGHT3_SIZE);
if (sun_angle > sun_size) {
sky = LIGHT3_COLOR * LIGHT3_ENERGY;
} else if (sun_angle > sun_angle_max) {
float c2 = (sun_size - sun_angle) / (sun_size - sun_angle_max);
sky = mix(sky, LIGHT3_COLOR * LIGHT3_ENERGY, clamp(pow(1.0 - c2, inv_sun_curve), 0.0, 1.0));
}
}
%s
%s
vec3 ground = mix(ground_bottom_color.rgb, ground_horizon_color.rgb, clamp(pow(1.0 + v_angle, inv_ground_curve), 0.0, 1.0));
COLOR = mix(ground, sky, step(0.0, EYEDIR.y)) * exposure;
}
)",
p_use_debanding ? "render_mode use_debanding;" : "", p_use_sky_cover ? "vec4 sky_cover_texture = texture(sky_cover, SKY_COORDS);" : "", p_use_sky_cover ? "sky += (sky_cover_texture.rgb * sky_cover_modulate.rgb) * sky_cover_texture.a * sky_cover_modulate.a;" : ""));
}
}
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);
set_sky_energy_multiplier(1.0);
set_sky_cover_modulate(Color(1, 1, 1));
set_ground_bottom_color(Color(0.2, 0.169, 0.133));
set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_ground_curve(0.02);
set_ground_energy_multiplier(1.0);
set_sun_angle_max(30.0);
set_sun_curve(0.15);
set_use_debanding(true);
set_energy_multiplier(1.0);
}
ProceduralSkyMaterial::~ProceduralSkyMaterial() {
}
/////////////////////////////////////////
/* PanoramaSkyMaterial */
void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) {
panorama = p_panorama;
if (p_panorama.is_valid()) {
RS::get_singleton()->material_set_param(_get_material(), "source_panorama", p_panorama->get_rid());
} else {
RS::get_singleton()->material_set_param(_get_material(), "source_panorama", Variant());
}
}
Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {
return panorama;
}
void PanoramaSkyMaterial::set_filtering_enabled(bool p_enabled) {
filter = p_enabled;
notify_property_list_changed();
_update_shader(filter);
// Only set if shader already compiled
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
}
}
bool PanoramaSkyMaterial::is_filtering_enabled() const {
return filter;
}
void PanoramaSkyMaterial::set_energy_multiplier(float p_multiplier) {
energy_multiplier = p_multiplier;
RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);
}
float PanoramaSkyMaterial::get_energy_multiplier() const {
return energy_multiplier;
}
Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
RID PanoramaSkyMaterial::get_rid() const {
_update_shader(filter);
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
shader_set = true;
}
return _get_material();
}
RID PanoramaSkyMaterial::get_shader_rid() const {
_update_shader(filter);
return shader_cache[int(filter)];
}
void PanoramaSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSkyMaterial::set_panorama);
ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSkyMaterial::get_panorama);
ClassDB::bind_method(D_METHOD("set_filtering_enabled", "enabled"), &PanoramaSkyMaterial::set_filtering_enabled);
ClassDB::bind_method(D_METHOD("is_filtering_enabled"), &PanoramaSkyMaterial::is_filtering_enabled);
ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PanoramaSkyMaterial::set_energy_multiplier);
ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PanoramaSkyMaterial::get_energy_multiplier);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_panorama", "get_panorama");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter"), "set_filtering_enabled", "is_filtering_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
}
Mutex PanoramaSkyMaterial::shader_mutex;
RID PanoramaSkyMaterial::shader_cache[2];
void PanoramaSkyMaterial::cleanup_shader() {
for (int i = 0; i < 2; i++) {
if (shader_cache[i].is_valid()) {
RS::get_singleton()->free(shader_cache[i]);
}
}
}
void PanoramaSkyMaterial::_update_shader(bool p_filter) {
MutexLock shader_lock(shader_mutex);
int index = int(p_filter);
if (shader_cache[index].is_null()) {
shader_cache[index] = RS::get_singleton()->shader_create();
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(
// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PanoramaSkyMaterial.
shader_type sky;
uniform sampler2D source_panorama : %s, source_color, hint_default_black;
uniform float exposure : hint_range(0, 128) = 1.0;
void sky() {
COLOR = texture(source_panorama, SKY_COORDS).rgb * exposure;
}
)",
p_filter ? "filter_linear" : "filter_nearest"));
}
}
PanoramaSkyMaterial::PanoramaSkyMaterial() {
_set_material(RS::get_singleton()->material_create());
set_energy_multiplier(1.0);
}
PanoramaSkyMaterial::~PanoramaSkyMaterial() {
}
//////////////////////////////////
/* PhysicalSkyMaterial */
void PhysicalSkyMaterial::set_rayleigh_coefficient(float p_rayleigh) {
rayleigh = p_rayleigh;
RS::get_singleton()->material_set_param(_get_material(), "rayleigh", rayleigh);
}
float PhysicalSkyMaterial::get_rayleigh_coefficient() const {
return rayleigh;
}
void PhysicalSkyMaterial::set_rayleigh_color(Color p_rayleigh_color) {
rayleigh_color = p_rayleigh_color;
RS::get_singleton()->material_set_param(_get_material(), "rayleigh_color", rayleigh_color);
}
Color PhysicalSkyMaterial::get_rayleigh_color() const {
return rayleigh_color;
}
void PhysicalSkyMaterial::set_mie_coefficient(float p_mie) {
mie = p_mie;
RS::get_singleton()->material_set_param(_get_material(), "mie", mie);
}
float PhysicalSkyMaterial::get_mie_coefficient() const {
return mie;
}
void PhysicalSkyMaterial::set_mie_eccentricity(float p_eccentricity) {
mie_eccentricity = p_eccentricity;
RS::get_singleton()->material_set_param(_get_material(), "mie_eccentricity", mie_eccentricity);
}
float PhysicalSkyMaterial::get_mie_eccentricity() const {
return mie_eccentricity;
}
void PhysicalSkyMaterial::set_mie_color(Color p_mie_color) {
mie_color = p_mie_color;
RS::get_singleton()->material_set_param(_get_material(), "mie_color", mie_color);
}
Color PhysicalSkyMaterial::get_mie_color() const {
return mie_color;
}
void PhysicalSkyMaterial::set_turbidity(float p_turbidity) {
turbidity = p_turbidity;
RS::get_singleton()->material_set_param(_get_material(), "turbidity", turbidity);
}
float PhysicalSkyMaterial::get_turbidity() const {
return turbidity;
}
void PhysicalSkyMaterial::set_sun_disk_scale(float p_sun_disk_scale) {
sun_disk_scale = p_sun_disk_scale;
RS::get_singleton()->material_set_param(_get_material(), "sun_disk_scale", sun_disk_scale);
}
float PhysicalSkyMaterial::get_sun_disk_scale() const {
return sun_disk_scale;
}
void PhysicalSkyMaterial::set_ground_color(Color p_ground_color) {
ground_color = p_ground_color;
RS::get_singleton()->material_set_param(_get_material(), "ground_color", ground_color);
}
Color PhysicalSkyMaterial::get_ground_color() const {
return ground_color;
}
void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) {
energy_multiplier = p_multiplier;
RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);
}
float PhysicalSkyMaterial::get_energy_multiplier() const {
return energy_multiplier;
}
void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
use_debanding = p_use_debanding;
_update_shader(use_debanding, night_sky.is_valid());
// Only set if shader already compiled
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
}
}
bool PhysicalSkyMaterial::get_use_debanding() const {
return use_debanding;
}
void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) {
night_sky = p_night_sky;
if (p_night_sky.is_valid()) {
RS::get_singleton()->material_set_param(_get_material(), "night_sky", p_night_sky->get_rid());
} else {
RS::get_singleton()->material_set_param(_get_material(), "night_sky", Variant());
}
_update_shader(use_debanding, night_sky.is_valid());
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
}
}
Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const {
return night_sky;
}
Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
// Internal function to grab the current shader RID.
// Must only be called if the shader is initialized.
RID PhysicalSkyMaterial::get_shader_cache() const {
return shader_cache[int(use_debanding) + (night_sky.is_valid() ? 2 : 0)];
}
RID PhysicalSkyMaterial::get_rid() const {
_update_shader(use_debanding, night_sky.is_valid());
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), get_shader_cache());
shader_set = true;
}
return _get_material();
}
RID PhysicalSkyMaterial::get_shader_rid() const {
_update_shader(use_debanding, night_sky.is_valid());
return get_shader_cache();
}
void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
if (p_property.name == "exposure_value" && !GLOBAL_GET_CACHED(bool, "rendering/lights_and_shadows/use_physical_light_units")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
Mutex PhysicalSkyMaterial::shader_mutex;
RID PhysicalSkyMaterial::shader_cache[4];
void PhysicalSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);
ClassDB::bind_method(D_METHOD("get_rayleigh_coefficient"), &PhysicalSkyMaterial::get_rayleigh_coefficient);
ClassDB::bind_method(D_METHOD("set_rayleigh_color", "color"), &PhysicalSkyMaterial::set_rayleigh_color);
ClassDB::bind_method(D_METHOD("get_rayleigh_color"), &PhysicalSkyMaterial::get_rayleigh_color);
ClassDB::bind_method(D_METHOD("set_mie_coefficient", "mie"), &PhysicalSkyMaterial::set_mie_coefficient);
ClassDB::bind_method(D_METHOD("get_mie_coefficient"), &PhysicalSkyMaterial::get_mie_coefficient);
ClassDB::bind_method(D_METHOD("set_mie_eccentricity", "eccentricity"), &PhysicalSkyMaterial::set_mie_eccentricity);
ClassDB::bind_method(D_METHOD("get_mie_eccentricity"), &PhysicalSkyMaterial::get_mie_eccentricity);
ClassDB::bind_method(D_METHOD("set_mie_color", "color"), &PhysicalSkyMaterial::set_mie_color);
ClassDB::bind_method(D_METHOD("get_mie_color"), &PhysicalSkyMaterial::get_mie_color);
ClassDB::bind_method(D_METHOD("set_turbidity", "turbidity"), &PhysicalSkyMaterial::set_turbidity);
ClassDB::bind_method(D_METHOD("get_turbidity"), &PhysicalSkyMaterial::get_turbidity);
ClassDB::bind_method(D_METHOD("set_sun_disk_scale", "scale"), &PhysicalSkyMaterial::set_sun_disk_scale);
ClassDB::bind_method(D_METHOD("get_sun_disk_scale"), &PhysicalSkyMaterial::get_sun_disk_scale);
ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);
ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);
ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier);
ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);
ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);
ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky);
ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky);
ADD_GROUP("Rayleigh", "rayleigh_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rayleigh_coefficient", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_rayleigh_coefficient", "get_rayleigh_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "rayleigh_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_rayleigh_color", "get_rayleigh_color");
ADD_GROUP("Mie", "mie_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_coefficient", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_mie_coefficient", "get_mie_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_eccentricity", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_mie_eccentricity", "get_mie_eccentricity");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "mie_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_mie_color", "get_mie_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky");
}
void PhysicalSkyMaterial::cleanup_shader() {
for (int i = 0; i < 4; i++) {
if (shader_cache[i].is_valid()) {
RS::get_singleton()->free(shader_cache[i]);
}
}
}
void PhysicalSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_night_sky) {
MutexLock shader_lock(shader_mutex);
int index = int(p_use_debanding) + int(p_use_night_sky) * 2;
if (shader_cache[index].is_null()) {
shader_cache[index] = RS::get_singleton()->shader_create();
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader_cache[index], vformat(R"(
// NOTE: Shader automatically converted from )" GODOT_VERSION_NAME " " GODOT_VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.
shader_type sky;
%s
uniform float rayleigh : hint_range(0, 64) = 2.0;
uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);
uniform float mie : hint_range(0, 1) = 0.005;
uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;
uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);
uniform float turbidity : hint_range(0, 1000) = 10.0;
uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
uniform float exposure : hint_range(0, 128) = 1.0;
uniform sampler2D night_sky : filter_linear, source_color, hint_default_black;
const vec3 UP = vec3( 0.0, 1.0, 0.0 );
// Optical length at zenith for molecules.
const float rayleigh_zenith_size = 8.4e3;
const float mie_zenith_size = 1.25e3;
float henyey_greenstein(float cos_theta, float g) {
const float k = 0.0795774715459;
return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
}
void sky() {
if (LIGHT0_ENABLED) {
float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
float sun_energy = max(0.0, 0.757 * zenith_angle) * LIGHT0_ENERGY;
float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);
// Rayleigh coefficients.
float rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );
vec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;
// mie coefficients from Preetham
vec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;
// Optical length.
float zenith = max(0.0, dot(UP, EYEDIR));
float optical_mass = 1.0 / (zenith + 0.15 * pow(3.885 + 54.5 * zenith, -1.253));
float rayleigh_scatter = rayleigh_zenith_size * optical_mass;
float mie_scatter = mie_zenith_size * optical_mass;
// Light extinction based on thickness of atmosphere.
vec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));
// In scattering.
float cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));
float rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));
vec3 betaRTheta = rayleigh_beta * rayleigh_phase;
float mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);
vec3 betaMTheta = mie_beta * mie_phase;
vec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));
// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js
Lin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));
// Hack in the ground color.
Lin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));
// Solar disk and out-scattering.
float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);
float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale * 0.5);
float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);
vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR;
%s
vec3 color = Lin + L0;
COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
COLOR *= exposure;
} else {
// There is no sun, so display night_sky and nothing else.
%s
COLOR *= exposure;
}
}
)",
p_use_debanding ? "render_mode use_debanding;" : "", p_use_night_sky ? "L0 += texture(night_sky, SKY_COORDS).xyz * extinction;" : "", p_use_night_sky ? "COLOR = texture(night_sky, SKY_COORDS).xyz;" : ""));
}
}
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);
set_mie_eccentricity(0.8);
set_mie_color(Color(0.69, 0.729, 0.812));
set_turbidity(10.0);
set_sun_disk_scale(1.0);
set_ground_color(Color(0.1, 0.07, 0.034));
set_energy_multiplier(1.0);
set_use_debanding(true);
}
PhysicalSkyMaterial::~PhysicalSkyMaterial() {
}

View File

@@ -0,0 +1,236 @@
/**************************************************************************/
/* sky_material.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/templates/rid.h"
#include "scene/resources/material.h"
class ProceduralSkyMaterial : public Material {
GDCLASS(ProceduralSkyMaterial, Material);
private:
Color sky_top_color;
Color sky_horizon_color;
float sky_curve = 0.0f;
float sky_energy_multiplier = 0.0f;
Ref<Texture2D> sky_cover;
Color sky_cover_modulate;
Color ground_bottom_color;
Color ground_horizon_color;
float ground_curve = 0.0f;
float ground_energy_multiplier = 0.0f;
float sun_angle_max = 0.0f;
float sun_curve = 0.0f;
bool use_debanding = true;
float global_energy_multiplier = 1.0f;
static Mutex shader_mutex;
static RID shader_cache[4];
static void _update_shader(bool p_use_debanding, bool p_use_sky_cover);
mutable bool shader_set = false;
RID get_shader_cache() const;
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &property) const;
public:
void set_sky_top_color(const Color &p_sky_top);
Color get_sky_top_color() const;
void set_sky_horizon_color(const Color &p_sky_horizon);
Color get_sky_horizon_color() const;
void set_sky_curve(float p_curve);
float get_sky_curve() const;
void set_sky_energy_multiplier(float p_multiplier);
float get_sky_energy_multiplier() const;
void set_sky_cover(const Ref<Texture2D> &p_sky_cover);
Ref<Texture2D> get_sky_cover() const;
void set_sky_cover_modulate(const Color &p_sky_cover_modulate);
Color get_sky_cover_modulate() const;
void set_ground_bottom_color(const Color &p_ground_bottom);
Color get_ground_bottom_color() const;
void set_ground_horizon_color(const Color &p_ground_horizon);
Color get_ground_horizon_color() const;
void set_ground_curve(float p_curve);
float get_ground_curve() const;
void set_ground_energy_multiplier(float p_energy);
float get_ground_energy_multiplier() const;
void set_sun_angle_max(float p_angle);
float get_sun_angle_max() const;
void set_sun_curve(float p_curve);
float get_sun_curve() const;
void set_use_debanding(bool p_use_debanding);
bool get_use_debanding() const;
void set_energy_multiplier(float p_multiplier);
float get_energy_multiplier() const;
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
static void cleanup_shader();
ProceduralSkyMaterial();
~ProceduralSkyMaterial();
};
//////////////////////////////////////////////////////
/* PanoramaSkyMaterial */
class PanoramaSkyMaterial : public Material {
GDCLASS(PanoramaSkyMaterial, Material);
private:
Ref<Texture2D> panorama;
float energy_multiplier = 1.0f;
static Mutex shader_mutex;
static RID shader_cache[2];
static void _update_shader(bool p_filter);
mutable bool shader_set = false;
bool filter = true;
protected:
static void _bind_methods();
public:
void set_panorama(const Ref<Texture2D> &p_panorama);
Ref<Texture2D> get_panorama() const;
void set_filtering_enabled(bool p_enabled);
bool is_filtering_enabled() const;
void set_energy_multiplier(float p_multiplier);
float get_energy_multiplier() const;
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
static void cleanup_shader();
PanoramaSkyMaterial();
~PanoramaSkyMaterial();
};
//////////////////////////////////////////////////////
/* PanoramaSkyMaterial */
class PhysicalSkyMaterial : public Material {
GDCLASS(PhysicalSkyMaterial, Material);
private:
static Mutex shader_mutex;
static RID shader_cache[4];
RID get_shader_cache() const;
float rayleigh = 0.0f;
Color rayleigh_color;
float mie = 0.0f;
float mie_eccentricity = 0.0f;
Color mie_color;
float turbidity = 0.0f;
float sun_disk_scale = 0.0f;
Color ground_color;
float energy_multiplier = 1.0f;
bool use_debanding = true;
Ref<Texture2D> night_sky;
static void _update_shader(bool p_use_debanding, bool p_use_night_sky);
mutable bool shader_set = false;
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &property) const;
public:
void set_rayleigh_coefficient(float p_rayleigh);
float get_rayleigh_coefficient() const;
void set_rayleigh_color(Color p_rayleigh_color);
Color get_rayleigh_color() const;
void set_turbidity(float p_turbidity);
float get_turbidity() const;
void set_mie_coefficient(float p_mie);
float get_mie_coefficient() const;
void set_mie_eccentricity(float p_eccentricity);
float get_mie_eccentricity() const;
void set_mie_color(Color p_mie_color);
Color get_mie_color() const;
void set_sun_disk_scale(float p_sun_disk_scale);
float get_sun_disk_scale() const;
void set_ground_color(Color p_ground_color);
Color get_ground_color() const;
void set_energy_multiplier(float p_multiplier);
float get_energy_multiplier() const;
void set_exposure_value(float p_exposure);
float get_exposure_value() const;
void set_use_debanding(bool p_use_debanding);
bool get_use_debanding() const;
void set_night_sky(const Ref<Texture2D> &p_night_sky);
Ref<Texture2D> get_night_sky() const;
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
static void cleanup_shader();
virtual RID get_rid() const override;
PhysicalSkyMaterial();
~PhysicalSkyMaterial();
};

View File

@@ -0,0 +1,106 @@
/**************************************************************************/
/* sphere_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
float r = get_radius();
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
float ra = Math::deg_to_rad((float)i);
float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
points.push_back(Vector3(a.x, 0, a.y));
points.push_back(Vector3(b.x, 0, b.y));
points.push_back(Vector3(0, a.x, a.y));
points.push_back(Vector3(0, b.x, b.y));
points.push_back(Vector3(a.x, a.y, 0));
points.push_back(Vector3(b.x, b.y, 0));
}
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;
}
void SphereShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), radius);
Shape3D::_update_shape();
}
void SphereShape3D::set_radius(float p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0, "SphereShape3D radius cannot be negative.");
radius = p_radius;
_update_shape();
emit_changed();
}
float SphereShape3D::get_radius() const {
return radius;
}
void SphereShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape3D::get_radius);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
SphereShape3D::SphereShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SPHERE)) {
set_radius(0.5);
}

View File

@@ -0,0 +1,55 @@
/**************************************************************************/
/* sphere_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class SphereShape3D : public Shape3D {
GDCLASS(SphereShape3D, Shape3D);
float radius = 0.5f;
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_radius(float p_radius);
float get_radius() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SphereShape3D();
};

View File

@@ -0,0 +1,210 @@
/**************************************************************************/
/* world_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "world_3d.h"
#include "core/config/project_settings.h"
#include "scene/3d/camera_3d.h"
#include "scene/resources/camera_attributes.h"
#include "scene/resources/environment.h"
#ifndef NAVIGATION_3D_DISABLED
#include "servers/navigation_server_3d.h"
#endif // NAVIGATION_3D_DISABLED
void World3D::_register_camera(Camera3D *p_camera) {
cameras.insert(p_camera);
}
void World3D::_remove_camera(Camera3D *p_camera) {
cameras.erase(p_camera);
}
RID World3D::get_space() const {
#ifndef PHYSICS_3D_DISABLED
if (space.is_null()) {
space = PhysicsServer3D::get_singleton()->space_create();
PhysicsServer3D::get_singleton()->space_set_active(space, true);
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_GET("physics/3d/default_gravity"));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_GET("physics/3d/default_gravity_vector"));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_GET("physics/3d/default_linear_damp"));
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_GET("physics/3d/default_angular_damp"));
}
#endif // PHYSICS_3D_DISABLED
return space;
}
#ifndef NAVIGATION_3D_DISABLED
RID World3D::get_navigation_map() const {
if (navigation_map.is_null()) {
navigation_map = NavigationServer3D::get_singleton()->map_create();
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_GET("navigation/3d/default_cell_size"));
NavigationServer3D::get_singleton()->map_set_cell_height(navigation_map, GLOBAL_GET("navigation/3d/default_cell_height"));
NavigationServer3D::get_singleton()->map_set_up(navigation_map, GLOBAL_GET("navigation/3d/default_up"));
NavigationServer3D::get_singleton()->map_set_merge_rasterizer_cell_scale(navigation_map, GLOBAL_GET("navigation/3d/merge_rasterizer_cell_scale"));
NavigationServer3D::get_singleton()->map_set_use_edge_connections(navigation_map, GLOBAL_GET("navigation/3d/use_edge_connections"));
NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_GET("navigation/3d/default_edge_connection_margin"));
NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_GET("navigation/3d/default_link_connection_radius"));
}
return navigation_map;
}
#endif // NAVIGATION_3D_DISABLED
RID World3D::get_scenario() const {
return scenario;
}
void World3D::set_environment(const Ref<Environment> &p_environment) {
if (environment == p_environment) {
return;
}
environment = p_environment;
if (environment.is_valid()) {
RS::get_singleton()->scenario_set_environment(scenario, environment->get_rid());
} else {
RS::get_singleton()->scenario_set_environment(scenario, RID());
}
emit_changed();
}
Ref<Environment> World3D::get_environment() const {
return environment;
}
void World3D::set_fallback_environment(const Ref<Environment> &p_environment) {
if (fallback_environment == p_environment) {
return;
}
fallback_environment = p_environment;
if (fallback_environment.is_valid()) {
RS::get_singleton()->scenario_set_fallback_environment(scenario, p_environment->get_rid());
} else {
RS::get_singleton()->scenario_set_fallback_environment(scenario, RID());
}
emit_changed();
}
Ref<Environment> World3D::get_fallback_environment() const {
return fallback_environment;
}
void World3D::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
camera_attributes = p_camera_attributes;
if (camera_attributes.is_valid()) {
RS::get_singleton()->scenario_set_camera_attributes(scenario, camera_attributes->get_rid());
} else {
RS::get_singleton()->scenario_set_camera_attributes(scenario, RID());
}
}
Ref<CameraAttributes> World3D::get_camera_attributes() const {
return camera_attributes;
}
void World3D::set_compositor(const Ref<Compositor> &p_compositor) {
compositor = p_compositor;
if (compositor.is_valid()) {
RS::get_singleton()->scenario_set_compositor(scenario, compositor->get_rid());
} else {
RS::get_singleton()->scenario_set_compositor(scenario, RID());
}
}
Ref<Compositor> World3D::get_compositor() const {
return compositor;
}
#ifndef PHYSICS_3D_DISABLED
PhysicsDirectSpaceState3D *World3D::get_direct_space_state() {
return PhysicsServer3D::get_singleton()->space_get_direct_state(get_space());
}
#endif // PHYSICS_3D_DISABLED
void World3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_space"), &World3D::get_space);
#ifndef NAVIGATION_3D_DISABLED
ClassDB::bind_method(D_METHOD("get_navigation_map"), &World3D::get_navigation_map);
#endif // NAVIGATION_3D_DISABLED
ClassDB::bind_method(D_METHOD("get_scenario"), &World3D::get_scenario);
ClassDB::bind_method(D_METHOD("set_environment", "env"), &World3D::set_environment);
ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment);
ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment);
ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment);
ClassDB::bind_method(D_METHOD("set_camera_attributes", "attributes"), &World3D::set_camera_attributes);
ClassDB::bind_method(D_METHOD("get_camera_attributes"), &World3D::get_camera_attributes);
#ifndef PHYSICS_3D_DISABLED
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state);
#endif // PHYSICS_3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_space");
#ifndef NAVIGATION_3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map");
#endif // NAVIGATION_3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_scenario");
#ifndef PHYSICS_3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState3D", PROPERTY_USAGE_NONE), "", "get_direct_space_state");
#endif // PHYSICS_3D_DISABLED
}
World3D::World3D() {
scenario = RenderingServer::get_singleton()->scenario_create();
}
World3D::~World3D() {
ERR_FAIL_NULL(RenderingServer::get_singleton());
#ifndef PHYSICS_3D_DISABLED
ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
#endif // PHYSICS_3D_DISABLED
#ifndef NAVIGATION_3D_DISABLED
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
#endif // NAVIGATION_3D_DISABLED
RenderingServer::get_singleton()->free(scenario);
#ifndef PHYSICS_3D_DISABLED
if (space.is_valid()) {
PhysicsServer3D::get_singleton()->free(space);
}
#endif // PHYSICS_3D_DISABLED
#ifndef NAVIGATION_3D_DISABLED
if (navigation_map.is_valid()) {
NavigationServer3D::get_singleton()->free(navigation_map);
}
#endif // NAVIGATION_3D_DISABLED
}

View File

@@ -0,0 +1,97 @@
/**************************************************************************/
/* world_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/io/resource.h"
#include "scene/resources/compositor.h"
#include "scene/resources/environment.h"
#ifndef PHYSICS_3D_DISABLED
#include "servers/physics_server_3d.h"
#endif // PHYSICS_3D_DISABLED
class CameraAttributes;
class Camera3D;
class VisibleOnScreenNotifier3D;
struct SpatialIndexer;
class World3D : public Resource {
GDCLASS(World3D, Resource);
private:
RID scenario;
mutable RID space;
#ifndef NAVIGATION_3D_DISABLED
mutable RID navigation_map;
#endif // NAVIGATION_3D_DISABLED
Ref<Environment> environment;
Ref<Environment> fallback_environment;
Ref<CameraAttributes> camera_attributes;
Ref<Compositor> compositor;
HashSet<Camera3D *> cameras;
protected:
static void _bind_methods();
friend class Camera3D;
void _register_camera(Camera3D *p_camera);
void _remove_camera(Camera3D *p_camera);
public:
RID get_space() const;
#ifndef NAVIGATION_3D_DISABLED
RID get_navigation_map() const;
#endif // NAVIGATION_3D_DISABLED
RID get_scenario() const;
void set_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_environment() const;
void set_fallback_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_fallback_environment() const;
void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
Ref<CameraAttributes> get_camera_attributes() const;
void set_compositor(const Ref<Compositor> &p_compositor);
Ref<Compositor> get_compositor() const;
_FORCE_INLINE_ const HashSet<Camera3D *> &get_cameras() const { return cameras; }
#ifndef PHYSICS_3D_DISABLED
PhysicsDirectSpaceState3D *get_direct_space_state();
#endif // PHYSICS_3D_DISABLED
World3D();
~World3D();
};

View File

@@ -0,0 +1,137 @@
/**************************************************************************/
/* world_boundary_shape_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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 {
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[1],
pface[2],
pface[2],
pface[3],
pface[3],
pface[0],
p.normal * p.d,
p.normal * p.d + p.normal * 3
};
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();
}
void WorldBoundaryShape3D::set_plane(const Plane &p_plane) {
plane = p_plane;
_update_shape();
emit_changed();
}
const Plane &WorldBoundaryShape3D::get_plane() const {
return plane;
}
void WorldBoundaryShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldBoundaryShape3D::set_plane);
ClassDB::bind_method(D_METHOD("get_plane"), &WorldBoundaryShape3D::get_plane);
ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane", PROPERTY_HINT_NONE, "suffix:m"), "set_plane", "get_plane");
}
WorldBoundaryShape3D::WorldBoundaryShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY)) {
set_plane(Plane(0, 1, 0, 0));
}

View File

@@ -0,0 +1,57 @@
/**************************************************************************/
/* world_boundary_shape_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/resources/3d/shape_3d.h"
class ArrayMesh;
class WorldBoundaryShape3D : public Shape3D {
GDCLASS(WorldBoundaryShape3D, Shape3D);
Plane plane;
protected:
static void _bind_methods();
virtual void _update_shape() override;
public:
void set_plane(const Plane &p_plane);
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;
}
WorldBoundaryShape3D();
};