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
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:
28
scene/resources/3d/SCsub
Normal file
28
scene/resources/3d/SCsub
Normal 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")
|
120
scene/resources/3d/box_shape_3d.cpp
Normal file
120
scene/resources/3d/box_shape_3d.cpp
Normal 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));
|
||||
}
|
57
scene/resources/3d/box_shape_3d.h
Normal file
57
scene/resources/3d/box_shape_3d.h
Normal 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();
|
||||
};
|
158
scene/resources/3d/capsule_shape_3d.cpp
Normal file
158
scene/resources/3d/capsule_shape_3d.cpp
Normal 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();
|
||||
}
|
60
scene/resources/3d/capsule_shape_3d.h
Normal file
60
scene/resources/3d/capsule_shape_3d.h
Normal 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();
|
||||
};
|
136
scene/resources/3d/concave_polygon_shape_3d.cpp
Normal file
136
scene/resources/3d/concave_polygon_shape_3d.cpp
Normal 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));
|
||||
}
|
80
scene/resources/3d/concave_polygon_shape_3d.h
Normal file
80
scene/resources/3d/concave_polygon_shape_3d.h
Normal 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();
|
||||
};
|
129
scene/resources/3d/convex_polygon_shape_3d.cpp
Normal file
129
scene/resources/3d/convex_polygon_shape_3d.cpp
Normal 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)) {
|
||||
}
|
55
scene/resources/3d/convex_polygon_shape_3d.h
Normal file
55
scene/resources/3d/convex_polygon_shape_3d.h
Normal 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();
|
||||
};
|
129
scene/resources/3d/cylinder_shape_3d.cpp
Normal file
129
scene/resources/3d/cylinder_shape_3d.cpp
Normal 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();
|
||||
}
|
57
scene/resources/3d/cylinder_shape_3d.h
Normal file
57
scene/resources/3d/cylinder_shape_3d.h
Normal 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();
|
||||
};
|
183
scene/resources/3d/fog_material.cpp
Normal file
183
scene/resources/3d/fog_material.cpp
Normal 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());
|
||||
}
|
84
scene/resources/3d/fog_material.h
Normal file
84
scene/resources/3d/fog_material.h
Normal 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();
|
||||
};
|
371
scene/resources/3d/height_map_shape_3d.cpp
Normal file
371
scene/resources/3d/height_map_shape_3d.cpp
Normal 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();
|
||||
}
|
69
scene/resources/3d/height_map_shape_3d.h
Normal file
69
scene/resources/3d/height_map_shape_3d.h
Normal 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();
|
||||
};
|
1240
scene/resources/3d/importer_mesh.cpp
Normal file
1240
scene/resources/3d/importer_mesh.cpp
Normal file
File diff suppressed because it is too large
Load Diff
137
scene/resources/3d/importer_mesh.h
Normal file
137
scene/resources/3d/importer_mesh.h
Normal 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();
|
||||
};
|
406
scene/resources/3d/mesh_library.cpp
Normal file
406
scene/resources/3d/mesh_library.cpp
Normal 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() {
|
||||
}
|
120
scene/resources/3d/mesh_library.h
Normal file
120
scene/resources/3d/mesh_library.h
Normal 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();
|
||||
};
|
425
scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
Normal file
425
scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
Normal 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");
|
||||
}
|
109
scene/resources/3d/navigation_mesh_source_geometry_data_3d.h
Normal file
109
scene/resources/3d/navigation_mesh_source_geometry_data_3d.h
Normal 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(); }
|
||||
};
|
3977
scene/resources/3d/primitive_meshes.cpp
Normal file
3977
scene/resources/3d/primitive_meshes.cpp
Normal file
File diff suppressed because it is too large
Load Diff
678
scene/resources/3d/primitive_meshes.h
Normal file
678
scene/resources/3d/primitive_meshes.h
Normal 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)
|
97
scene/resources/3d/separation_ray_shape_3d.cpp
Normal file
97
scene/resources/3d/separation_ray_shape_3d.cpp
Normal 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();
|
||||
}
|
58
scene/resources/3d/separation_ray_shape_3d.h
Normal file
58
scene/resources/3d/separation_ray_shape_3d.h
Normal 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();
|
||||
};
|
169
scene/resources/3d/shape_3d.cpp
Normal file
169
scene/resources/3d/shape_3d.cpp
Normal 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);
|
||||
}
|
92
scene/resources/3d/shape_3d.h
Normal file
92
scene/resources/3d/shape_3d.h
Normal 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
162
scene/resources/3d/skin.cpp
Normal 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
86
scene/resources/3d/skin.h
Normal 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();
|
||||
};
|
838
scene/resources/3d/sky_material.cpp
Normal file
838
scene/resources/3d/sky_material.cpp
Normal 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() {
|
||||
}
|
236
scene/resources/3d/sky_material.h
Normal file
236
scene/resources/3d/sky_material.h
Normal 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();
|
||||
};
|
106
scene/resources/3d/sphere_shape_3d.cpp
Normal file
106
scene/resources/3d/sphere_shape_3d.cpp
Normal 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);
|
||||
}
|
55
scene/resources/3d/sphere_shape_3d.h
Normal file
55
scene/resources/3d/sphere_shape_3d.h
Normal 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();
|
||||
};
|
210
scene/resources/3d/world_3d.cpp
Normal file
210
scene/resources/3d/world_3d.cpp
Normal 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
|
||||
}
|
97
scene/resources/3d/world_3d.h
Normal file
97
scene/resources/3d/world_3d.h
Normal 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();
|
||||
};
|
137
scene/resources/3d/world_boundary_shape_3d.cpp
Normal file
137
scene/resources/3d/world_boundary_shape_3d.cpp
Normal 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));
|
||||
}
|
57
scene/resources/3d/world_boundary_shape_3d.h
Normal file
57
scene/resources/3d/world_boundary_shape_3d.h
Normal 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();
|
||||
};
|
Reference in New Issue
Block a user