|
1 | 1 | #include "tetra_mesh_4d.h" |
2 | 2 |
|
| 3 | +#include "../material_4d.h" |
3 | 4 | #include "array_tetra_mesh_4d.h" |
4 | 5 |
|
5 | 6 | #if GDEXTENSION |
6 | | -#include <godot_cpp/classes/mesh.hpp> |
| 7 | +#include <godot_cpp/classes/material.hpp> |
7 | 8 | #include <godot_cpp/classes/standard_material3d.hpp> |
8 | 9 | #include <godot_cpp/classes/surface_tool.hpp> |
9 | 10 | #elif GODOT_MODULE |
10 | | -#include "scene/resources/mesh.h" |
| 11 | +#include "scene/resources/material.h" |
11 | 12 | #include "scene/resources/surface_tool.h" |
12 | 13 | #endif |
13 | 14 |
|
| 15 | +namespace { |
| 16 | +Color vec4_to_color(Vector4 v) { |
| 17 | + return Color(v.x, v.y, v.z, v.w); |
| 18 | +} |
| 19 | +} //namespace |
| 20 | + |
14 | 21 | Ref<ArrayMesh> TetraMesh4D::export_uvw_map_mesh() { |
15 | 22 | const PackedVector3Array uvw_map = get_cell_uvw_map(); |
16 | 23 | Ref<SurfaceTool> surface_tool; |
@@ -47,6 +54,7 @@ Ref<ArrayMesh> TetraMesh4D::export_uvw_map_mesh() { |
47 | 54 | void TetraMesh4D::tetra_mesh_clear_cache() { |
48 | 55 | _edge_positions_cache.clear(); |
49 | 56 | _edge_indices_cache.clear(); |
| 57 | + mark_cross_section_mesh_dirty(); |
50 | 58 | } |
51 | 59 |
|
52 | 60 | void TetraMesh4D::validate_material_for_mesh(const Ref<Material4D> &p_material) { |
@@ -140,6 +148,82 @@ PackedVector4Array TetraMesh4D::get_edge_positions() { |
140 | 148 | return _edge_positions_cache; |
141 | 149 | } |
142 | 150 |
|
| 151 | +void TetraMesh4D::update_cross_section_mesh() { |
| 152 | + ERR_FAIL_NULL(_cross_section_mesh); |
| 153 | + _cross_section_mesh->clear_surfaces(); |
| 154 | + |
| 155 | + Ref<SurfaceTool> surface_tool; |
| 156 | + surface_tool.instantiate(); |
| 157 | + surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); |
| 158 | + surface_tool->set_smooth_group(-1); |
| 159 | + |
| 160 | + PackedVector4Array vertices = get_vertices(); |
| 161 | + PackedInt32Array cell_indices = get_cell_indices(); |
| 162 | + PackedVector3Array cell_uvws = get_cell_uvw_map(); |
| 163 | + PackedVector4Array cell_normals = get_cell_normals(); |
| 164 | + Ref<Material4D> material = get_material(); |
| 165 | + if (material.is_valid()) { |
| 166 | + surface_tool->set_material(material->get_cross_section_material()); |
| 167 | + } |
| 168 | + surface_tool->set_custom_format(0, SurfaceTool::CUSTOM_RGBA_FLOAT); |
| 169 | + surface_tool->set_custom_format(1, SurfaceTool::CUSTOM_RGBA_FLOAT); |
| 170 | + surface_tool->set_custom_format(2, SurfaceTool::CUSTOM_RGBA_FLOAT); |
| 171 | + surface_tool->set_custom_format(3, SurfaceTool::CUSTOM_RGBA_FLOAT); |
| 172 | + for (int i = 0; i < cell_indices.size(); i += 4) { |
| 173 | + // Cramming a bunch of data where it fits. Each cell's cross section can be 0-2 triangles. We create two triangles for each cell |
| 174 | + // with all the info about the cell and figure everything out in the vertex shader after transforms have been applied. |
| 175 | + // As of 4.4.1, available slots are: |
| 176 | + // - Vertex position (3) |
| 177 | + // - Custom 0-3 (4 * 4) |
| 178 | + // - UV1 and UV2 (2 * 2) |
| 179 | + // - Normal (3) |
| 180 | + // - Tangent (3) |
| 181 | + // - Color (4) |
| 182 | + // Slots that don't work: |
| 183 | + // - Bone weights: get truncated, sorted, and normalized automatically |
| 184 | + // - Binormal: available in shader, but computed in SurfaceTool from normal/tangent |
| 185 | + // |
| 186 | + // Some alternative strategies: |
| 187 | + // - ImmediateMesh to compute cross-section on the CPU every frame, but that's likely slower. |
| 188 | + // - Some kind of compute shader or custom render pipeline, but that's not supported on the Compatibility renderer. |
| 189 | + |
| 190 | + //// Shared attrs for both triangles: |
| 191 | + |
| 192 | + // Cell vertex positions: Using custom because there are conveniently four of them and they each take a vector4. |
| 193 | + surface_tool->set_custom(0, vec4_to_color(vertices[cell_indices[i]])); |
| 194 | + surface_tool->set_custom(1, vec4_to_color(vertices[cell_indices[i + 1]])); |
| 195 | + surface_tool->set_custom(2, vec4_to_color(vertices[cell_indices[i + 2]])); |
| 196 | + surface_tool->set_custom(3, vec4_to_color(vertices[cell_indices[i + 3]])); |
| 197 | + |
| 198 | + // UVW texture coords, need 4*3 float slots. Using UV, UV2, Normal, Color, and one vertex.y. |
| 199 | + Vector3 uvw1 = cell_uvws[cell_indices[i]]; |
| 200 | + Vector3 uvw2 = cell_uvws[cell_indices[i + 1]]; |
| 201 | + Vector3 uvw3 = cell_uvws[cell_indices[i + 2]]; |
| 202 | + Vector3 uvw4 = cell_uvws[cell_indices[i + 3]]; |
| 203 | + surface_tool->set_uv(Vector2(uvw1.x, uvw1.y)); |
| 204 | + surface_tool->set_uv2(Vector2(uvw2.x, uvw2.y)); |
| 205 | + surface_tool->set_normal(uvw3); |
| 206 | + surface_tool->set_color(Color(uvw4.x, uvw4.y, uvw4.z, uvw1.z)); |
| 207 | + |
| 208 | + // Not enough slots left for normals. Also interpolating the 4D normals gives weird results, needs more experimentation. |
| 209 | + // Currently flat normals are computed in the vertex shader. |
| 210 | + |
| 211 | + //// Vertices: |
| 212 | + |
| 213 | + // Not storing actual position data in the vertex positions, x is an index, y is UVW data, z is unused. |
| 214 | + surface_tool->add_vertex(Vector3(0.0, uvw2.z, 0.0)); |
| 215 | + surface_tool->add_vertex(Vector3(1.0, uvw2.z, 0.0)); |
| 216 | + surface_tool->add_vertex(Vector3(2.0, uvw2.z, 0.0)); |
| 217 | + |
| 218 | + surface_tool->add_vertex(Vector3(3.0, uvw2.z, 0.0)); |
| 219 | + surface_tool->add_vertex(Vector3(4.0, uvw2.z, 0.0)); |
| 220 | + surface_tool->add_vertex(Vector3(5.0, uvw2.z, 0.0)); |
| 221 | + } |
| 222 | + surface_tool->commit(_cross_section_mesh); |
| 223 | + |
| 224 | + // TODO Second surface for 4D "shadow" effect. |
| 225 | +} |
| 226 | + |
143 | 227 | void TetraMesh4D::_bind_methods() { |
144 | 228 | ClassDB::bind_method(D_METHOD("export_uvw_map_mesh"), &TetraMesh4D::export_uvw_map_mesh); |
145 | 229 | ClassDB::bind_method(D_METHOD("tetra_mesh_clear_cache"), &TetraMesh4D::tetra_mesh_clear_cache); |
|
0 commit comments