debugging indexed geometry

This commit is contained in:
Stewart Allen 2022-01-04 01:11:13 -05:00
commit 9b77c837e3
5 changed files with 63 additions and 41 deletions

View file

@ -197,8 +197,12 @@ function space_init(data) {
moto.client.fn.model_heal(m.id) moto.client.fn.model_heal(m.id)
.then(data => { .then(data => {
if (data) { if (data) {
m.wireframe(false); console.log({data});
m.reload(data.vertices.toFloat32()); m.load(
// Float32Array.from(data.vertices.toFloat32()),
Float32Array.from([...data.v]),
Uint32Array.from([...data.f])
);
} }
}); });
} }

View file

@ -89,6 +89,11 @@ mesh.group = class MeshGroup extends mesh.object {
return this; return this;
} }
// update(oldmesh, newmesh) {
// this.group.remove(oldmesh);
// this.group.add(newmesh);
// }
// center objects to group bounds // center objects to group bounds
// dependent on first being added to world/scene // dependent on first being added to world/scene
centerModels() { centerModels() {

View file

@ -90,11 +90,14 @@ mesh.model = class MeshModel extends mesh.object {
} }
load(vertices, indices) { load(vertices, indices) {
this.wireframe(false);
let geo = new THREE.BufferGeometry(); let geo = new THREE.BufferGeometry();
if (indices) geo.setIndex(new THREE.BufferAttribute(indices, 1));
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
let meh = new THREE.Mesh(geo, materials.unselected); if (indices) geo.setIndex(new THREE.BufferAttribute(indices, 1));
geo.computeVertexNormals(); geo.computeVertexNormals();
// reuse mesh if this is a "reload"
let meh = this.mesh || new THREE.Mesh(geo, materials.unselected);
meh.geometry = geo;
meh.receiveShadow = true; meh.receiveShadow = true;
meh.castShadow = true; meh.castShadow = true;
meh.renderOrder = 1; meh.renderOrder = 1;
@ -102,21 +105,29 @@ mesh.model = class MeshModel extends mesh.object {
meh.model = this; meh.model = this;
// sync data to worker // sync data to worker
worker.model_load({id: this.id, name: this.file, vertices, indices}); worker.model_load({id: this.id, name: this.file, vertices, indices});
// update mesh in group
// if (this.group) this.group.update(oldmesh, meh);
return meh; return meh;
} }
reload(vertices, indices) { optimize() {
let geo = this.mesh.geometry; let ind = THREE.BufferGeometryUtils.mergeVertices(this.mesh.geometry);
geo.attributes.position.array = vertices; console.log({geo: this.mesh.geometry, ind});
geo.attributes.position.needsUpdate = true;
geo.setAttribute('normal', undefined);
if (indices) {
geo.setIndex(new THREE.BufferAttribute(indices, 1));
}
geo.computeVertexNormals();
worker.model_load({id: this.id, name: this.name, vertices, indices});
} }
// reload(vertices, indices) {
// this.wireframe(false);
// let geo = this.mesh.geometry;
// geo.attributes.position.array = vertices;
// geo.attributes.position.needsUpdate = true;
// geo.setAttribute('normal', undefined);
// if (indices) {
// geo.setIndex(new THREE.BufferAttribute(indices, 1));
// }
// geo.computeVertexNormals();
// worker.model_load({id: this.id, name: this.name, vertices, indices});
// }
get group() { get group() {
return this._group; return this._group;
} }

View file

@ -13,7 +13,6 @@ if (mesh.tool) return;
/** tool for identiying defects and healing them **/ /** tool for identiying defects and healing them **/
mesh.tool = class MeshTool { mesh.tool = class MeshTool {
constructor(params = {}) { constructor(params = {}) {
this.debug = params.debug;
this.precision = Math.pow(10, params.precision || 6); this.precision = Math.pow(10, params.precision || 6);
if (params.vertices) { if (params.vertices) {
this.setData(params.vertices, params.faces); this.setData(params.vertices, params.faces);
@ -38,10 +37,8 @@ mesh.tool = class MeshTool {
if (vertices.length % 3 !== 0) { if (vertices.length % 3 !== 0) {
throw "invalid vertices"; throw "invalid vertices";
} }
let TEST = this.debug;
// when face/index data is missing, vertices need to be normalized // when face/index data is missing, vertices need to be normalized
if (!faces) { if (!faces) {
if (TEST) console.time('generate faces');
faces = []; faces = [];
let fcac = {}; // seen face hash let fcac = {}; // seen face hash
let fnew = []; // accumulate vertex triplets let fnew = []; // accumulate vertex triplets
@ -49,7 +46,7 @@ mesh.tool = class MeshTool {
let hash = {}; // find vertex matches let hash = {}; // find vertex matches
let prec = this.precision; let prec = this.precision;
let dups = 0; let dups = 0;
// let cull = 0; let cull = 0;
for (let i=0, l=vertices.length; i<l; i += 3) { for (let i=0, l=vertices.length; i<l; i += 3) {
let x = vertices[i]; let x = vertices[i];
let y = vertices[i+1]; let y = vertices[i+1];
@ -61,33 +58,37 @@ mesh.tool = class MeshTool {
].join(''); ].join('');
let vpos = hash[key]; let vpos = hash[key];
if (vpos === undefined) { if (vpos === undefined) {
// add new vertex x,y,z and hash entry with index
hash[key] = vpos = nuvt.length; hash[key] = vpos = nuvt.length;
nuvt.push(x); nuvt.push(x);
nuvt.push(y); nuvt.push(y);
nuvt.push(z); nuvt.push(z);
} }
// add vertex position to face accumulator
fnew.push(vpos); fnew.push(vpos);
if (fnew.length === 3) { if (fnew.length === 3) {
// cull invalid faces (shares 2 or more points) // check and emit face if it's unique
// if (fnew[0] === fnew[1] || fnew[0] === fnew[2] || fnew[1] === fnew[2]) { // cull invalid faces (has 2 or more shared vertices)
// fnew = []; if (fnew[0] === fnew[1] || fnew[0] === fnew[2] || fnew[1] === fnew[2]) {
// cull++; fnew = [];
// continue; cull++;
// } continue;
}
let key = fnew.slice().sort().join('-'); let key = fnew.slice().sort().join('-');
// drop duplicate faces (sort handles reverse order) // drop duplicate faces (sort handles reverse order)
if (!fcac[key]) { if (!fcac[key]) {
faces.appendAll(fnew); faces.appendAll(fnew);
fcac[key] = key;
} else { } else {
dups++; dups++;
} }
fcac[key] = key;
fnew = []; fnew = [];
} }
} }
vertices = nuvt; vertices = nuvt;
if (TEST) console.timeEnd('generate faces'); this.stats = {cull, dups, faces:faces.length/3};
if (TEST) console.log({dups, faces:faces.length/3}); } else {
faces = faces.map(v => v*3);
} }
this.vertices = vertices; this.vertices = vertices;
this.faces = faces; this.faces = faces;
@ -112,9 +113,6 @@ mesh.tool = class MeshTool {
* connect lines into polys. earcut polys into new faces. * connect lines into polys. earcut polys into new faces.
*/ */
heal() { heal() {
let TEST = this.debug;
if (TEST) console.time('heal');
let vertices = this.vertices; let vertices = this.vertices;
let faces = this.faces; let faces = this.faces;
let hash = {}; // key to line map let hash = {}; // key to line map
@ -131,7 +129,7 @@ mesh.tool = class MeshTool {
addFace(face) { addFace(face) {
if (this.faces.indexOf(face) < 0) { if (this.faces.indexOf(face) < 0) {
this.faces.push(face); this.faces.push(face);
} else if (TEST) { } else if (false) {
console.log('adding face to line twice', this, face); console.log('adding face to line twice', this, face);
} }
return this; return this;
@ -250,7 +248,7 @@ mesh.tool = class MeshTool {
let tmp = adjacent[0].v1; let tmp = adjacent[0].v1;
adjacent[0].v1 = adjacent[0].v2; adjacent[0].v1 = adjacent[0].v2;
adjacent[0].v2 = tmp; adjacent[0].v2 = tmp;
if (TEST > 1) console.log('chirality mismatch fixed'); // console.log('chirality mismatch fixed');
} }
line = adjacent[0]; line = adjacent[0];
} else if (adjacent.length === 2) { } else if (adjacent.length === 2) {
@ -259,7 +257,7 @@ mesh.tool = class MeshTool {
adjacent[0] : adjacent[0] :
adjacent[1] adjacent[1]
} else { } else {
if (TEST > 1) console.log('error adjacent', line, adjacent, loops.length, loop.length); // console.log('error adjacent', line, adjacent, loops.length, loop.length);
line.split = adjacent; line.split = adjacent;
line = adjacent[0]; line = adjacent[0];
} }
@ -306,11 +304,11 @@ mesh.tool = class MeshTool {
// store invalid loops for display / culling // store invalid loops for display / culling
this.shorts = loops.filter(l => l && l.length <= 2); this.shorts = loops.filter(l => l && l.length <= 2);
if (TEST) console.log({edges, loops, shorts: this.shorts}); // console.log({edges, loops, shorts: this.shorts});
// filter out null and short loops // filter out null and short loops
this.loops = loops = loops.filter(l => l && l.length > 2); this.loops = loops = loops.filter(l => l && l.length > 2);
if (TEST > 1) console.log({loops_filtered: loops}); // console.log({loops_filtered: loops});
// rotate/flatten to Z plane and use earcut to generate faces // rotate/flatten to Z plane and use earcut to generate faces
// because earcut emits point indexes, no need to un-rotate // because earcut emits point indexes, no need to un-rotate
@ -367,7 +365,7 @@ mesh.tool = class MeshTool {
let fpoints = points.flat(); let fpoints = points.flat();
let ec = earcut(fpoints, undefined, 3); let ec = earcut(fpoints, undefined, 3);
if (TEST > 2) console.log({points, fpoints, ec, dx, dy, dz}); // console.log({points, fpoints, ec, dx, dy, dz});
for (let point of ec) { for (let point of ec) {
faces.push(pindex[point]); faces.push(pindex[point]);
@ -381,8 +379,6 @@ mesh.tool = class MeshTool {
} }
this.newFaces = this.faces.length - faceCount; this.newFaces = this.faces.length - faceCount;
if (TEST) console.log({newFaces: this.newFaces});
if (TEST) console.timeEnd('heal');
return this; return this;
} }
}; };

View file

@ -29,9 +29,10 @@ function cacheUpdate(id, data) {
let model = { let model = {
load(data) { load(data) {
let { vertices, name, id } = data; let { vertices, indices, name, id } = data;
let geo = new THREE.BufferGeometry(); let geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
if (indices) geo.setIndex(new THREE.BufferAttribute(indices, 1));
cacheUpdate(id, { name, geo, matrix: core_matrix.clone() }); cacheUpdate(id, { name, geo, matrix: core_matrix.clone() });
}, },
@ -47,15 +48,20 @@ let model = {
heal(id) { heal(id) {
dbug.log({healing: id}); dbug.log({healing: id});
let geo = cache[id].geo;
let tool = new mesh.tool({ let tool = new mesh.tool({
vertices: cache[id].geo.attributes.position.array vertices: geo.attributes.position.array,
faces: geo.index ? geo.index.array : undefined,
debug: false
}); });
dbug.log('...imported data'); dbug.log('...imported data');
tool.heal(); tool.heal();
dbug.log('...healed'); dbug.log('...healed');
dbug.log(tool); dbug.log(tool);
return tool.newFaces ? { return true || tool.newFaces ? {
vertices: tool.unrolled(), vertices: tool.unrolled(),
v: tool.vertices,
f: tool.faces.map(f => f/3)
} : 0; } : 0;
} }
}; };