convert all meshes to non-indexed

This commit is contained in:
Stewart Allen 2022-01-31 13:27:09 -05:00
commit 6993a339e7
4 changed files with 60 additions and 74 deletions

View file

@ -125,7 +125,6 @@
* add section view. local clip. raycast skip points above plane
* add isolate op = separate bodies
* add decimate op = face reduction
* add union op (applied after isolate)
* add flatten/crush op: for z bottoms
* face selection: find regions with < delta to normal
* better z snap using just vertexes from face intersected

View file

@ -182,7 +182,11 @@ mesh.model = class MeshModel extends mesh.object {
load(vertices, indices, normals) {
let geo = new BufferGeometry();
geo.setAttribute('position', new BufferAttribute(vertices, 3));
if (indices) geo.setIndex(new BufferAttribute(indices, 1));
if (indices) {
// unroll indexed geometries
geo.setIndex(new BufferAttribute(indices, 1));
geo = geo.toNonIndexed();
}
if (!normals) geo.computeVertexNormals();
let meh = this.mesh = new Mesh(geo, [
this.mats.normal,
@ -199,24 +203,23 @@ mesh.model = class MeshModel extends mesh.object {
// persist in db so it can be restored on page load
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
// 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});
}
reload(vertices, indices, normals) {
reload(vertices) {
let was = this.wireframe(false);
let geo = this.mesh.geometry;
geo.setAttribute('position', new BufferAttribute(vertices, 3));
geo.setAttribute('normal', undefined);
// signal util.box3expand that geometry changed
geo._model_invalid = true;
if (indices) geo.setIndex(new BufferAttribute(indices, 1));
if (!normals) geo.computeVertexNormals();
geo.computeVertexNormals();
// allows raycasting to work
geo.computeBoundingSphere();
// persist in db so it can be restored on page load
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
// sync data to worker
worker.model_load({id: this.id, name: this.name, vertices, indices});
worker.model_load({id: this.id, name: this.name, vertices});
// restore wireframe state
this.wireframe(was);
// fixup normals

View file

@ -24,82 +24,68 @@ mesh.tool = class MeshTool {
constructor(params = {}) {
this.precision = Math.pow(10, params.precision || 6);
if (params.vertices) {
this.setData(params.vertices, params.faces);
this.setVertices(params.vertices);
}
}
/**
* set vertices and faces of the mesh. if only vertices are provided
* then the data is assumed to be un-indexed and will be indexed into
* faces. if faces are provided, they are assumed to be index references
* into the vertex data. removes invalid faces.
*
* the end result is face data mapped to an indexed set of unique vertices.
*
* @param {number[]} vertices
* @param {number[]} faces
*/
setData(vertices, faces) {
setVertices(vertices, opt = {}) {
if (!vertices) {
throw "missing vertices";
}
if (vertices.length % 3 !== 0) {
throw "invalid vertices";
}
// when face/index data is missing, vertices need to be normalized
if (!faces) {
faces = [];
let fcac = {}; // seen face hash
let fnew = []; // accumulate vertex triplets
let nuvt = []; // new vertex list
let hash = {}; // find vertex matches
let prec = this.precision;
let dups = 0;
let cull = 0;
for (let i=0, l=vertices.length; i<l; i += 3) {
let x = vertices[i];
let y = vertices[i+1];
let z = vertices[i+2];
let key = [
(x * prec) | 0,
(y * prec) | 0,
(z * prec) | 0
].join('');
let vpos = hash[key];
if (vpos === undefined) {
// add new vertex x,y,z and hash entry with index
hash[key] = vpos = nuvt.length;
nuvt.push(x);
nuvt.push(y);
nuvt.push(z);
}
// add vertex position to face accumulator
fnew.push(vpos);
if (fnew.length === 3) {
// check and emit face if it's unique
// cull invalid faces (has 2 or more shared vertices)
if (fnew[0] === fnew[1] || fnew[0] === fnew[2] || fnew[1] === fnew[2]) {
fnew = [];
cull++;
continue;
}
let key = fnew.slice().sort().join('-');
// drop duplicate faces (sort handles reverse order)
if (!fcac[key]) {
faces.appendAll(fnew);
fcac[key] = key;
} else {
dups++;
}
fnew = [];
}
let faces = [];
let fcac = {}; // seen face hash
let fnew = []; // accumulate vertex triplets
let nuvt = []; // new vertex list
let hash = {}; // find vertex matches
let prec = this.precision;
let dups = 0;
let cull = 0;
for (let i=0, l=vertices.length; i<l; i += 3) {
let x = vertices[i];
let y = vertices[i+1];
let z = vertices[i+2];
let key = [
(x * prec) | 0,
(y * prec) | 0,
(z * prec) | 0
].join('');
let vpos = hash[key];
if (vpos === undefined) {
// add new vertex x,y,z and hash entry with index
hash[key] = vpos = nuvt.length;
nuvt.push(x);
nuvt.push(y);
nuvt.push(z);
}
// add vertex position to face accumulator
fnew.push(vpos);
if (fnew.length === 3) {
// check and emit face if it's unique
// cull invalid faces (has 2 or more shared vertices)
if (fnew[0] === fnew[1] || fnew[0] === fnew[2] || fnew[1] === fnew[2]) {
fnew = [];
cull++;
continue;
}
let key = fnew.slice().sort().join('-');
// drop duplicate faces (sort handles reverse order)
if (!fcac[key]) {
faces.appendAll(fnew);
fcac[key] = key;
} else {
dups++;
}
fnew = [];
}
vertices = nuvt;
this.stats = {cull, dups, faces:faces.length/3};
// console.log({stats: this.stats});
} else {
faces = faces.map(v => v*3);
}
vertices = nuvt;
this.stats = {cull, dups, faces:faces.length/3};
// unique vertex array
this.vertices = vertices;
// unique face array. elements are offset into vertices
@ -112,7 +98,7 @@ mesh.tool = class MeshTool {
* construct ordered line maps with array of connected edges.
* connect lines into polys. earcut polys into new faces.
*/
heal(opt = { merge: true }) {
patch(opt = { merge: true }) {
let vertices = this.vertices;
let faces = this.faces;
let hash = {}; // key to line map

View file

@ -59,25 +59,23 @@ function translate_encode(id, matrix) {
}
function analyze(id, opt = {}) {
log(`${id} | indexing...`);
log(`${id} | analyzing...`);
let geo = cache[id].geo;
let tool = new mesh.tool({
vertices: geo.attributes.position.array,
faces: geo.index ? geo.index.array : undefined,
debug: false
});
log(`${id} | analyzing...`);
tool.heal(opt);
log(`${id} | patching...`);
tool.patch(opt);
dbug.log(tool);
return tool;
}
let model = {
load(data) {
let { vertices, indices, name, id } = data;
let { vertices, name, id } = data;
let geo = new BufferGeometry();
geo.setAttribute('position', new BufferAttribute(vertices, 3));
if (indices) geo.setIndex(new BufferAttribute(indices, 1));
cacheUpdate(id, { name, geo, xmatrix: core_matrix.clone(), trans: undefined });
},