GLB voor AR zonder alles onder het maaiveld (GlbWriter clipBelow, zonder sandwichpanelen), AR op ware grootte; model Van den Berg (dubbel chalet met portiek en overdekte vlonder)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4bb1548125
commit
0da1769f51
+43
-1
@@ -34,10 +34,14 @@ window.GlbWriter = (() => {
|
||||
} catch (e) { return null; }
|
||||
}
|
||||
|
||||
// objects: three.js-objecten (zichtbaar deel); origin: verschuiving in meters. Geeft { blob, stats }.
|
||||
// objects: three.js-objecten (zichtbaar deel); origin: verschuiving in meters; clipBelow: alles onder deze hoogte (m, na
|
||||
// de verschuiving) valt weg, driehoeken die de snede kruisen worden afgesneden (AR zet de onderkant van het model op de
|
||||
// grond: met clipBelow 0 op het maaiveld valt die samen met de oorsprong). Geeft { blob, stats }.
|
||||
function build(objects, opts) {
|
||||
const o = opts || {};
|
||||
const origin = o.origin || { x: 0, y: 0, z: 0 };
|
||||
const clip = typeof o.clipBelow === 'number', clipY = o.clipBelow, EPS = 1e-6;
|
||||
const originV = new THREE.Vector3(origin.x, origin.y, origin.z);
|
||||
const buckets = new Map(); // materiaal -> { mat, tex, pos, nrm, uv, idx, n }
|
||||
const images = new Map(), samplers = new Map(), textures = new Map();
|
||||
const gltfImages = [], gltfSamplers = [], gltfTextures = [];
|
||||
@@ -115,6 +119,25 @@ window.GlbWriter = (() => {
|
||||
}
|
||||
return (remap[ci] = b.n++);
|
||||
};
|
||||
// Afgesneden driehoeken: losse hoekpunten (geïnterpoleerd), niet gedeeld via de remap.
|
||||
const raw = (ci) => {
|
||||
const p = new THREE.Vector3().fromBufferAttribute(pos, ci).applyMatrix4(mesh.matrixWorld).sub(originV);
|
||||
const n = new THREE.Vector3().fromBufferAttribute(nrm, ci).applyMatrix3(nm);
|
||||
if (n.lengthSq() < 1e-12) n.copy(face); else n.normalize();
|
||||
const t = new THREE.Vector2();
|
||||
if (b.map && uvA) t.fromBufferAttribute(uvA, ci).applyMatrix3(b.map.matrix);
|
||||
return { p, n, t };
|
||||
};
|
||||
const lerp = (A, B, f) => ({
|
||||
p: new THREE.Vector3().lerpVectors(A.p, B.p, f), n: new THREE.Vector3().lerpVectors(A.n, B.n, f).normalize(),
|
||||
t: new THREE.Vector2().lerpVectors(A.t, B.t, f)
|
||||
});
|
||||
const push = (q) => {
|
||||
b.pos.push(q.p.x, q.p.y, q.p.z);
|
||||
b.nrm.push(q.n.x, q.n.y, q.n.z);
|
||||
if (b.map) b.uv.push(q.t.x, b.map.flipY ? 1 - q.t.y : q.t.y);
|
||||
return b.n++;
|
||||
};
|
||||
const end = Math.min(gr.start + gr.count, idx ? idx.count : pos.count);
|
||||
for (let k = gr.start; k + 2 < end; k += 3) {
|
||||
const s = [0, 1, 2].map(j => idx ? idx.getX(k + j) : k + j);
|
||||
@@ -126,6 +149,25 @@ window.GlbWriter = (() => {
|
||||
const len = face.length();
|
||||
if (len < 2e-7) continue;
|
||||
face.multiplyScalar(flip ? -1 / len : 1 / len);
|
||||
if (clip) {
|
||||
const ys = s.map(ci => v.fromBufferAttribute(pos, ci).applyMatrix4(mesh.matrixWorld).y - origin.y);
|
||||
const inside = ys.map(y => y >= clipY - EPS), nIn = inside.filter(Boolean).length;
|
||||
if (!nIn) continue;
|
||||
if (nIn < 3) {
|
||||
const q = s.map(raw), poly = [];
|
||||
for (let j = 0; j < 3; j++) {
|
||||
const k2 = (j + 1) % 3;
|
||||
if (inside[j]) poly.push(q[j]);
|
||||
if (inside[j] !== inside[k2]) poly.push(lerp(q[j], q[k2], (clipY - ys[j]) / (ys[k2] - ys[j])));
|
||||
}
|
||||
const c = poly.map(push);
|
||||
for (let j = 1; j + 1 < c.length; j++) {
|
||||
if (flip) b.idx.push(c[0], c[j + 1], c[j]); else b.idx.push(c[0], c[j], c[j + 1]);
|
||||
triCount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const c = s.map(add);
|
||||
if (flip) b.idx.push(c[0], c[2], c[1]); else b.idx.push(c[0], c[1], c[2]);
|
||||
triCount++;
|
||||
|
||||
Reference in New Issue
Block a user