OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / distribute / hypertps-win64 / shaders / bake_planeset.glsl

169 lines · glsl ref:
#version 450

// ============================================================================
// Plane-set BAKE pass (the SDF plane-set brick).
//
// For every cell, capture the exact convex-brush plane-set (face/edge/corner)
// from the brush geometry and store it, so qef_solve READS the baked planes
// instead of re-deriving them per remesh. This is the mutability substrate:
// settled architecture is baked once; a remesh of a settled region does no
// O(edits) capture. (Re-bake-on-edit / persistence = a later increment; this
// pass currently bakes per mesh, moving the capture out of the hot QEF stage.)
//
// The capture logic is byte-for-byte the qef_solve Step-5b capture:
//   - faces within T of the cell centre,
//   - cell inside all OTHER planes of the SAME brush (onbrush),
//   - csg4 cross-brush HIDDEN-FACE removal (a face is real only if a point just
//     outside it lies outside every other brush),
//   - dedup by normal (|dot|>0.999) into up to 3 planes,
//   - material from the nearest face.
//
// Dispatch: ceil(grid_dims³ / 256), 1, 1  (per cell; inactive cells → cl_count 0)
// ============================================================================

#define THREADS 256
layout(local_size_x = THREADS, local_size_y = 1, local_size_z = 1) in;

struct GpuEdit {
    uint  edit_type;
    float pos_x, pos_y, pos_z;
    float half_x, half_y, half_z;
    float radius;
    float strength;
    uint  _pad0, _pad1, _pad2;   // _pad0=material_id, _pad1=plane offset, _pad2=count
};

layout(set = 0, binding = 9, std430) readonly buffer EditBuf {
    uint edit_count;
    uint _edit_pad0, _edit_pad1, _edit_pad2;
    GpuEdit gpu_edits[];
};
layout(set = 0, binding = 10, std430) readonly buffer ConvexPlaneBuf { vec4 convex_planes[]; };
// Per-face projection index, parallel to convex_planes (1-based; 0 = none). Stage-2 texturing.
layout(set = 0, binding = 12, std430) readonly buffer FaceProjBuf { uint convex_faceproj[]; };

// Per-cell baked plane-set. 64 bytes/cell (std430, 16-byte aligned).
struct CellPlaneSet {
    uint cl_count;      // 0..3
    uint material;      // material_id of the nearest face
    uint proj0;         // projection index of the cell's 1st captured face (0 = none)
    uint proj1;         // ...and its 2nd (a crease's other face; 0 if single-face). The shader
                        // picks between them per-fragment by normal, killing the edge-strip
                        // stretch where one face's projection bled across a sharp crease.
    vec4 planes[3];     // (nx, ny, nz, d)  — n·p = d on the face
};
layout(set = 0, binding = 11, std430) writeonly buffer PlaneSetBuf { CellPlaneSet cell_planeset[]; };

layout(push_constant) uniform PushConstants {
    vec3  cell_origin;
    float voxel_size;
    ivec3 grid_dims;
    uint  total_elements;
    uint  mesh_quality_flags;
    uint  _pc_pad0;
    uint  _pc_pad1;
    uint  _pc_pad2;
};

void main() {
    uint gid = gl_GlobalInvocationID.x;
    if (gid >= total_elements) return;

    int V = grid_dims.x;
    int x = int(gid % uint(V));
    int y = int((gid / uint(V)) % uint(V));
    int z = int(gid / uint(V * V));
    vec3 cell_ctr = cell_origin + (vec3(float(x), float(y), float(z)) + 0.5) * voxel_size;

    vec3  cl_n[3];
    float cl_d[3];
    uint  cl_proj[3];           // per-captured-face projection index (parallel to cl_n)
    int   cl_count = 0;
    uint  cell_material = 0u;   // material of the DOMINANT brush (smallest union-SDF at the
    float best_sdf = 1e30;      // cell centre) = the outermost surface the cell is on. Picking
    float T = voxel_size * 1.2; // by nearest-plane / first-captured bled coplanar merges.

    for (uint ei = 0u; ei < edit_count; ei++) {
        GpuEdit ce = gpu_edits[ei];
        if (ce.edit_type != 8u && ce.edit_type != 9u) continue;   // convex brushes only
        vec3 dcv = cell_ctr - vec3(ce.pos_x, ce.pos_y, ce.pos_z);
        float rr = ce.radius + T;
        if (dot(dcv, dcv) > rr * rr) continue;
        uint poff = ce._pad1;
        uint pcnt = ce._pad2;
        bool contributed = false;   // did this brush contribute a real (onbrush, unburied) face?
        for (uint pi = 0u; pi < pcnt; pi++) {
            vec4 pl = convex_planes[poff + pi];
            float fd = pl.x * cell_ctr.x + pl.y * cell_ctr.y + pl.z * cell_ctr.z - pl.w;
            if (abs(fd) >= T) continue;
            bool onbrush = true;                        // cell inside this brush's OTHER planes (~T)
            for (uint pj = 0u; pj < pcnt; pj++) {
                if (pj == pi) continue;
                vec4 q = convex_planes[poff + pj];
                if (q.x * cell_ctr.x + q.y * cell_ctr.y + q.z * cell_ctr.z - q.w > T) { onbrush = false; break; }
            }
            if (!onbrush) continue;
            // csg4 cross-brush hidden-face removal
            vec3 fpt = cell_ctr - pl.xyz * fd;
            vec3 qp  = fpt + pl.xyz * (voxel_size * 0.5);
            bool buried = false;
            for (uint ej = 0u; ej < edit_count && !buried; ej++) {
                if (ej == ei) continue;
                GpuEdit ce2 = gpu_edits[ej];
                if (ce2.edit_type != 8u && ce2.edit_type != 9u) continue;
                vec3 dcv2 = qp - vec3(ce2.pos_x, ce2.pos_y, ce2.pos_z);
                if (dot(dcv2, dcv2) > ce2.radius * ce2.radius) continue;
                uint po2 = ce2._pad1, pc2 = ce2._pad2;
                float mx = -1e30;
                for (uint pk = 0u; pk < pc2; pk++) {
                    vec4 pl2 = convex_planes[po2 + pk];
                    mx = max(mx, pl2.x * qp.x + pl2.y * qp.y + pl2.z * qp.z - pl2.w);
                }
                // Require GENUINE burial (>1 voxel inside the neighbor), not merely abutting. The
                // outward point is pushed 0.5 voxel out; abutting arch wedges land it barely inside a
                // neighbor (mx just <0) and wrongly hid the VISIBLE diagonal faces. A truly hidden face
                // sits far deeper. Oracle (START.MAP): diagonal capture 86%% -> 99.7%%; material-bleed
                // guard (tests/test_material_merge) unchanged.
                if (mx < -voxel_size) buried = true;
            }
            if (buried) continue;
            contributed = true;
            int matched = -1;                            // merge only SAME-facing planes — NOT
            for (int c = 0; c < cl_count; c++)           // anti-parallel (abs()), which collapsed
                if (dot(pl.xyz, cl_n[c]) > 0.999) { matched = c; break; }  // a thin slab's two
                                                         // faces into one → one side stair-stepped.
                                                         // Oracle: tests/test_thin_slab.cpp.
            if (matched < 0 && cl_count < 3) {           // new face → capture its plane + projection
                cl_n[cl_count] = pl.xyz; cl_d[cl_count] = pl.w;
                cl_proj[cl_count] = convex_faceproj[poff + pi];
                cl_count++;
            }
        }
        // Material = the brush the cell is most INSIDE (smallest union-SDF). Restricted to
        // brushes that actually contribute a face here, so an adjacent/overlapping brush
        // with a COPLANAR face no longer steals the colour. Validated on CPU:
        // tests/test_material_merge.cpp (adjacent bleed 1->0, overlap 6->4-in-ambiguous-band).
        if (contributed) {
            float bs = -1e30;
            for (uint pk = 0u; pk < pcnt; pk++) {
                vec4 plk = convex_planes[poff + pk];
                bs = max(bs, plk.x * cell_ctr.x + plk.y * cell_ctr.y + plk.z * cell_ctr.z - plk.w);
            }
            if (bs < best_sdf) { best_sdf = bs; cell_material = ce._pad0; }
        }
    }

    CellPlaneSet ps;
    ps.cl_count = uint(cl_count);
    ps.material = cell_material;   // dominant-brush material (see loop above)
    // Two candidate face projections (Stage-2). The fragment shader picks between them by
    // matching each face's table-derived normal to the pixel normal, so a sharp crease's
    // two faces each texture correctly instead of one bleeding across the edge.
    ps.proj0 = (cl_count > 0) ? cl_proj[0] : 0u;
    ps.proj1 = (cl_count > 1) ? cl_proj[1] : 0u;
    ps.planes[0] = (cl_count > 0) ? vec4(cl_n[0], cl_d[0]) : vec4(0.0);
    ps.planes[1] = (cl_count > 1) ? vec4(cl_n[1], cl_d[1]) : vec4(0.0);
    ps.planes[2] = (cl_count > 2) ? vec4(cl_n[2], cl_d[2]) : vec4(0.0);
    cell_planeset[gid] = ps;
}