OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain / tests / test_material_merge.cpp

117 lines · cpp ref:
// Reproduce the ADJACENT-MERGE MATERIAL BLEED and validate a fix — CPU oracle.
//
// Symptom (in-game): where two brushes with DIFFERENT materials merge, the colour
// bleeds across the seam. Hypothesis: the plane-set bake dedups parallel faces
// (>0.999) into ONE plane, so two COPLANAR faces from different brushes collapse to a
// single plane whose material = the FIRST-captured brush. Everything on that merged
// face gets one material regardless of which brush is actually under each cell → bleed.
// (The deployed "nearest-to-snapped-vertex" material pick can't help: after dedup the
// cell has ONE plane, so there's nothing to choose between.)
//
// Geometry: two axis boxes sharing the x=0 plane, with COPLANAR tops (y=2), different
// materials (A=1 for x<0, B=2 for x>0). Also an OVERLAP variant (x in [-1,1]).
//
// Methods compared, per top-surface cell:
//   FIRST   — material of the first-captured plane after dedup (models the current bake).
//   NEAREST — material of the plane whose |dist to cell CENTRE| is smallest (old bake).
//   FIX     — material of the brush with the smallest union-SDF at the cell centre
//             (= the brush the cell is most INSIDE = the true surface owner).
// Correct owner: brush the cell centre is laterally inside (A: x<0, B: x>0).
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
struct V3 { float x, y, z; };
static V3 operator-(V3 a, V3 b) { return {a.x - b.x, a.y - b.y, a.z - b.z}; }
static float dot(V3 a, V3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
struct Plane { V3 n; float d; };
struct Brush { std::vector<Plane> pl; int mat; };
static float bsdf(V3 p, const Brush& b) { float m = -1e30f; for (auto& q : b.pl) m = fmaxf(m, dot(q.n, p) - q.d); return m; }

static Brush box(V3 lo, V3 hi, int mat) {
    Brush b; b.mat = mat;
    b.pl = { {{1,0,0}, hi.x}, {{-1,0,0}, -lo.x},
             {{0,1,0}, hi.y}, {{0,-1,0}, -lo.y},
             {{0,0,1}, hi.z}, {{0,0,-1}, -lo.z} };
    return b;
}

// Replicate bake_planeset per-cell capture (T window, onbrush, csg4 not-buried, dedup)
// and return the three material choices + the captured plane count.
struct Res { int first, nearest, fix, cl_count; };
static Res bakeCell(V3 c, const std::vector<Brush>& B, float vox) {
    float T = vox * 1.2f;
    V3 cl_n[3]; float cl_d[3]; int cl_mat[3]; int cl_count = 0;
    int nearest_mat = 0; float best_absf = 1e30f;
    for (size_t ei = 0; ei < B.size(); ei++) {
        const Brush& ce = B[ei];
        for (auto& pl : ce.pl) {
            float fd = dot(pl.n, c) - pl.d;
            if (fabsf(fd) >= T) continue;
            bool onbrush = true;                             // cell inside this brush's OTHER planes (~T)
            for (auto& q : ce.pl) { if (&q == &pl) continue; if (dot(q.n, c) - q.d > T) { onbrush = false; break; } }
            if (!onbrush) continue;
            V3 fpt = { c.x - pl.n.x * fd, c.y - pl.n.y * fd, c.z - pl.n.z * fd };  // point on the face
            V3 qp = { fpt.x + pl.n.x * (vox * 0.5f), fpt.y + pl.n.y * (vox * 0.5f), fpt.z + pl.n.z * (vox * 0.5f) };
            bool buried = false;                             // csg4: face buried inside another brush?
            for (size_t ej = 0; ej < B.size() && !buried; ej++) {
                if (ej == ei) continue;
                if (bsdf(qp, B[ej]) < 0.0f) buried = true;
            }
            if (buried) continue;
            int matched = -1;                                // dedup by parallel normal
            for (int k = 0; k < cl_count; k++) if (fabsf(dot(pl.n, cl_n[k])) > 0.999f) { matched = k; break; }
            if (matched < 0 && cl_count < 3) { cl_n[cl_count] = pl.n; cl_d[cl_count] = pl.d; cl_mat[cl_count] = ce.mat; cl_count++; }
            if (fabsf(fd) < best_absf) { best_absf = fabsf(fd); nearest_mat = ce.mat; }
        }
    }
    Res r; r.cl_count = cl_count;
    r.first = cl_count > 0 ? cl_mat[0] : 0;
    r.nearest = nearest_mat;
    // FIX: material of the brush the cell is most INSIDE (smallest union-SDF), restricted
    // to brushes that actually contributed a captured face at this cell.
    int fix_mat = r.first; float best_sdf = 1e30f;
    for (size_t ei = 0; ei < B.size(); ei++) {
        bool contributes = false;                            // did this brush contribute a captured plane?
        for (auto& pl : B[ei].pl) {
            float fd = dot(pl.n, c) - pl.d; if (fabsf(fd) >= T) continue;
            bool onbrush = true; for (auto& q : B[ei].pl) { if (&q == &pl) continue; if (dot(q.n, c) - q.d > T) { onbrush = false; break; } }
            if (onbrush) { contributes = true; break; }
        }
        if (!contributes) continue;
        float s = bsdf(c, B[ei]);
        if (s < best_sdf) { best_sdf = s; fix_mat = B[ei].mat; }
    }
    r.fix = fix_mat;
    return r;
}

static void run(const char* name, const std::vector<Brush>& B, float vox) {
    int nfirst = 0, nnear = 0, nfix = 0, total = 0, band = 0;
    for (float cx = -3.5f; cx <= 3.5f + 1e-4f; cx += vox) {
        V3 c = { cx, 2.0f - vox * 0.5f, 0.0f };              // cell centre just under the coplanar top
        int correct = (cx < 0.0f) ? 1 : 2;
        Res r = bakeCell(c, B, vox);
        if (r.cl_count == 0) continue;                       // no face here
        total++;
        if (r.cl_count >= 2) band++;                         // cells that captured >1 plane before dedup would-be
        if (r.first != correct) nfirst++;
        if (r.nearest != correct) nnear++;
        if (r.fix != correct) nfix++;
    }
    printf("%-14s cells=%3d  BLEED: first=%3d  nearest=%3d  FIX=%3d\n", name, total, nfirst, nnear, nfix);
}

int main() {
    float vox = 0.224f;
    // Adjacent: share x=0, coplanar tops y=2.
    std::vector<Brush> adj = { box({-4,-4,-4},{0,2,4}, 1), box({0,-4,-4},{4,2,4}, 2) };
    // Overlapping: A x[-4,1], B x[-1,4] overlap [-1,1], coplanar tops.
    std::vector<Brush> ovl = { box({-4,-4,-4},{1,2,4}, 1), box({-1,-4,-4},{4,2,4}, 2) };
    printf("Material-merge bleed oracle (correct = brush the cell is laterally inside):\n");
    run("adjacent", adj, vox);
    run("overlapping", ovl, vox);
    printf("\nPASS if FIX == 0 while first/nearest > 0 (bleed reproduced AND fixed).\n");
    return 0;
}