Skip to content

Commit 5a34a61

Browse files
authored
Merge pull request #8 from HenryWConklin/crossection
Cross-section rendering
2 parents b79abb3 + b354ec8 commit 5a34a61

17 files changed

+539
-2
lines changed

addons/4d/SConstruct

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ env.Append(
2525
"../../physics/shapes",
2626
"../../render",
2727
"../../render/wireframe_canvas",
28+
"../../render/cross_section"
2829
]
2930
)
3031

@@ -49,8 +50,10 @@ sources = (
4950
+ Glob("../../physics/shapes/*.cpp")
5051
+ Glob("../../render/*.cpp")
5152
+ Glob("../../render/wireframe_canvas/*.cpp")
53+
+ Glob("../../render/cross_section/*.cpp")
5254
)
5355

56+
5457
env.Append(CPPDEFINES=["GDEXTENSION"])
5558

5659
if env["target"] == "editor":
@@ -132,6 +135,8 @@ env["BUILDERS"]["GLSL_HEADER"] = Builder(
132135
suffix="glsl.gen.h",
133136
)
134137

138+
env.GLSL_HEADER("../../render/cross_section/cross_section_shader.glsl")
139+
135140
target_file_path = "../../editor/icons/editor_4d_icons.gen.h"
136141
icon_sources = Glob("icons/4D.svg") + Glob("icons/Node4D.svg")
137142
header_builders.make_svg_icons_action([target_file_path], icon_sources, env)

addons/4d/doc_classes/Material4D.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
[b]Note:[/b] When making materials, use the high-level properties from the derived classes instead, such as [member WireMaterial4D.albedo_source] or [member TetraMaterial4D.albedo_source].
4545
</description>
4646
</method>
47+
<method name="get_cross_section_material">
48+
<return type="ShaderMaterial" />
49+
<description>
50+
Returns a 3D material to be used by the cross-section renderer. The returned material is automatically updated to match the properties of this material.
51+
</description>
52+
</method>
4753
<method name="is_default_material" qualifiers="const">
4854
<return type="bool" />
4955
<description>

addons/4d/doc_classes/Mesh4D.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
Callback method that should return the vertices of a mesh. Do not call this method. This can be overridden by derived classes when creating a custom mesh type in GDScript or another scripting language. See [method get_vertices] for details of the returned data.
2828
</description>
2929
</method>
30+
<method name="_update_cross_section_mesh" qualifiers="virtual">
31+
<return type="void" />
32+
<description>
33+
Updates the 3D mesh this mesh uses for cross-section rendering. Can be called to force the cross-section mesh to be updated, but typically should only be called internally. Subclasses can override this, but most cases should be covered by the default implementation.
34+
</description>
35+
</method>
3036
<method name="_validate_material_for_mesh" qualifiers="virtual">
3137
<return type="void" />
3238
<param index="0" name="material" type="Material4D" />
@@ -48,6 +54,12 @@
4854
[b]Note[/b]: This only looks at edge indices. It does not remove duplicate vertices, nor does it have access to the vertices array.
4955
</description>
5056
</method>
57+
<method name="get_cross_section_mesh">
58+
<return type="ArrayMesh" />
59+
<description>
60+
Returns a 3D mesh that can be used to render 3D cross-sections of this mesh in the cross-section renderer. This mesh will only render properly with the cross-section material from [method Material4D.get_cross_section_material].
61+
</description>
62+
</method>
5163
<method name="get_edge_indices">
5264
<return type="PackedInt32Array" />
5365
<description>
@@ -82,6 +94,12 @@
8294
If a mesh has valid data, the result of the validation will be cached until the mesh data changes, so this method may be called multiple times without performance concerns. This also means this method should be called after generating a mesh. This especially useful when generating a mesh on a thread; calling this on the thread will avoid stalling the main thread with mesh validation during rendering.
8395
</description>
8496
</method>
97+
<method name="mark_cross_section_mesh_dirty">
98+
<return type="void" />
99+
<description>
100+
Marks the cross-section mesh as dirty, meaning it needs to be updated. Must be called by subclasses whenever the underlying 4D mesh data changes.
101+
</description>
102+
</method>
85103
<method name="reset_mesh_data_validation">
86104
<return type="void" />
87105
<description>
@@ -101,6 +119,12 @@
101119
Converts this Mesh4D to a [WireMesh4D]. This method will use the best conversion available. For example, a [BoxTetraMesh4D] will be converted to a [BoxWireMesh4D]. If no specialized conversion is available, the method will return an [ArrayWireMesh4D]. See [method to_array_wire_mesh] for more details.
102120
</description>
103121
</method>
122+
<method name="update_cross_section_mesh">
123+
<return type="void" />
124+
<description>
125+
Updates the 3D mesh this mesh uses for cross-section rendering. Can be called to force the cross-section mesh to be updated, but typically should only be called internally.
126+
</description>
127+
</method>
104128
<method name="validate_material_for_mesh">
105129
<return type="void" />
106130
<param index="0" name="material" type="Material4D" />

addons/4d/doc_classes/TetraMaterial4D.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
<member name="albedo_source" type="int" setter="set_albedo_source" getter="get_albedo_source" enum="TetraMaterial4D.TetraColorSource" default="0">
2020
The albedo source of the material, an enum specific to tetrahedral meshes. Can be a single color, per-vertex, per-cell, per-cell UVW coordinates, 4D texture, or a combination of single color and the other color sources.
2121
</member>
22+
<member name="texture" type="Texture3D" setter="set_texture" getter="get_texture">
23+
The albedo texture of the material as a Texture3D. Used by the cross-section renderer. Used when albedo_source is [constant TETRA_COLOR_SOURCE_CELL_UVW_ONLY] or [constant TETRA_COLOR_SOURCE_CELL_UVW_AND_SINGLE].
24+
</member>
2225
</members>
2326
<constants>
2427
<constant name="TETRA_COLOR_SOURCE_SINGLE_COLOR" value="0" enum="TetraColorSource">

model/material_4d.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ Material4D::ColorSourceFlags Material4D::get_albedo_source_flags() const {
112112

113113
void Material4D::set_albedo_source_flags(const ColorSourceFlags p_albedo_source_flags) {
114114
_albedo_source_flags = p_albedo_source_flags;
115+
update_cross_section_material();
115116
}
116117

117118
Color Material4D::get_albedo_color() const {
@@ -120,6 +121,7 @@ Color Material4D::get_albedo_color() const {
120121

121122
void Material4D::set_albedo_color(const Color &p_albedo_color) {
122123
_albedo_color = p_albedo_color;
124+
update_cross_section_material();
123125
}
124126

125127
PackedColorArray Material4D::get_albedo_color_array() const {
@@ -128,10 +130,12 @@ PackedColorArray Material4D::get_albedo_color_array() const {
128130

129131
void Material4D::set_albedo_color_array(const PackedColorArray &p_albedo_color_array) {
130132
_albedo_color_array = p_albedo_color_array;
133+
update_cross_section_material();
131134
}
132135

133136
void Material4D::append_albedo_color(const Color &p_albedo_color) {
134137
_albedo_color_array.push_back(p_albedo_color);
138+
update_cross_section_material();
135139
}
136140

137141
void Material4D::resize_albedo_color_array(const int64_t p_size, const Color &p_fill_color) {
@@ -140,6 +144,18 @@ void Material4D::resize_albedo_color_array(const int64_t p_size, const Color &p_
140144
for (int64_t i = existing_size; i < p_size; i++) {
141145
_albedo_color_array.set(i, p_fill_color);
142146
}
147+
update_cross_section_material();
148+
}
149+
150+
Ref<ShaderMaterial> Material4D::get_cross_section_material() {
151+
if (_cross_section_material.is_null()) {
152+
_cross_section_material.instantiate();
153+
update_cross_section_material();
154+
}
155+
return _cross_section_material;
156+
}
157+
158+
void Material4D::update_cross_section_material() {
143159
}
144160

145161
void Material4D::_bind_methods() {
@@ -158,6 +174,8 @@ void Material4D::_bind_methods() {
158174
ClassDB::bind_method(D_METHOD("append_albedo_color", "albedo_color"), &Material4D::append_albedo_color);
159175
ClassDB::bind_method(D_METHOD("resize_albedo_color_array", "size", "fill_color"), &Material4D::resize_albedo_color_array, DEFVAL(Color(1, 1, 1, 1)));
160176

177+
ClassDB::bind_method(D_METHOD("get_cross_section_material"), &Material4D::get_cross_section_material);
178+
161179
BIND_ENUM_CONSTANT(COLOR_SOURCE_FLAG_SINGLE_COLOR);
162180
BIND_ENUM_CONSTANT(COLOR_SOURCE_FLAG_PER_VERT);
163181
BIND_ENUM_CONSTANT(COLOR_SOURCE_FLAG_PER_EDGE);

model/material_4d.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
#if GDEXTENSION
66
#include <godot_cpp/classes/resource.hpp>
7+
#include <godot_cpp/classes/shader_material.hpp>
78
#include <godot_cpp/core/gdvirtual.gen.inc>
89
#elif GODOT_MODULE
910
#include "core/io/resource.h"
11+
#include "scene/resources/material.h"
1012
#endif
1113

1214
class Mesh4D;
@@ -44,6 +46,10 @@ class Material4D : public Resource {
4446
PackedColorArray _albedo_color_array;
4547
Color _albedo_color = Color(1, 1, 1, 1);
4648
ColorSourceFlags _albedo_source_flags = COLOR_SOURCE_FLAG_SINGLE_COLOR;
49+
Ref<ShaderMaterial> _cross_section_material;
50+
51+
// Update _cross_section_material to match current settings on the material, skip if _cross_section_material is null.
52+
virtual void update_cross_section_material();
4753

4854
public:
4955
virtual Color get_albedo_color_of_edge(const int64_t p_edge_index, const Ref<Mesh4D> &p_for_mesh);
@@ -60,6 +66,8 @@ class Material4D : public Resource {
6066
void set_albedo_color_array(const PackedColorArray &p_albedo_color_array);
6167
void append_albedo_color(const Color &p_albedo_color);
6268
void resize_albedo_color_array(const int64_t p_size, const Color &p_fill_color = Color(1, 1, 1, 1));
69+
70+
Ref<ShaderMaterial> get_cross_section_material();
6371
};
6472

6573
VARIANT_ENUM_CAST(Material4D::ColorSourceFlags);

model/mesh_4d.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ bool Mesh4D::validate_mesh_data() {
5858
return ret;
5959
}
6060

61+
void Mesh4D::update_cross_section_mesh() {
62+
GDVIRTUAL_CALL(_update_cross_section_mesh);
63+
}
64+
6165
void Mesh4D::validate_material_for_mesh(const Ref<Material4D> &p_material) {
6266
GDVIRTUAL_CALL(_validate_material_for_mesh, p_material);
6367
const Material4D::ColorSourceFlags albedo_source_flags = p_material->get_albedo_source_flags();
@@ -93,6 +97,15 @@ Ref<WireMesh4D> Mesh4D::to_wire_mesh() {
9397
return to_array_wire_mesh();
9498
}
9599

100+
Ref<ArrayMesh> Mesh4D::get_cross_section_mesh() {
101+
if (_is_cross_section_mesh_dirty || _cross_section_mesh.is_null()) {
102+
_cross_section_mesh.instantiate();
103+
update_cross_section_mesh();
104+
_is_cross_section_mesh_dirty = false;
105+
}
106+
return _cross_section_mesh;
107+
}
108+
96109
Ref<Material4D> Mesh4D::get_material() const {
97110
return _material;
98111
}
@@ -126,9 +139,12 @@ void Mesh4D::_bind_methods() {
126139
ClassDB::bind_method(D_METHOD("is_mesh_data_valid"), &Mesh4D::is_mesh_data_valid);
127140
ClassDB::bind_method(D_METHOD("reset_mesh_data_validation"), &Mesh4D::reset_mesh_data_validation);
128141
ClassDB::bind_method(D_METHOD("validate_material_for_mesh", "material"), &Mesh4D::validate_material_for_mesh);
142+
ClassDB::bind_method(D_METHOD("mark_cross_section_mesh_dirty"), &Mesh4D::mark_cross_section_mesh_dirty);
143+
ClassDB::bind_method(D_METHOD("update_cross_section_mesh"), &Mesh4D::update_cross_section_mesh);
129144

130145
ClassDB::bind_method(D_METHOD("to_array_wire_mesh"), &Mesh4D::to_array_wire_mesh);
131146
ClassDB::bind_method(D_METHOD("to_wire_mesh"), &Mesh4D::to_wire_mesh);
147+
ClassDB::bind_method(D_METHOD("get_cross_section_mesh"), &Mesh4D::get_cross_section_mesh);
132148

133149
ClassDB::bind_method(D_METHOD("get_material"), &Mesh4D::get_material);
134150
ClassDB::bind_method(D_METHOD("set_material", "material"), &Mesh4D::set_material);
@@ -143,4 +159,5 @@ void Mesh4D::_bind_methods() {
143159
GDVIRTUAL_BIND(_get_vertices);
144160
GDVIRTUAL_BIND(_validate_material_for_mesh, "material");
145161
GDVIRTUAL_BIND(_validate_mesh_data);
162+
GDVIRTUAL_BIND(_update_cross_section_mesh);
146163
}

model/mesh_4d.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
#include "material_4d.h"
44

5+
#if GDEXTENSION
6+
#include <godot_cpp/classes/array_mesh.hpp>
7+
#elif GODOT_MODULE
8+
#include "scene/resources/mesh.h"
9+
#endif
10+
511
class ArrayWireMesh4D;
612
class WireMesh4D;
713

@@ -10,10 +16,19 @@ class Mesh4D : public Resource {
1016

1117
Ref<Material4D> _material;
1218
bool _is_mesh_data_valid = false;
19+
bool _is_cross_section_mesh_dirty = true;
1320

1421
protected:
22+
Ref<ArrayMesh> _cross_section_mesh;
23+
1524
static void _bind_methods();
1625
virtual bool validate_mesh_data();
26+
// Call when the mesh is modified to indicate that
27+
// the 3D mesh used for cross-section rendering needs to be updated.
28+
void mark_cross_section_mesh_dirty() { _is_cross_section_mesh_dirty = true; };
29+
// Called when the cross-section mesh is requested and the cross-section mesh has been marked dirty.
30+
// Update the mesh referenced by _cross_section_mesh to match the current state of the mesh.
31+
virtual void update_cross_section_mesh();
1732

1833
public:
1934
static PackedInt32Array deduplicate_edge_indices(const PackedInt32Array &p_items);
@@ -25,6 +40,8 @@ class Mesh4D : public Resource {
2540

2641
Ref<ArrayWireMesh4D> to_array_wire_mesh();
2742
virtual Ref<WireMesh4D> to_wire_mesh();
43+
// Returns a reference to the mesh used for cross-section rendering.
44+
Ref<ArrayMesh> get_cross_section_mesh();
2845

2946
Ref<Material4D> get_material() const;
3047
void set_material(const Ref<Material4D> &p_material);
@@ -37,5 +54,6 @@ class Mesh4D : public Resource {
3754
GDVIRTUAL0R(PackedVector4Array, _get_edge_positions);
3855
GDVIRTUAL0R(PackedVector4Array, _get_vertices);
3956
GDVIRTUAL0R(bool, _validate_mesh_data);
57+
GDVIRTUAL0(_update_cross_section_mesh);
4058
GDVIRTUAL1(_validate_material_for_mesh, const Ref<Material4D> &);
4159
};

model/tetra/tetra_material_4d.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "tetra_material_4d.h"
22

3+
#include "../../render/cross_section/cross_section_shader.glsl.gen.h"
34
#include "tetra_mesh_4d.h"
45

56
Material4D::ColorSourceFlags TetraMaterial4D::_tetra_source_to_flags(const TetraColorSource p_tetra_source) {
@@ -122,6 +123,52 @@ void TetraMaterial4D::set_albedo_source(const TetraColorSource p_albedo_source)
122123
_albedo_source = p_albedo_source;
123124
_albedo_source_flags = _tetra_source_to_flags(_albedo_source);
124125
notify_property_list_changed();
126+
update_cross_section_material();
127+
}
128+
129+
Ref<Texture3D> TetraMaterial4D::get_texture() const {
130+
return _texture;
131+
}
132+
133+
void TetraMaterial4D::set_texture(const Ref<Texture3D> &p_texture) {
134+
_texture = p_texture;
135+
update_cross_section_material();
136+
}
137+
138+
void TetraMaterial4D::update_cross_section_material() {
139+
if (_cross_section_material.is_null()) {
140+
return;
141+
}
142+
if (_cross_section_material->get_shader().is_null()) {
143+
// TODO this re-compiles the shader for every material, should cache the Shader object somewhere.
144+
Ref<Shader> cross_section_shader;
145+
cross_section_shader.instantiate();
146+
cross_section_shader->set_code(cross_section_shader_shader_glsl);
147+
_cross_section_material->set_shader(cross_section_shader);
148+
}
149+
Color albedo;
150+
Variant texture;
151+
switch (_albedo_source) {
152+
case TETRA_COLOR_SOURCE_SINGLE_COLOR:
153+
albedo = _albedo_color;
154+
// Setting to a Nil variant resets to the default texture, which is white.
155+
texture = Variant();
156+
break;
157+
case TETRA_COLOR_SOURCE_CELL_UVW_ONLY:
158+
albedo = Color(1.0, 1.0, 1.0);
159+
texture = _texture;
160+
break;
161+
case TETRA_COLOR_SOURCE_CELL_UVW_AND_SINGLE:
162+
albedo = _albedo_color;
163+
texture = _texture;
164+
break;
165+
default:
166+
albedo = Color(1.0, 1.0, 1.0);
167+
texture = Variant();
168+
break;
169+
}
170+
_cross_section_material->set_shader_parameter("albedo", albedo);
171+
_cross_section_material->set_shader_parameter("albedo_texture", texture);
125172
}
126173

127174
void TetraMaterial4D::_get_property_list(List<PropertyInfo> *p_list) const {
@@ -142,11 +189,14 @@ TetraMaterial4D::TetraMaterial4D() {
142189
void TetraMaterial4D::_bind_methods() {
143190
ClassDB::bind_method(D_METHOD("get_albedo_source"), &TetraMaterial4D::get_albedo_source);
144191
ClassDB::bind_method(D_METHOD("set_albedo_source", "albedo_source"), &TetraMaterial4D::set_albedo_source);
192+
ClassDB::bind_method(D_METHOD("get_texture"), &TetraMaterial4D::get_texture);
193+
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TetraMaterial4D::set_texture);
145194

146195
//ADD_GROUP("Albedo", "albedo_");
147196
ADD_PROPERTY(PropertyInfo(Variant::INT, "albedo_source", PROPERTY_HINT_ENUM, "Single Color,Per Vertex Only,Per Cell Only,Cell UVW Only,Texture4D Only,Per Vertex and Single Color,Per Cell and Single Color,Cell UVW and Single Color,Texture4D and Single Color"), "set_albedo_source", "get_albedo_source");
148197
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo_color"), "set_albedo_color", "get_albedo_color");
149198
ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "albedo_color_array"), "set_albedo_color_array", "get_albedo_color_array");
199+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
150200

151201
BIND_ENUM_CONSTANT(TETRA_COLOR_SOURCE_SINGLE_COLOR);
152202
BIND_ENUM_CONSTANT(TETRA_COLOR_SOURCE_PER_VERT_ONLY);

0 commit comments

Comments
 (0)