Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/classes/CollisionPolygon3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
<tutorials>
</tutorials>
<members>
<member name="debug_color" type="Color" setter="set_debug_color" getter="get_debug_color" default="Color(0, 0, 0, 0)">
The collision shape color that is displayed in the editor, or in the running project if [b]Debug &gt; Visible Collision Shapes[/b] is checked at the top of the editor.
[b]Note:[/b] The default value is [member ProjectSettings.debug/shapes/collision/shape_color]. The [code]Color(0, 0, 0, 0)[/code] value documented here is a placeholder, and not the actual default debug color.
</member>
<member name="debug_fill" type="bool" setter="set_enable_debug_fill" getter="get_enable_debug_fill" default="true">
If [code]true[/code], when the shape is displayed, it will show a solid fill color in addition to its wireframe.
</member>
<member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
Length that the resulting collision extends in either direction perpendicular to its 2D polygon.
</member>
Expand Down
169 changes: 161 additions & 8 deletions editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,44 @@

#include "collision_polygon_3d_gizmo_plugin.h"

#include "core/math/geometry_2d.h"
#include "scene/3d/physics/collision_polygon_3d.h"

CollisionPolygon3DGizmoPlugin::CollisionPolygon3DGizmoPlugin() {
const Color gizmo_color = SceneTree::get_singleton()->get_debug_collisions_color();
create_material("shape_material", gizmo_color);
const float gizmo_value = gizmo_color.get_v();
const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
create_material("shape_material_disabled", gizmo_color_disabled);
create_collision_material("shape_material", 2.0);
create_collision_material("shape_material_arraymesh", 0.0625);

create_collision_material("shape_material_disabled", 0.0625);
create_collision_material("shape_material_arraymesh_disabled", 0.015625);
}

void CollisionPolygon3DGizmoPlugin::create_collision_material(const String &p_name, float p_alpha) {
Vector<Ref<StandardMaterial3D>> mats;

const Color collision_color(1.0, 1.0, 1.0, p_alpha);

for (int i = 0; i < 4; i++) {
bool instantiated = i < 2;

Ref<StandardMaterial3D> material;
material.instantiate();

Color color = collision_color;
color.a *= instantiated ? 0.25 : 1.0;

material->set_albedo(color);
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
material->set_cull_mode(StandardMaterial3D::CULL_BACK);
material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);

mats.push_back(material);
}

materials[p_name] = mats;
}

bool CollisionPolygon3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
Expand All @@ -57,6 +87,13 @@ void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {

p_gizmo->clear();

const Ref<StandardMaterial3D> material =
get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
const Ref<StandardMaterial3D> material_arraymesh =
get_material(!polygon->is_disabled() ? "shape_material_arraymesh" : "shape_material_arraymesh_disabled", p_gizmo);

const Color collision_color = polygon->is_disabled() ? Color(1.0, 1.0, 1.0, 0.75) : polygon->get_debug_color();

Vector<Vector2> points = polygon->get_polygon();
float depth = polygon->get_depth() * 0.5;

Expand All @@ -71,9 +108,125 @@ void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
lines.push_back(Vector3(points[i].x, points[i].y, -depth));
}

const Ref<Material> material =
get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
if (polygon->get_debug_fill_enabled()) {
Ref<ArrayMesh> array_mesh;
array_mesh.instantiate();

Vector<Vector3> verts;
Vector<Color> colors;
Vector<int> indices;

// Determine orientation of the 2D polygon's vertices to determine
// which direction to draw outer polygons.
float signed_area = 0.0f;
for (int i = 0; i < points.size(); i++) {
const int j = (i + 1) % points.size();
signed_area += points[i].x * points[j].y - points[j].x * points[i].y;
}

// Generate triangles for the sides of the extruded polygon.
for (int i = 0; i < points.size(); i++) {
verts.push_back(Vector3(points[i].x, points[i].y, depth));
verts.push_back(Vector3(points[i].x, points[i].y, -depth));

colors.push_back(collision_color);
colors.push_back(collision_color);
}

for (int i = 0; i < verts.size(); i += 2) {
const int j = (i + 1) % verts.size();
const int k = (i + 2) % verts.size();
const int l = (i + 3) % verts.size();

indices.push_back(i);
if (signed_area < 0) {
indices.push_back(j);
indices.push_back(k);
} else {
indices.push_back(k);
indices.push_back(j);
}

indices.push_back(j);
if (signed_area < 0) {
indices.push_back(l);
indices.push_back(k);
} else {
indices.push_back(k);
indices.push_back(l);
}
}

Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(polygon->get_polygon());

// Generate triangles for the bottom cap of the extruded polygon.
for (int i = 0; i < decomp.size(); i++) {
Vector<Vector3> cap_verts_bottom;
Vector<Color> cap_colours_bottom;
Vector<int> cap_indices_bottom;

const int index_offset = verts.size();

const Vector<Vector2> &convex = decomp[i];

for (int j = 0; j < convex.size(); j++) {
cap_verts_bottom.push_back(Vector3(convex[j].x, convex[j].y, -depth));
cap_colours_bottom.push_back(collision_color);
}

if (convex.size() >= 3) {
for (int j = 1; j < convex.size(); j++) {
const int k = (j + 1) % convex.size();

cap_indices_bottom.push_back(index_offset + 0);
cap_indices_bottom.push_back(index_offset + j);
cap_indices_bottom.push_back(index_offset + k);
}
}
verts.append_array(cap_verts_bottom);
colors.append_array(cap_colours_bottom);
indices.append_array(cap_indices_bottom);
}

// Generate triangles for the top cap of the extruded polygon.
for (int i = 0; i < decomp.size(); i++) {
Vector<Vector3> cap_verts_top;
Vector<Color> cap_colours_top;
Vector<int> cap_indices_top;

const int index_offset = verts.size();

const Vector<Vector2> &convex = decomp[i];

for (int j = 0; j < convex.size(); j++) {
cap_verts_top.push_back(Vector3(convex[j].x, convex[j].y, depth));
cap_colours_top.push_back(collision_color);
}

if (convex.size() >= 3) {
for (int j = 1; j < convex.size(); j++) {
const int k = (j + 1) % convex.size();

cap_indices_top.push_back(index_offset + k);
cap_indices_top.push_back(index_offset + j);
cap_indices_top.push_back(index_offset + 0);
}
}
verts.append_array(cap_verts_top);
colors.append_array(cap_colours_top);
indices.append_array(cap_indices_top);
}

Array a;
a.resize(Mesh::ARRAY_MAX);
a[RS::ARRAY_VERTEX] = verts;
a[RS::ARRAY_COLOR] = colors;
a[RS::ARRAY_INDEX] = indices;
array_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);

p_gizmo->add_mesh(array_mesh, material_arraymesh);
}

p_gizmo->add_lines(lines, material);
p_gizmo->add_lines(lines, material, false, collision_color);
p_gizmo->add_collision_segments(lines);
}
2 changes: 2 additions & 0 deletions editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
class CollisionPolygon3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CollisionPolygon3DGizmoPlugin, EditorNode3DGizmoPlugin);

void create_collision_material(const String &p_name, float p_alpha);

public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
Expand Down
77 changes: 77 additions & 0 deletions scene/3d/physics/collision_polygon_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ void CollisionPolygon3D::_build_polygon() {

convex->set_points(cp);
convex->set_margin(margin);
convex->set_debug_color(debug_color);
convex->set_debug_fill(debug_fill);
collision_object->shape_owner_add_shape(owner_id, convex);
collision_object->shape_owner_set_disabled(owner_id, disabled);
}
Expand Down Expand Up @@ -157,6 +159,68 @@ bool CollisionPolygon3D::is_disabled() const {
return disabled;
}

Color CollisionPolygon3D::_get_default_debug_color() const {
const SceneTree *st = SceneTree::get_singleton();
return st ? st->get_debug_collisions_color() : Color(0.0, 0.0, 0.0, 0.0);
}

void CollisionPolygon3D::set_debug_color(const Color &p_color) {
if (debug_color == p_color) {
return;
}

debug_color = p_color;

update_gizmos();
}

Color CollisionPolygon3D::get_debug_color() const {
return debug_color;
}

void CollisionPolygon3D::set_debug_fill_enabled(bool p_enable) {
if (debug_fill == p_enable) {
return;
}

debug_fill = p_enable;

update_gizmos();
}

bool CollisionPolygon3D::get_debug_fill_enabled() const {
return debug_fill;
}

#ifdef DEBUG_ENABLED

bool CollisionPolygon3D::_property_can_revert(const StringName &p_name) const {
if (p_name == "debug_color") {
return true;
}
return false;
}

bool CollisionPolygon3D::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (p_name == "debug_color") {
r_property = _get_default_debug_color();
return true;
}
return false;
}

void CollisionPolygon3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "debug_color") {
if (debug_color == _get_default_debug_color()) {
p_property.usage = PROPERTY_USAGE_DEFAULT & ~PROPERTY_USAGE_STORAGE;
} else {
p_property.usage = PROPERTY_USAGE_DEFAULT;
}
}
}

#endif // DEBUG_ENABLED

real_t CollisionPolygon3D::get_margin() const {
return margin;
}
Expand Down Expand Up @@ -201,6 +265,12 @@ void CollisionPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon3D::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon3D::is_disabled);

ClassDB::bind_method(D_METHOD("set_debug_color", "color"), &CollisionPolygon3D::set_debug_color);
ClassDB::bind_method(D_METHOD("get_debug_color"), &CollisionPolygon3D::get_debug_color);

ClassDB::bind_method(D_METHOD("set_enable_debug_fill", "enable"), &CollisionPolygon3D::set_debug_fill_enabled);
ClassDB::bind_method(D_METHOD("get_enable_debug_fill"), &CollisionPolygon3D::get_debug_fill_enabled);

ClassDB::bind_method(D_METHOD("set_margin", "margin"), &CollisionPolygon3D::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &CollisionPolygon3D::get_margin);

Expand All @@ -210,8 +280,15 @@ void CollisionPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001,suffix:m"), "set_margin", "get_margin");

ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_color"), "set_debug_color", "get_debug_color");
// Default value depends on a project setting, override for doc generation purposes.
ADD_PROPERTY_DEFAULT("debug_color", Color(0.0, 0.0, 0.0, 0.0));

ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_fill"), "set_enable_debug_fill", "get_enable_debug_fill");
}

CollisionPolygon3D::CollisionPolygon3D() {
set_notify_local_transform(true);
debug_color = _get_default_debug_color();
}
17 changes: 17 additions & 0 deletions scene/3d/physics/collision_polygon_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ class CollisionPolygon3D : public Node3D {
uint32_t owner_id = 0;
CollisionObject3D *collision_object = nullptr;

Color debug_color;
bool debug_fill = true;

Color _get_default_debug_color() const;

bool disabled = false;

void _build_polygon();
Expand All @@ -58,6 +63,12 @@ class CollisionPolygon3D : public Node3D {
void _notification(int p_what);
static void _bind_methods();

#ifdef DEBUG_ENABLED
bool _property_can_revert(const StringName &p_name) const;
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
void _validate_property(PropertyInfo &p_property) const;
#endif // DEBUG_ENABLED

public:
void set_depth(real_t p_depth);
real_t get_depth() const;
Expand All @@ -68,6 +79,12 @@ class CollisionPolygon3D : public Node3D {
void set_disabled(bool p_disabled);
bool is_disabled() const;

void set_debug_color(const Color &p_color);
Color get_debug_color() const;

void set_debug_fill_enabled(bool p_enable);
bool get_debug_fill_enabled() const;

virtual AABB get_item_rect() const;

real_t get_margin() const;
Expand Down