feat: godot-engine-source-4.3-stable

This commit is contained in:
Jan van der Weide 2025-01-17 16:36:38 +01:00
parent c59a7dcade
commit 7125d019b5
11149 changed files with 5070401 additions and 0 deletions

View file

@ -0,0 +1,6 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
env.add_source_files(env.scene_sources, "skeleton/*.cpp")

View file

@ -0,0 +1,100 @@
/**************************************************************************/
/* 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 "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;
}
real_t BoxShape3D::get_enclosing_radius() const {
return size.length() / 2;
}
void BoxShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), size / 2);
Shape3D::_update_shape();
}
#ifndef DISABLE_DEPRECATED
bool BoxShape3D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "extents") { // Compatibility with Godot 3.x.
// Convert to `size`, twice as big.
set_size((Vector3)p_value * 2);
return true;
}
return false;
}
bool BoxShape3D::_get(const StringName &p_name, Variant &r_property) const {
if (p_name == "extents") { // Compatibility with Godot 3.x.
// Convert to `extents`, half as big.
r_property = size / 2;
return true;
}
return false;
}
#endif // DISABLE_DEPRECATED
void BoxShape3D::set_size(const Vector3 &p_size) {
ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0 || p_size.z < 0, "BoxShape3D size cannot be negative.");
size = p_size;
_update_shape();
emit_changed();
}
Vector3 BoxShape3D::get_size() const {
return size;
}
void BoxShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxShape3D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &BoxShape3D::get_size);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
}
BoxShape3D::BoxShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_BOX)) {
set_size(Vector3(1, 1, 1));
}

View file

@ -0,0 +1,59 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef BOX_SHAPE_3D_H
#define BOX_SHAPE_3D_H
#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 real_t get_enclosing_radius() const override;
BoxShape3D();
};
#endif // BOX_SHAPE_3D_H

View file

@ -0,0 +1,125 @@
/**************************************************************************/
/* 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 "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.5 - 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;
}
real_t CapsuleShape3D::get_enclosing_radius() const {
return height * 0.5;
}
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, "CapsuleShape3D radius cannot be negative.");
radius = p_radius;
if (radius > height * 0.5) {
height = radius * 2.0;
}
_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, "CapsuleShape3D height cannot be negative.");
height = p_height;
if (radius > height * 0.5) {
radius = height * 0.5;
}
_update_shape();
emit_changed();
}
float CapsuleShape3D::get_height() const {
return height;
}
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);
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_LINKED_PROPERTY("radius", "height");
ADD_LINKED_PROPERTY("height", "radius");
}
CapsuleShape3D::CapsuleShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CAPSULE)) {
_update_shape();
}

View file

@ -0,0 +1,58 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef CAPSULE_SHAPE_3D_H
#define CAPSULE_SHAPE_3D_H
#include "scene/resources/3d/shape_3d.h"
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;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
CapsuleShape3D();
};
#endif // CAPSULE_SHAPE_3D_H

View file

@ -0,0 +1,118 @@
/**************************************************************************/
/* 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 "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;
}
real_t ConcavePolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_faces();
const Vector3 *read = data.ptr();
real_t r = 0.0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
return Math::sqrt(r);
}
void ConcavePolygonShape3D::_update_shape() {
Dictionary d;
d["faces"] = faces;
d["backface_collision"] = backface_collision;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) {
faces = p_faces;
_update_shape();
emit_changed();
}
Vector<Vector3> ConcavePolygonShape3D::get_faces() const {
return faces;
}
void ConcavePolygonShape3D::set_backface_collision_enabled(bool p_enabled) {
backface_collision = p_enabled;
if (!faces.is_empty()) {
_update_shape();
emit_changed();
}
}
bool ConcavePolygonShape3D::is_backface_collision_enabled() const {
return backface_collision;
}
void ConcavePolygonShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape3D::set_faces);
ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape3D::get_faces);
ClassDB::bind_method(D_METHOD("set_backface_collision_enabled", "enabled"), &ConcavePolygonShape3D::set_backface_collision_enabled);
ClassDB::bind_method(D_METHOD("is_backface_collision_enabled"), &ConcavePolygonShape3D::is_backface_collision_enabled);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "backface_collision"), "set_backface_collision_enabled", "is_backface_collision_enabled");
}
ConcavePolygonShape3D::ConcavePolygonShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON)) {
//set_planes(Vector3(1,1,1));
}

View file

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

View file

@ -0,0 +1,90 @@
/**************************************************************************/
/* 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 "servers/physics_server_3d.h"
Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
Vector<Vector3> poly_points = get_points();
if (poly_points.size() > 3) {
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>();
}
real_t ConvexPolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_points();
const Vector3 *read = data.ptr();
real_t r = 0.0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
return Math::sqrt(r);
}
void ConvexPolygonShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), points);
Shape3D::_update_shape();
}
void ConvexPolygonShape3D::set_points(const Vector<Vector3> &p_points) {
points = p_points;
_update_shape();
emit_changed();
}
Vector<Vector3> ConvexPolygonShape3D::get_points() const {
return points;
}
void ConvexPolygonShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_points", "points"), &ConvexPolygonShape3D::set_points);
ClassDB::bind_method(D_METHOD("get_points"), &ConvexPolygonShape3D::get_points);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "points"), "set_points", "get_points");
}
ConvexPolygonShape3D::ConvexPolygonShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON)) {
}

View file

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

View file

@ -0,0 +1,110 @@
/**************************************************************************/
/* 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 "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;
}
real_t CylinderShape3D::get_enclosing_radius() const {
return Vector2(radius, height * 0.5).length();
}
void CylinderShape3D::_update_shape() {
Dictionary d;
d["radius"] = radius;
d["height"] = height;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void CylinderShape3D::set_radius(float p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0, "CylinderShape3D radius cannot be negative.");
radius = p_radius;
_update_shape();
emit_changed();
}
float CylinderShape3D::get_radius() const {
return radius;
}
void CylinderShape3D::set_height(float p_height) {
ERR_FAIL_COND_MSG(p_height < 0, "CylinderShape3D height cannot be negative.");
height = p_height;
_update_shape();
emit_changed();
}
float CylinderShape3D::get_height() const {
return height;
}
void CylinderShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape3D::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape3D::get_height);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
CylinderShape3D::CylinderShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CYLINDER)) {
_update_shape();
}

View file

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

View file

@ -0,0 +1,182 @@
/**************************************************************************/
/* 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() {
shader_mutex.lock();
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 )" VERSION_NAME " " 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;
}
)");
}
shader_mutex.unlock();
}
FogMaterial::FogMaterial() {
set_density(1.0);
set_albedo(Color(1, 1, 1, 1));
set_emission(Color(0, 0, 0, 1));
set_height_falloff(0.0);
set_edge_fade(0.1);
}
FogMaterial::~FogMaterial() {
RS::get_singleton()->material_set_shader(_get_material(), RID());
}

View file

@ -0,0 +1,87 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef FOG_MATERIAL_H
#define FOG_MATERIAL_H
#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();
};
#endif // FOG_MATERIAL_H

View file

@ -0,0 +1,316 @@
/**************************************************************************/
/* 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 "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;
}
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, "0.001,100,0.001,or_greater"), "set_map_width", "get_map_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_depth", "get_map_depth");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data");
}
HeightMapShape3D::HeightMapShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) {
map_data.resize(map_width * map_depth);
real_t *w = map_data.ptrw();
w[0] = 0.0;
w[1] = 0.0;
w[2] = 0.0;
w[3] = 0.0;
_update_shape();
}

View file

@ -0,0 +1,70 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef HEIGHT_MAP_SHAPE_3D_H
#define HEIGHT_MAP_SHAPE_3D_H
#include "scene/resources/3d/shape_3d.h"
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 real_t get_enclosing_radius() const override;
HeightMapShape3D();
};
#endif // HEIGHT_MAP_SHAPE_3D_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,135 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef IMPORTER_MESH_H
#define IMPORTER_MESH_H
#include "core/io/resource.h"
#include "core/templates/local_vector.h"
#include "scene/resources/3d/concave_polygon_shape_3d.h"
#include "scene/resources/3d/convex_polygon_shape_3d.h"
#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h"
#include <cstdint>
// 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;
}
};
void split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals);
static void _split_normals(Array &r_arrays, const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals);
};
Vector<Surface> surfaces;
Vector<String> blend_shapes;
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;
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;
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 generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array);
void create_shadow_mesh();
Ref<ImporterMesh> get_shadow_mesh() const;
Vector<Face3> get_faces() const;
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;
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();
};
#endif // IMPORTER_MESH_H

View file

@ -0,0 +1,356 @@
/**************************************************************************/
/* 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"
#include "box_shape_3d.h"
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 == "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);
} 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 == "shapes") {
r_ret = _get_item_shapes(idx);
} 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::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_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();
}
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;
}
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;
}
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;
}
}
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;
}
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_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);
ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes);
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_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);
ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes);
ClassDB::bind_method(D_METHOD("get_item_preview", "id"), &MeshLibrary::get_item_preview);
ClassDB::bind_method(D_METHOD("remove_item", "id"), &MeshLibrary::remove_item);
ClassDB::bind_method(D_METHOD("find_item_by_name", "name"), &MeshLibrary::find_item_by_name);
ClassDB::bind_method(D_METHOD("clear"), &MeshLibrary::clear);
ClassDB::bind_method(D_METHOD("get_item_list"), &MeshLibrary::get_item_list);
ClassDB::bind_method(D_METHOD("get_last_unused_item_id"), &MeshLibrary::get_last_unused_item_id);
}
MeshLibrary::MeshLibrary() {
}
MeshLibrary::~MeshLibrary() {
}

View file

@ -0,0 +1,106 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef MESH_LIBRARY_H
#define MESH_LIBRARY_H
#include "core/io/resource.h"
#include "core/templates/rb_map.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/resources/mesh.h"
#include "shape_3d.h"
class MeshLibrary : public Resource {
GDCLASS(MeshLibrary, Resource);
RES_BASE_EXTENSION("meshlib");
public:
struct ShapeData {
Ref<Shape3D> shape;
Transform3D local_transform;
};
struct Item {
String name;
Ref<Mesh> mesh;
Transform3D mesh_transform;
Vector<ShapeData> shapes;
Ref<Texture2D> preview;
Ref<NavigationMesh> navigation_mesh;
Transform3D navigation_mesh_transform;
uint32_t navigation_layers = 1;
};
RBMap<int, Item> item_map;
void _set_item_shapes(int p_item, const Array &p_shapes);
Array _get_item_shapes(int p_item) const;
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_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);
void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes);
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;
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;
Vector<ShapeData> get_item_shapes(int p_item) const;
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();
};
#endif // MESH_LIBRARY_H

View file

@ -0,0 +1,373 @@
/**************************************************************************/
/* 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;
}
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;
}
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);
}
}
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();
}
void NavigationMeshSourceGeometryData3D::clear_projected_obstructions() {
RWLockWrite write_lock(geometry_rwlock);
_projected_obstructions.clear();
}
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_valid());
#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);
}
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);
}
void NavigationMeshSourceGeometryData3D::merge(const Ref<NavigationMeshSourceGeometryData3D> &p_other_geometry) {
ERR_FAIL_NULL(p_other_geometry);
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);
}
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);
}
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);
}
}
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;
}
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;
}
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);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_indices", "get_indices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "projected_obstructions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_projected_obstructions", "get_projected_obstructions");
}

View file

@ -0,0 +1,108 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_3D_H
#define NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_3D_H
#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;
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);
NavigationMeshSourceGeometryData3D() {}
~NavigationMeshSourceGeometryData3D() { clear(); }
};
#endif // NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_3D_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,690 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef PRIMITIVE_MESHES_H
#define PRIMITIVE_MESHES_H
#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;
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(){};
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;
CapsuleMesh();
};
/**
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;
BoxMesh();
};
/**
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;
CylinderMesh();
};
/*
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;
PlaneMesh();
};
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;
PrismMesh();
};
/**
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;
SphereMesh();
};
/**
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;
TorusMesh();
};
/**
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(INFINITY, INFINITY);
Vector2 max_p = Vector2(-INFINITY, -INFINITY);
};
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)
#endif // PRIMITIVE_MESHES_H

View file

@ -0,0 +1,92 @@
/**************************************************************************/
/* 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 "servers/physics_server_3d.h"
Vector<Vector3> SeparationRayShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points = {
Vector3(),
Vector3(0, 0, get_length())
};
return points;
}
real_t SeparationRayShape3D::get_enclosing_radius() const {
return length;
}
void SeparationRayShape3D::_update_shape() {
Dictionary d;
d["length"] = length;
d["slide_on_slope"] = slide_on_slope;
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}
void SeparationRayShape3D::set_length(float p_length) {
length = p_length;
_update_shape();
emit_changed();
}
float SeparationRayShape3D::get_length() const {
return length;
}
void SeparationRayShape3D::set_slide_on_slope(bool p_active) {
slide_on_slope = p_active;
_update_shape();
emit_changed();
}
bool SeparationRayShape3D::get_slide_on_slope() const {
return slide_on_slope;
}
void SeparationRayShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_length", "length"), &SeparationRayShape3D::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &SeparationRayShape3D::get_length);
ClassDB::bind_method(D_METHOD("set_slide_on_slope", "active"), &SeparationRayShape3D::set_slide_on_slope);
ClassDB::bind_method(D_METHOD("get_slide_on_slope"), &SeparationRayShape3D::get_slide_on_slope);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_slope"), "set_slide_on_slope", "get_slide_on_slope");
}
SeparationRayShape3D::SeparationRayShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SEPARATION_RAY)) {
/* Code copied from setters to prevent the use of uninitialized variables */
_update_shape();
emit_changed();
}

View file

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

View file

@ -0,0 +1,133 @@
/**************************************************************************/
/* 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 "core/os/os.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);
}
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 = Ref<ArrayMesh>(memnew(ArrayMesh));
if (!lines.is_empty()) {
//make mesh
Vector<Vector3> array;
array.resize(lines.size());
{
Vector3 *w = array.ptrw();
for (int i = 0; i < lines.size(); i++) {
w[i] = lines[i];
}
}
Array arr;
arr.resize(Mesh::ARRAY_MAX);
arr[Mesh::ARRAY_VERTEX] = array;
SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
if (st) {
debug_mesh_cache->surface_set_material(0, st->get_debug_collision_material());
}
}
return debug_mesh_cache;
}
void Shape3D::_update_shape() {
emit_changed();
debug_mesh_cache.unref();
}
void Shape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_solver_bias", "bias"), &Shape3D::set_custom_solver_bias);
ClassDB::bind_method(D_METHOD("get_custom_solver_bias"), &Shape3D::get_custom_solver_bias);
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape3D::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &Shape3D::get_margin);
ClassDB::bind_method(D_METHOD("get_debug_mesh"), &Shape3D::get_debug_mesh);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater,suffix:m"), "set_margin", "get_margin");
}
Shape3D::Shape3D() {
ERR_PRINT("Default constructor must not be called!");
}
Shape3D::Shape3D(RID p_shape) :
shape(p_shape) {}
Shape3D::~Shape3D() {
ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(shape);
}

View file

@ -0,0 +1,76 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef SHAPE_3D_H
#define SHAPE_3D_H
#include "core/io/resource.h"
class ArrayMesh;
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;
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>(); }
/// 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);
Shape3D();
~Shape3D();
};
#endif // SHAPE_3D_H

View file

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

View file

@ -0,0 +1,89 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef SKIN_H
#define SKIN_H
#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();
};
#endif // SKIN_H

View file

@ -0,0 +1,806 @@
/**************************************************************************/
/* 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[2];
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);
}
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);
}
Color ProceduralSkyMaterial::get_sky_horizon_color() const {
return sky_horizon_color;
}
void ProceduralSkyMaterial::set_sky_curve(float p_curve) {
sky_curve = p_curve;
RS::get_singleton()->material_set_param(_get_material(), "sky_curve", 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_energy", 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());
}
}
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", sky_cover_modulate);
}
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);
}
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);
}
Color ProceduralSkyMaterial::get_ground_horizon_color() const {
return ground_horizon_color;
}
void ProceduralSkyMaterial::set_ground_curve(float p_curve) {
ground_curve = p_curve;
RS::get_singleton()->material_set_param(_get_material(), "ground_curve", 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_energy", 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::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;
RS::get_singleton()->material_set_param(_get_material(), "sun_curve", sun_curve);
}
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();
// Only set if shader already compiled
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
}
}
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;
}
RID ProceduralSkyMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
shader_set = true;
}
return _get_material();
}
RID ProceduralSkyMaterial::get_shader_rid() const {
_update_shader();
return shader_cache[int(use_debanding)];
}
void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET("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() {
if (shader_cache[0].is_valid()) {
RS::get_singleton()->free(shader_cache[0]);
RS::get_singleton()->free(shader_cache[1]);
}
}
void ProceduralSkyMaterial::_update_shader() {
shader_mutex.lock();
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = 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[i], vformat(R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " 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 sky_curve : hint_range(0, 1) = 0.15;
uniform float sky_energy = 1.0; // In Lux.
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);
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 ground_curve : hint_range(0, 1) = 0.02;
uniform float ground_energy = 1.0;
uniform float sun_angle_max = 30.0;
uniform float sun_curve : hint_range(0, 1) = 0.15;
uniform float exposure : hint_range(0, 128) = 1.0;
void sky() {
float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));
float c = (1.0 - v_angle / (PI * 0.5));
vec3 sky = mix(sky_horizon_color.rgb, sky_top_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / sky_curve), 0.0, 1.0));
sky *= sky_energy;
if (LIGHT0_ENABLED) {
float sun_angle = acos(dot(LIGHT0_DIRECTION, EYEDIR));
if (sun_angle < LIGHT0_SIZE) {
sky = LIGHT0_COLOR * LIGHT0_ENERGY;
} else if (sun_angle < sun_angle_max) {
float c2 = (sun_angle - LIGHT0_SIZE) / (sun_angle_max - LIGHT0_SIZE);
sky = mix(LIGHT0_COLOR * LIGHT0_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
}
}
if (LIGHT1_ENABLED) {
float sun_angle = acos(dot(LIGHT1_DIRECTION, EYEDIR));
if (sun_angle < LIGHT1_SIZE) {
sky = LIGHT1_COLOR * LIGHT1_ENERGY;
} else if (sun_angle < sun_angle_max) {
float c2 = (sun_angle - LIGHT1_SIZE) / (sun_angle_max - LIGHT1_SIZE);
sky = mix(LIGHT1_COLOR * LIGHT1_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
}
}
if (LIGHT2_ENABLED) {
float sun_angle = acos(dot(LIGHT2_DIRECTION, EYEDIR));
if (sun_angle < LIGHT2_SIZE) {
sky = LIGHT2_COLOR * LIGHT2_ENERGY;
} else if (sun_angle < sun_angle_max) {
float c2 = (sun_angle - LIGHT2_SIZE) / (sun_angle_max - LIGHT2_SIZE);
sky = mix(LIGHT2_COLOR * LIGHT2_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
}
}
if (LIGHT3_ENABLED) {
float sun_angle = acos(dot(LIGHT3_DIRECTION, EYEDIR));
if (sun_angle < LIGHT3_SIZE) {
sky = LIGHT3_COLOR * LIGHT3_ENERGY;
} else if (sun_angle < sun_angle_max) {
float c2 = (sun_angle - LIGHT3_SIZE) / (sun_angle_max - LIGHT3_SIZE);
sky = mix(LIGHT3_COLOR * LIGHT3_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));
}
}
vec4 sky_cover_texture = texture(sky_cover, SKY_COORDS);
sky += (sky_cover_texture.rgb * sky_cover_modulate.rgb) * sky_cover_texture.a * sky_cover_modulate.a * sky_energy;
c = (v_angle - (PI * 0.5)) / (PI * 0.5);
vec3 ground = mix(ground_horizon_color.rgb, ground_bottom_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / ground_curve), 0.0, 1.0));
ground *= ground_energy;
COLOR = mix(ground, sky, step(0.0, EYEDIR.y)) * exposure;
}
)",
i ? "render_mode use_debanding;" : ""));
}
}
shader_mutex.unlock();
}
ProceduralSkyMaterial::ProceduralSkyMaterial() {
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();
// 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();
// Don't compile shaders until first use, then compile both
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(filter)]);
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();
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() {
if (shader_cache[0].is_valid()) {
RS::get_singleton()->free(shader_cache[0]);
RS::get_singleton()->free(shader_cache[1]);
}
}
void PanoramaSkyMaterial::_update_shader() {
shader_mutex.lock();
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = 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[i], vformat(R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " 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;
}
)",
i ? "filter_linear" : "filter_nearest"));
}
}
shader_mutex.unlock();
}
PanoramaSkyMaterial::PanoramaSkyMaterial() {
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();
// Only set if shader already compiled
if (shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
}
}
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());
}
}
Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const {
return night_sky;
}
Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
RID PhysicalSkyMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
shader_set = true;
}
return _get_material();
}
RID PhysicalSkyMaterial::get_shader_rid() const {
_update_shader();
return shader_cache[int(use_debanding)];
}
void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "exposure_value" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
Mutex PhysicalSkyMaterial::shader_mutex;
RID PhysicalSkyMaterial::shader_cache[2];
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() {
if (shader_cache[0].is_valid()) {
RS::get_singleton()->free(shader_cache[0]);
RS::get_singleton()->free(shader_cache[1]);
}
}
void PhysicalSkyMaterial::_update_shader() {
shader_mutex.lock();
if (shader_cache[0].is_null()) {
for (int i = 0; i < 2; i++) {
shader_cache[i] = 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[i], vformat(R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " 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, 1.0 - exp(-((PI * 0.5) - acos(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 = acos(max(0.0, dot(UP, EYEDIR)));
float optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(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;
L0 += texture(night_sky, SKY_COORDS).xyz * extinction;
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.
COLOR = texture(night_sky, SKY_COORDS).xyz;
COLOR *= exposure;
}
}
)",
i ? "render_mode use_debanding;" : ""));
}
}
shader_mutex.unlock();
}
PhysicalSkyMaterial::PhysicalSkyMaterial() {
set_rayleigh_coefficient(2.0);
set_rayleigh_color(Color(0.3, 0.405, 0.6));
set_mie_coefficient(0.005);
set_mie_eccentricity(0.8);
set_mie_color(Color(0.69, 0.729, 0.812));
set_turbidity(10.0);
set_sun_disk_scale(1.0);
set_ground_color(Color(0.1, 0.07, 0.034));
set_energy_multiplier(1.0);
set_use_debanding(true);
}
PhysicalSkyMaterial::~PhysicalSkyMaterial() {
}

View file

@ -0,0 +1,235 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef SKY_MATERIAL_H
#define SKY_MATERIAL_H
#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[2];
static void _update_shader();
mutable bool shader_set = false;
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();
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[2];
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();
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();
};
#endif // SKY_MATERIAL_H

View file

@ -0,0 +1,87 @@
/**************************************************************************/
/* 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 "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;
}
real_t SphereShape3D::get_enclosing_radius() const {
return radius;
}
void SphereShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), radius);
Shape3D::_update_shape();
}
void SphereShape3D::set_radius(float p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0, "SphereShape3D radius cannot be negative.");
radius = p_radius;
_update_shape();
emit_changed();
}
float SphereShape3D::get_radius() const {
return radius;
}
void SphereShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape3D::get_radius);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
}
SphereShape3D::SphereShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SPHERE)) {
set_radius(0.5);
}

View file

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

View file

@ -0,0 +1,183 @@
/**************************************************************************/
/* 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/3d/visible_on_screen_notifier_3d.h"
#include "scene/resources/camera_attributes.h"
#include "scene/resources/environment.h"
#include "servers/navigation_server_3d.h"
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 {
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"));
}
return space;
}
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;
}
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;
}
PhysicsDirectSpaceState3D *World3D::get_direct_space_state() {
return PhysicsServer3D::get_singleton()->space_get_direct_state(get_space());
}
void World3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_space"), &World3D::get_space);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &World3D::get_navigation_map);
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);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state);
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");
ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map");
ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_scenario");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState3D", PROPERTY_USAGE_NONE), "", "get_direct_space_state");
}
World3D::World3D() {
scenario = RenderingServer::get_singleton()->scenario_create();
}
World3D::~World3D() {
ERR_FAIL_NULL(RenderingServer::get_singleton());
ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
RenderingServer::get_singleton()->free(scenario);
if (space.is_valid()) {
PhysicsServer3D::get_singleton()->free(space);
}
if (navigation_map.is_valid()) {
NavigationServer3D::get_singleton()->free(navigation_map);
}
}

View file

@ -0,0 +1,93 @@
/**************************************************************************/
/* 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. */
/**************************************************************************/
#ifndef WORLD_3D_H
#define WORLD_3D_H
#include "core/io/resource.h"
#include "scene/resources/compositor.h"
#include "scene/resources/environment.h"
#include "servers/physics_server_3d.h"
#include "servers/rendering_server.h"
class CameraAttributes;
class Camera3D;
class VisibleOnScreenNotifier3D;
struct SpatialIndexer;
class World3D : public Resource {
GDCLASS(World3D, Resource);
private:
RID scenario;
mutable RID space;
mutable RID navigation_map;
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;
RID get_navigation_map() const;
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; }
PhysicsDirectSpaceState3D *get_direct_space_state();
World3D();
~World3D();
};
#endif // WORLD_3D_H

View file

@ -0,0 +1,89 @@
/**************************************************************************/
/* 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 "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;
}
void WorldBoundaryShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane);
Shape3D::_update_shape();
}
void WorldBoundaryShape3D::set_plane(const Plane &p_plane) {
plane = p_plane;
_update_shape();
emit_changed();
}
const Plane &WorldBoundaryShape3D::get_plane() const {
return plane;
}
void WorldBoundaryShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldBoundaryShape3D::set_plane);
ClassDB::bind_method(D_METHOD("get_plane"), &WorldBoundaryShape3D::get_plane);
ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane", PROPERTY_HINT_NONE, "suffix:m"), "set_plane", "get_plane");
}
WorldBoundaryShape3D::WorldBoundaryShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY)) {
set_plane(Plane(0, 1, 0, 0));
}

View file

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