render-zig

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

mesh.zig (4332B)


      1 const std = @import("std");
      2 
      3 const f32x3 = @Vector(3, f32);
      4 const f32x4 = @Vector(4, f32);
      5 
      6 const Mesh = @This();
      7 
      8 positions: []f32x4,
      9 normals: []f32x3,
     10 tex_coords: []f32x3,
     11 tangents: []f32x3,
     12 bitangents: []f32x3,
     13 indices: []u32,
     14 descriptors: ?[]MeshletDescriptor = null,
     15 bbox: [6]f32 = undefined,
     16 
     17 pub const MeshletDescriptor = struct {
     18     offset: u32,
     19     num_vertices: u32,
     20     num_triangles: u32,
     21 };
     22 
     23 pub fn tangentsAndBitangents(
     24     mesh: *const Mesh,
     25     allocator: std.mem.Allocator,
     26 ) !void {
     27     const positions = mesh.positions;
     28     const tex_coords = mesh.tex_coords;
     29     const indices = mesh.indices;
     30     const tangents = mesh.tangents;
     31     const bitangents = mesh.bitangents;
     32 
     33     @memset(std.mem.asBytes(tangents), 0);
     34     @memset(std.mem.asBytes(bitangents), 0);
     35     if (tex_coords.len <= 0) {
     36         return;
     37     }
     38 
     39     var references = try allocator.alloc(u32, positions.len);
     40     defer allocator.free(references);
     41     @memset(references, 0);
     42 
     43     var i: u32 = 0;
     44     while (i < indices.len) : (i += 3) {
     45         const idx_0 = indices[i + 0];
     46         const idx_1 = indices[i + 1];
     47         const idx_2 = indices[i + 2];
     48 
     49         const p0: f32x3 = @as([4]f32, positions[idx_0])[0..3].*;
     50         const p1: f32x3 = @as([4]f32, positions[idx_1])[0..3].*;
     51         const p2: f32x3 = @as([4]f32, positions[idx_2])[0..3].*;
     52         const delta_p1 = p1 - p0;
     53         const delta_p2 = p2 - p0;
     54 
     55         const t0 = tex_coords[idx_0];
     56         const t1 = tex_coords[idx_1];
     57         const t2 = tex_coords[idx_2];
     58         const delta_t1 = t1 - t0;
     59         const delta_t2 = t2 - t0;
     60 
     61         const r = 1.0 / (delta_t1[0] * delta_t2[1] - delta_t1[1] * delta_t2[0]);
     62 
     63         const tangent_a = delta_p1 * @as(f32x3, @splat(delta_t2[1]));
     64         const tangent_b = delta_p2 * @as(f32x3, @splat(delta_t1[1]));
     65         const tangent = (tangent_a - tangent_b) * @as(f32x3, @splat(r));
     66         tangents[idx_0] += tangent;
     67         tangents[idx_1] += tangent;
     68         tangents[idx_2] += tangent;
     69 
     70         const bitangent_a = delta_p2 * @as(f32x3, @splat(delta_t1[0]));
     71         const bitangent_b = delta_p1 * @as(f32x3, @splat(delta_t2[0]));
     72         const bitangent = (bitangent_a - bitangent_b) * @as(f32x3, @splat(-r));
     73         bitangents[idx_0] += bitangent;
     74         bitangents[idx_1] += bitangent;
     75         bitangents[idx_2] += bitangent;
     76 
     77         references[idx_0] += 1;
     78         references[idx_1] += 1;
     79         references[idx_2] += 1;
     80     }
     81 
     82     for (references, 0..references.len) |ref_count, idx| {
     83         const scale = @as(f32x3, @splat(1 / @as(f32, @floatFromInt(ref_count))));
     84         tangents[idx] *= scale;
     85         bitangents[idx] *= scale;
     86     }
     87 }
     88 
     89 pub fn axisAlignedBoundingBox(self: *const Mesh) [6]f32 {
     90     var min_x: f32 = self.positions[0][0];
     91     var max_x: f32 = self.positions[0][0];
     92     var min_y: f32 = self.positions[0][1];
     93     var max_y: f32 = self.positions[0][1];
     94     var min_z: f32 = self.positions[0][2];
     95     var max_z: f32 = self.positions[0][2];
     96     for (self.positions) |p| {
     97         const x = p[0];
     98         const y = p[1];
     99         const z = p[2];
    100         if (x < min_x) {
    101             min_x = x;
    102         }
    103         if (y < min_y) {
    104             min_y = y;
    105         }
    106         if (z < min_z) {
    107             min_z = z;
    108         }
    109         if (x > max_x) {
    110             max_x = x;
    111         }
    112         if (y > max_y) {
    113             max_y = y;
    114         }
    115         if (z > max_z) {
    116             max_z = z;
    117         }
    118     }
    119     std.log.info("bbox min: {} {} {}", .{ min_x, min_y, min_z });
    120     std.log.info("bbox max: {} {} {}", .{ max_x, max_y, max_z });
    121     return .{ min_x, min_y, min_z, max_x, max_y, max_z };
    122 }
    123 
    124 pub fn bboxVertices(self: *const Mesh) [8]f32x4 {
    125     const min_x = self.bbox[0];
    126     const min_y = self.bbox[1];
    127     const min_z = self.bbox[2];
    128     const max_x = self.bbox[3];
    129     const max_y = self.bbox[4];
    130     const max_z = self.bbox[5];
    131     return .{
    132         .{ min_x, min_y, min_z, 1 },
    133         .{ max_x, min_y, min_z, 1 },
    134         .{ max_x, max_y, min_z, 1 },
    135         .{ min_x, max_y, min_z, 1 },
    136         .{ min_x, min_y, max_z, 1 },
    137         .{ max_x, min_y, max_z, 1 },
    138         .{ max_x, max_y, max_z, 1 },
    139         .{ min_x, max_y, max_z, 1 },
    140     };
    141 }
    142 
    143 pub fn bboxIndices() [24]u32 {
    144     return .{
    145         0, 1, 1, 2, 2, 3, 3, 0,
    146         4, 5, 5, 6, 6, 7, 7, 4,
    147         0, 4, 1, 5, 2, 6, 3, 7,
    148     };
    149 }