debugging indexed geometry
This commit is contained in:
parent
c86c90d915
commit
9b77c837e3
5 changed files with 63 additions and 41 deletions
|
|
@ -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])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue