From e279537708fb511abf1d8f65325c145916a10918 Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 8 Feb 2026 07:21:29 +0100 Subject: feat(3d): Implement Mesh Wireframe rendering for Visual Debug --- src/3d/renderer.cc | 14 +++++++++++--- src/3d/visual_debug.cc | 26 ++++++++++++++++++++++++++ src/3d/visual_debug.h | 3 +++ src/tests/test_mesh.cc | 26 ++++++++++++++++++++++---- 4 files changed, 62 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc index eea3ff0..6e8f38a 100644 --- a/src/3d/renderer.cc +++ b/src/3d/renderer.cc @@ -306,11 +306,19 @@ void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene, vec3 extent = obj.local_extent; if (obj.type == ObjectType::TORUS) { extent = vec3(1.5f, 0.5f, 1.5f); - } else if (obj.type != ObjectType::MESH) { + } else if (obj.type == ObjectType::MESH) { + MeshAsset mesh = GetMeshAsset(obj.mesh_asset_id); + if (mesh.num_indices > 0) { + visual_debug_.add_mesh_wireframe(obj.get_model_matrix(), mesh.num_vertices, mesh.vertices, mesh.num_indices, mesh.indices, vec3(0.0f, 1.0f, 1.0f)); // Cyan wireframe + } + } else { extent = vec3(1.0f, 1.0f, 1.0f); } - visual_debug_.add_box(obj.get_model_matrix(), extent, - vec3(1.0f, 1.0f, 0.0f)); // Yellow boxes + + if (obj.type != ObjectType::MESH) { + visual_debug_.add_box(obj.get_model_matrix(), extent, + vec3(1.0f, 1.0f, 0.0f)); // Yellow boxes + } } // Calculate ViewProj matrix for the debug renderer diff --git a/src/3d/visual_debug.cc b/src/3d/visual_debug.cc index 3f5778a..78c751b 100644 --- a/src/3d/visual_debug.cc +++ b/src/3d/visual_debug.cc @@ -225,6 +225,32 @@ void VisualDebug::add_mesh_normals(const mat4& transform, uint32_t num_vertices, } } +void VisualDebug::add_mesh_wireframe(const mat4& transform, uint32_t num_vertices, + const MeshVertex* vertices, uint32_t num_indices, + const uint32_t* indices, const vec3& color) { + if (!vertices || !indices || num_indices == 0) + return; + + for (uint32_t i = 0; i < num_indices; i += 3) { + if (i + 2 >= num_indices) break; + + uint32_t idx0 = indices[i]; + uint32_t idx1 = indices[i + 1]; + uint32_t idx2 = indices[i + 2]; + + if (idx0 >= num_vertices || idx1 >= num_vertices || idx2 >= num_vertices) + continue; + + vec4 p0_world = transform * vec4(vertices[idx0].p[0], vertices[idx0].p[1], vertices[idx0].p[2], 1.0f); + vec4 p1_world = transform * vec4(vertices[idx1].p[0], vertices[idx1].p[1], vertices[idx1].p[2], 1.0f); + vec4 p2_world = transform * vec4(vertices[idx2].p[0], vertices[idx2].p[1], vertices[idx2].p[2], 1.0f); + + add_line(p0_world.xyz(), p1_world.xyz(), color); + add_line(p1_world.xyz(), p2_world.xyz(), color); + add_line(p2_world.xyz(), p0_world.xyz(), color); + } +} + void VisualDebug::add_line(const vec3& start, const vec3& end, const vec3& color) { lines_.push_back({start, end, color}); } diff --git a/src/3d/visual_debug.h b/src/3d/visual_debug.h index 7f1aa8b..c8069e1 100644 --- a/src/3d/visual_debug.h +++ b/src/3d/visual_debug.h @@ -30,6 +30,9 @@ class VisualDebug { void add_aabb(const vec3& min, const vec3& max, const vec3& color); void add_mesh_normals(const mat4& transform, uint32_t num_vertices, const MeshVertex* vertices); + void add_mesh_wireframe(const mat4& transform, uint32_t num_vertices, + const MeshVertex* vertices, uint32_t num_indices, + const uint32_t* indices, const vec3& color); void add_line(const vec3& start, const vec3& end, const vec3& color); void add_cross(const vec3& center, float size, const vec3& color); diff --git a/src/tests/test_mesh.cc b/src/tests/test_mesh.cc index 7f898c4..992471a 100644 --- a/src/tests/test_mesh.cc +++ b/src/tests/test_mesh.cc @@ -242,8 +242,16 @@ bool load_obj_and_create_buffers(const char* path, Object3D& out_obj) { g_mesh_gpu_data.vertex_buffer = gpu_create_buffer(g_device, final_vertices.size() * sizeof(MeshVertex), WGPUBufferUsage_Vertex | WGPUBufferUsage_CopyDst, final_vertices.data()).buffer; g_mesh_gpu_data.index_buffer = gpu_create_buffer(g_device, final_indices.size() * sizeof(uint32_t), WGPUBufferUsage_Index | WGPUBufferUsage_CopyDst, final_indices.data()).buffer; + struct MeshData { + std::vector vertices; + std::vector indices; + }; + MeshData* mesh_data = new MeshData(); + mesh_data->vertices = final_vertices; + mesh_data->indices = final_indices; + out_obj.type = ObjectType::MESH; - out_obj.user_data = new std::vector(final_vertices); + out_obj.user_data = mesh_data; // This test doesn't use the asset system, so we override the renderer's internal cache lookup // by manually setting the buffers on the renderer object. This is a HACK for this specific tool. @@ -314,8 +322,14 @@ int main(int argc, char** argv) { #if !defined(STRIP_ALL) if (debug_mode) { - auto* vertices = (std::vector*)g_scene.objects[1].user_data; - g_renderer.GetVisualDebug().add_mesh_normals(g_scene.objects[1].get_model_matrix(), (uint32_t)vertices->size(), vertices->data()); + struct MeshData { + std::vector vertices; + std::vector indices; + }; + auto* data = (MeshData*)g_scene.objects[1].user_data; + VisualDebug& dbg = g_renderer.GetVisualDebug(); + dbg.add_mesh_normals(g_scene.objects[1].get_model_matrix(), (uint32_t)data->vertices.size(), data->vertices.data()); + dbg.add_mesh_wireframe(g_scene.objects[1].get_model_matrix(), (uint32_t)data->vertices.size(), data->vertices.data(), (uint32_t)data->indices.size(), data->indices.data(), vec3(0.0f, 1.0f, 1.0f)); } #endif /* !defined(STRIP_ALL) */ @@ -334,7 +348,11 @@ int main(int argc, char** argv) { Renderer3D::SetDebugEnabled(false); // Reset debug mode #endif - delete (std::vector*)g_scene.objects[1].user_data; + struct MeshData { + std::vector vertices; + std::vector indices; + }; + delete (MeshData*)g_scene.objects[1].user_data; wgpuBufferRelease(g_mesh_gpu_data.vertex_buffer); wgpuBufferRelease(g_mesh_gpu_data.index_buffer); -- cgit v1.2.3