Skip to content

Commit bc3ef40

Browse files
BattyBovineSplizard
authored andcommitted
Add debug colours and fills to CollisionPolygon3D.
This brings CollisionPolygon3D up to feature parity with its counterpart CollisionShape3D. Closes godotengine#101414. In addition, adding this feature fixes the issue that CollisionPolygon3D would never be rendered in exported builds, even if Visible Collision Shapes is enabled at runtime. Closes godotengine#101413.
1 parent acd3714 commit bc3ef40

5 files changed

+264
-8
lines changed

doc/classes/CollisionPolygon3D.xml

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
<tutorials>
1111
</tutorials>
1212
<members>
13+
<member name="debug_color" type="Color" setter="set_debug_color" getter="get_debug_color" default="Color(0, 0, 0, 0)">
14+
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.
15+
[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.
16+
</member>
17+
<member name="debug_fill" type="bool" setter="set_enable_debug_fill" getter="get_enable_debug_fill" default="true">
18+
If [code]true[/code], when the shape is displayed, it will show a solid fill color in addition to its wireframe.
19+
</member>
1320
<member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
1421
Length that the resulting collision extends in either direction perpendicular to its 2D polygon.
1522
</member>

editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp

+161-8
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,44 @@
3030

3131
#include "collision_polygon_3d_gizmo_plugin.h"
3232

33+
#include "core/math/geometry_2d.h"
3334
#include "scene/3d/physics/collision_polygon_3d.h"
3435

3536
CollisionPolygon3DGizmoPlugin::CollisionPolygon3DGizmoPlugin() {
36-
const Color gizmo_color = SceneTree::get_singleton()->get_debug_collisions_color();
37-
create_material("shape_material", gizmo_color);
38-
const float gizmo_value = gizmo_color.get_v();
39-
const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
40-
create_material("shape_material_disabled", gizmo_color_disabled);
37+
create_collision_material("shape_material", 2.0);
38+
create_collision_material("shape_material_arraymesh", 0.0625);
39+
40+
create_collision_material("shape_material_disabled", 0.0625);
41+
create_collision_material("shape_material_arraymesh_disabled", 0.015625);
42+
}
43+
44+
void CollisionPolygon3DGizmoPlugin::create_collision_material(const String &p_name, float p_alpha) {
45+
Vector<Ref<StandardMaterial3D>> mats;
46+
47+
const Color collision_color(1.0, 1.0, 1.0, p_alpha);
48+
49+
for (int i = 0; i < 4; i++) {
50+
bool instantiated = i < 2;
51+
52+
Ref<StandardMaterial3D> material;
53+
material.instantiate();
54+
55+
Color color = collision_color;
56+
color.a *= instantiated ? 0.25 : 1.0;
57+
58+
material->set_albedo(color);
59+
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
60+
material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
61+
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
62+
material->set_cull_mode(StandardMaterial3D::CULL_BACK);
63+
material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
64+
material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
65+
material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
66+
67+
mats.push_back(material);
68+
}
69+
70+
materials[p_name] = mats;
4171
}
4272

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

5888
p_gizmo->clear();
5989

90+
const Ref<StandardMaterial3D> material =
91+
get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
92+
const Ref<StandardMaterial3D> material_arraymesh =
93+
get_material(!polygon->is_disabled() ? "shape_material_arraymesh" : "shape_material_arraymesh_disabled", p_gizmo);
94+
95+
const Color collision_color = polygon->is_disabled() ? Color(1.0, 1.0, 1.0, 0.75) : polygon->get_debug_color();
96+
6097
Vector<Vector2> points = polygon->get_polygon();
6198
float depth = polygon->get_depth() * 0.5;
6299

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

74-
const Ref<Material> material =
75-
get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
111+
if (polygon->get_debug_fill_enabled()) {
112+
Ref<ArrayMesh> array_mesh;
113+
array_mesh.instantiate();
114+
115+
Vector<Vector3> verts;
116+
Vector<Color> colors;
117+
Vector<int> indices;
118+
119+
// Determine orientation of the 2D polygon's vertices to determine
120+
// which direction to draw outer polygons.
121+
float signed_area = 0.0f;
122+
for (int i = 0; i < points.size(); i++) {
123+
const int j = (i + 1) % points.size();
124+
signed_area += points[i].x * points[j].y - points[j].x * points[i].y;
125+
}
126+
127+
// Generate triangles for the sides of the extruded polygon.
128+
for (int i = 0; i < points.size(); i++) {
129+
verts.push_back(Vector3(points[i].x, points[i].y, depth));
130+
verts.push_back(Vector3(points[i].x, points[i].y, -depth));
131+
132+
colors.push_back(collision_color);
133+
colors.push_back(collision_color);
134+
}
135+
136+
for (int i = 0; i < verts.size(); i += 2) {
137+
const int j = (i + 1) % verts.size();
138+
const int k = (i + 2) % verts.size();
139+
const int l = (i + 3) % verts.size();
140+
141+
indices.push_back(i);
142+
if (signed_area < 0) {
143+
indices.push_back(j);
144+
indices.push_back(k);
145+
} else {
146+
indices.push_back(k);
147+
indices.push_back(j);
148+
}
149+
150+
indices.push_back(j);
151+
if (signed_area < 0) {
152+
indices.push_back(l);
153+
indices.push_back(k);
154+
} else {
155+
indices.push_back(k);
156+
indices.push_back(l);
157+
}
158+
}
159+
160+
Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(polygon->get_polygon());
161+
162+
// Generate triangles for the bottom cap of the extruded polygon.
163+
for (int i = 0; i < decomp.size(); i++) {
164+
Vector<Vector3> cap_verts_bottom;
165+
Vector<Color> cap_colours_bottom;
166+
Vector<int> cap_indices_bottom;
167+
168+
const int index_offset = verts.size();
169+
170+
const Vector<Vector2> &convex = decomp[i];
171+
172+
for (int j = 0; j < convex.size(); j++) {
173+
cap_verts_bottom.push_back(Vector3(convex[j].x, convex[j].y, -depth));
174+
cap_colours_bottom.push_back(collision_color);
175+
}
176+
177+
if (convex.size() >= 3) {
178+
for (int j = 1; j < convex.size(); j++) {
179+
const int k = (j + 1) % convex.size();
180+
181+
cap_indices_bottom.push_back(index_offset + 0);
182+
cap_indices_bottom.push_back(index_offset + j);
183+
cap_indices_bottom.push_back(index_offset + k);
184+
}
185+
}
186+
verts.append_array(cap_verts_bottom);
187+
colors.append_array(cap_colours_bottom);
188+
indices.append_array(cap_indices_bottom);
189+
}
190+
191+
// Generate triangles for the top cap of the extruded polygon.
192+
for (int i = 0; i < decomp.size(); i++) {
193+
Vector<Vector3> cap_verts_top;
194+
Vector<Color> cap_colours_top;
195+
Vector<int> cap_indices_top;
196+
197+
const int index_offset = verts.size();
198+
199+
const Vector<Vector2> &convex = decomp[i];
200+
201+
for (int j = 0; j < convex.size(); j++) {
202+
cap_verts_top.push_back(Vector3(convex[j].x, convex[j].y, depth));
203+
cap_colours_top.push_back(collision_color);
204+
}
205+
206+
if (convex.size() >= 3) {
207+
for (int j = 1; j < convex.size(); j++) {
208+
const int k = (j + 1) % convex.size();
209+
210+
cap_indices_top.push_back(index_offset + k);
211+
cap_indices_top.push_back(index_offset + j);
212+
cap_indices_top.push_back(index_offset + 0);
213+
}
214+
}
215+
verts.append_array(cap_verts_top);
216+
colors.append_array(cap_colours_top);
217+
indices.append_array(cap_indices_top);
218+
}
219+
220+
Array a;
221+
a.resize(Mesh::ARRAY_MAX);
222+
a[RS::ARRAY_VERTEX] = verts;
223+
a[RS::ARRAY_COLOR] = colors;
224+
a[RS::ARRAY_INDEX] = indices;
225+
array_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
226+
227+
p_gizmo->add_mesh(array_mesh, material_arraymesh);
228+
}
76229

77-
p_gizmo->add_lines(lines, material);
230+
p_gizmo->add_lines(lines, material, false, collision_color);
78231
p_gizmo->add_collision_segments(lines);
79232
}

editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.h

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
class CollisionPolygon3DGizmoPlugin : public EditorNode3DGizmoPlugin {
3737
GDCLASS(CollisionPolygon3DGizmoPlugin, EditorNode3DGizmoPlugin);
3838

39+
void create_collision_material(const String &p_name, float p_alpha);
40+
3941
public:
4042
bool has_gizmo(Node3D *p_spatial) override;
4143
String get_gizmo_name() const override;

scene/3d/physics/collision_polygon_3d.cpp

+77
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ void CollisionPolygon3D::_build_polygon() {
7070

7171
convex->set_points(cp);
7272
convex->set_margin(margin);
73+
convex->set_debug_color(debug_color);
74+
convex->set_debug_fill(debug_fill);
7375
collision_object->shape_owner_add_shape(owner_id, convex);
7476
collision_object->shape_owner_set_disabled(owner_id, disabled);
7577
}
@@ -157,6 +159,68 @@ bool CollisionPolygon3D::is_disabled() const {
157159
return disabled;
158160
}
159161

162+
Color CollisionPolygon3D::_get_default_debug_color() const {
163+
const SceneTree *st = SceneTree::get_singleton();
164+
return st ? st->get_debug_collisions_color() : Color(0.0, 0.0, 0.0, 0.0);
165+
}
166+
167+
void CollisionPolygon3D::set_debug_color(const Color &p_color) {
168+
if (debug_color == p_color) {
169+
return;
170+
}
171+
172+
debug_color = p_color;
173+
174+
update_gizmos();
175+
}
176+
177+
Color CollisionPolygon3D::get_debug_color() const {
178+
return debug_color;
179+
}
180+
181+
void CollisionPolygon3D::set_debug_fill_enabled(bool p_enable) {
182+
if (debug_fill == p_enable) {
183+
return;
184+
}
185+
186+
debug_fill = p_enable;
187+
188+
update_gizmos();
189+
}
190+
191+
bool CollisionPolygon3D::get_debug_fill_enabled() const {
192+
return debug_fill;
193+
}
194+
195+
#ifdef DEBUG_ENABLED
196+
197+
bool CollisionPolygon3D::_property_can_revert(const StringName &p_name) const {
198+
if (p_name == "debug_color") {
199+
return true;
200+
}
201+
return false;
202+
}
203+
204+
bool CollisionPolygon3D::_property_get_revert(const StringName &p_name, Variant &r_property) const {
205+
if (p_name == "debug_color") {
206+
r_property = _get_default_debug_color();
207+
return true;
208+
}
209+
return false;
210+
}
211+
212+
void CollisionPolygon3D::_validate_property(PropertyInfo &p_property) const {
213+
if (p_property.name == "debug_color") {
214+
if (debug_color == _get_default_debug_color()) {
215+
p_property.usage = PROPERTY_USAGE_DEFAULT & ~PROPERTY_USAGE_STORAGE;
216+
} else {
217+
p_property.usage = PROPERTY_USAGE_DEFAULT;
218+
}
219+
}
220+
}
221+
222+
#endif // DEBUG_ENABLED
223+
160224
real_t CollisionPolygon3D::get_margin() const {
161225
return margin;
162226
}
@@ -201,6 +265,12 @@ void CollisionPolygon3D::_bind_methods() {
201265
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon3D::set_disabled);
202266
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon3D::is_disabled);
203267

268+
ClassDB::bind_method(D_METHOD("set_debug_color", "color"), &CollisionPolygon3D::set_debug_color);
269+
ClassDB::bind_method(D_METHOD("get_debug_color"), &CollisionPolygon3D::get_debug_color);
270+
271+
ClassDB::bind_method(D_METHOD("set_enable_debug_fill", "enable"), &CollisionPolygon3D::set_debug_fill_enabled);
272+
ClassDB::bind_method(D_METHOD("get_enable_debug_fill"), &CollisionPolygon3D::get_debug_fill_enabled);
273+
204274
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &CollisionPolygon3D::set_margin);
205275
ClassDB::bind_method(D_METHOD("get_margin"), &CollisionPolygon3D::get_margin);
206276

@@ -210,8 +280,15 @@ void CollisionPolygon3D::_bind_methods() {
210280
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
211281
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
212282
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001,suffix:m"), "set_margin", "get_margin");
283+
284+
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_color"), "set_debug_color", "get_debug_color");
285+
// Default value depends on a project setting, override for doc generation purposes.
286+
ADD_PROPERTY_DEFAULT("debug_color", Color(0.0, 0.0, 0.0, 0.0));
287+
288+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_fill"), "set_enable_debug_fill", "get_enable_debug_fill");
213289
}
214290

215291
CollisionPolygon3D::CollisionPolygon3D() {
216292
set_notify_local_transform(true);
293+
debug_color = _get_default_debug_color();
217294
}

scene/3d/physics/collision_polygon_3d.h

+17
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ class CollisionPolygon3D : public Node3D {
4646
uint32_t owner_id = 0;
4747
CollisionObject3D *collision_object = nullptr;
4848

49+
Color debug_color;
50+
bool debug_fill = true;
51+
52+
Color _get_default_debug_color() const;
53+
4954
bool disabled = false;
5055

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

66+
#ifdef DEBUG_ENABLED
67+
bool _property_can_revert(const StringName &p_name) const;
68+
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
69+
void _validate_property(PropertyInfo &p_property) const;
70+
#endif // DEBUG_ENABLED
71+
6172
public:
6273
void set_depth(real_t p_depth);
6374
real_t get_depth() const;
@@ -68,6 +79,12 @@ class CollisionPolygon3D : public Node3D {
6879
void set_disabled(bool p_disabled);
6980
bool is_disabled() const;
7081

82+
void set_debug_color(const Color &p_color);
83+
Color get_debug_color() const;
84+
85+
void set_debug_fill_enabled(bool p_enable);
86+
bool get_debug_fill_enabled() const;
87+
7188
virtual AABB get_item_rect() const;
7289

7390
real_t get_margin() const;

0 commit comments

Comments
 (0)