render-zig

A 3D rendering engine written in Zig
git clone git://git.christianermann.dev/render-zig
Log | Files | Refs

meshlets.zig (3279B)


      1 const std = @import("std");
      2 const assert = std.debug.assert;
      3 
      4 const Mesh = @import("mesh.zig");
      5 const MeshletDescriptor = Mesh.MeshletDescriptor;
      6 
      7 const f32x3 = @Vector(3, f32);
      8 const f32x4 = @Vector(4, f32);
      9 
     10 pub fn buildClusters(
     11     allocator: std.mem.Allocator,
     12     mesh: *const Mesh,
     13     max_vertices: u32,
     14     max_triangles: u32,
     15 ) !Mesh {
     16     // Only triangle meshes are supported
     17     assert(mesh.indices.len % 3 == 0);
     18     // Must have at least one triangle
     19     assert(max_vertices >= 3);
     20     assert(max_triangles >= 1);
     21 
     22     // 'unused' tracks which vertices have not been used
     23     // unused[vtx_idx] = 1 -> not used
     24     // unused[vtx_idx] = 0 -> used
     25     const unused = try allocator.alloc(u8, mesh.positions.len);
     26     defer allocator.free(unused);
     27     @memset(unused, 1);
     28 
     29     const indices = try allocator.alloc(u32, mesh.indices.len);
     30     var descriptors = std.ArrayList(MeshletDescriptor).init(allocator);
     31     defer descriptors.deinit();
     32 
     33     var num_vertices: u32 = 0;
     34     var num_triangles: u32 = 0;
     35     var cluster_offset: u32 = 0;
     36 
     37     for (0..mesh.indices.len / 3) |i| {
     38         const mesh_offset = i * 3;
     39         const a = mesh.indices[mesh_offset];
     40         const b = mesh.indices[mesh_offset + 1];
     41         const c = mesh.indices[mesh_offset + 2];
     42 
     43         // Triangles must be non-degenerate
     44         assert(a != b and a != c and b != c);
     45         // Vertices must be contained in the mesh
     46         const a_valid = a < mesh.positions.len;
     47         const b_valid = b < mesh.positions.len;
     48         const c_valid = c < mesh.positions.len;
     49         assert(a_valid and b_valid and c_valid);
     50 
     51         const num_extra = unused[a] + unused[b] + unused[c];
     52         const too_many_vertices = num_vertices + num_extra >= max_vertices;
     53         const too_many_triangles = num_triangles >= max_triangles;
     54         if (too_many_vertices or too_many_triangles) {
     55             // Save cluster info
     56             try descriptors.append(.{
     57                 .offset = cluster_offset,
     58                 .num_vertices = num_vertices,
     59                 .num_triangles = num_triangles,
     60             });
     61 
     62             // Reset state for next cluster
     63             @memset(unused, 1);
     64             cluster_offset += num_triangles * 3;
     65             num_vertices = 0;
     66             num_triangles = 0;
     67         }
     68 
     69         // Mark vertices as used
     70         unused[a] = 0;
     71         unused[b] = 0;
     72         unused[c] = 0;
     73 
     74         // Add triangle to cluster
     75         const offset = cluster_offset + num_triangles * 3;
     76         indices[offset] = a;
     77         indices[offset + 1] = b;
     78         indices[offset + 2] = c;
     79 
     80         num_vertices += num_extra;
     81         num_triangles += 1;
     82     }
     83 
     84     // Add final cluster
     85     if (num_triangles > 0) {
     86         try descriptors.append(.{
     87             .offset = cluster_offset,
     88             .num_vertices = num_vertices,
     89             .num_triangles = num_triangles,
     90         });
     91     }
     92 
     93     // Total size of mesh should not change
     94     assert(mesh.indices.len == cluster_offset + num_triangles * 3);
     95 
     96     return .{
     97         .positions = mesh.positions,
     98         .normals = mesh.normals,
     99         .tex_coords = mesh.tex_coords,
    100         .tangents = mesh.tangents,
    101         .bitangents = mesh.bitangents,
    102         .indices = indices,
    103         .descriptors = try descriptors.toOwnedSlice(),
    104     };
    105 }