convert all meshes to non-indexed
This commit is contained in:
parent
f1ea39f786
commit
6993a339e7
4 changed files with 60 additions and 74 deletions
1
notes.md
1
notes.md
|
|
@ -125,7 +125,6 @@
|
||||||
* add section view. local clip. raycast skip points above plane
|
* add section view. local clip. raycast skip points above plane
|
||||||
* add isolate op = separate bodies
|
* add isolate op = separate bodies
|
||||||
* add decimate op = face reduction
|
* add decimate op = face reduction
|
||||||
* add union op (applied after isolate)
|
|
||||||
* add flatten/crush op: for z bottoms
|
* add flatten/crush op: for z bottoms
|
||||||
* face selection: find regions with < delta to normal
|
* face selection: find regions with < delta to normal
|
||||||
* better z snap using just vertexes from face intersected
|
* better z snap using just vertexes from face intersected
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,11 @@ mesh.model = class MeshModel extends mesh.object {
|
||||||
load(vertices, indices, normals) {
|
load(vertices, indices, normals) {
|
||||||
let geo = new BufferGeometry();
|
let geo = new BufferGeometry();
|
||||||
geo.setAttribute('position', new BufferAttribute(vertices, 3));
|
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();
|
if (!normals) geo.computeVertexNormals();
|
||||||
let meh = this.mesh = new Mesh(geo, [
|
let meh = this.mesh = new Mesh(geo, [
|
||||||
this.mats.normal,
|
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
|
// persist in db so it can be restored on page load
|
||||||
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
|
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
|
||||||
// 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});
|
||||||
}
|
}
|
||||||
|
|
||||||
reload(vertices, indices, normals) {
|
reload(vertices) {
|
||||||
let was = this.wireframe(false);
|
let was = this.wireframe(false);
|
||||||
let geo = this.mesh.geometry;
|
let geo = this.mesh.geometry;
|
||||||
geo.setAttribute('position', new BufferAttribute(vertices, 3));
|
geo.setAttribute('position', new BufferAttribute(vertices, 3));
|
||||||
geo.setAttribute('normal', undefined);
|
geo.setAttribute('normal', undefined);
|
||||||
// signal util.box3expand that geometry changed
|
// signal util.box3expand that geometry changed
|
||||||
geo._model_invalid = true;
|
geo._model_invalid = true;
|
||||||
if (indices) geo.setIndex(new BufferAttribute(indices, 1));
|
geo.computeVertexNormals();
|
||||||
if (!normals) geo.computeVertexNormals();
|
|
||||||
// allows raycasting to work
|
// allows raycasting to work
|
||||||
geo.computeBoundingSphere();
|
geo.computeBoundingSphere();
|
||||||
// persist in db so it can be restored on page load
|
// persist in db so it can be restored on page load
|
||||||
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
|
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
|
||||||
// sync data to worker
|
// 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
|
// restore wireframe state
|
||||||
this.wireframe(was);
|
this.wireframe(was);
|
||||||
// fixup normals
|
// fixup normals
|
||||||
|
|
|
||||||
112
src/mesh/tool.js
112
src/mesh/tool.js
|
|
@ -24,82 +24,68 @@ mesh.tool = class MeshTool {
|
||||||
constructor(params = {}) {
|
constructor(params = {}) {
|
||||||
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.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[]} vertices
|
||||||
* @param {number[]} faces
|
|
||||||
*/
|
*/
|
||||||
setData(vertices, faces) {
|
setVertices(vertices, opt = {}) {
|
||||||
if (!vertices) {
|
if (!vertices) {
|
||||||
throw "missing vertices";
|
throw "missing vertices";
|
||||||
}
|
}
|
||||||
if (vertices.length % 3 !== 0) {
|
if (vertices.length % 3 !== 0) {
|
||||||
throw "invalid vertices";
|
throw "invalid vertices";
|
||||||
}
|
}
|
||||||
// when face/index data is missing, vertices need to be normalized
|
let faces = [];
|
||||||
if (!faces) {
|
let fcac = {}; // seen face hash
|
||||||
faces = [];
|
let fnew = []; // accumulate vertex triplets
|
||||||
let fcac = {}; // seen face hash
|
let nuvt = []; // new vertex list
|
||||||
let fnew = []; // accumulate vertex triplets
|
let hash = {}; // find vertex matches
|
||||||
let nuvt = []; // new vertex list
|
let prec = this.precision;
|
||||||
let hash = {}; // find vertex matches
|
let dups = 0;
|
||||||
let prec = this.precision;
|
let cull = 0;
|
||||||
let dups = 0;
|
for (let i=0, l=vertices.length; i<l; i += 3) {
|
||||||
let cull = 0;
|
let x = vertices[i];
|
||||||
for (let i=0, l=vertices.length; i<l; i += 3) {
|
let y = vertices[i+1];
|
||||||
let x = vertices[i];
|
let z = vertices[i+2];
|
||||||
let y = vertices[i+1];
|
let key = [
|
||||||
let z = vertices[i+2];
|
(x * prec) | 0,
|
||||||
let key = [
|
(y * prec) | 0,
|
||||||
(x * prec) | 0,
|
(z * prec) | 0
|
||||||
(y * prec) | 0,
|
].join('');
|
||||||
(z * prec) | 0
|
let vpos = hash[key];
|
||||||
].join('');
|
if (vpos === undefined) {
|
||||||
let vpos = hash[key];
|
// add new vertex x,y,z and hash entry with index
|
||||||
if (vpos === undefined) {
|
hash[key] = vpos = nuvt.length;
|
||||||
// add new vertex x,y,z and hash entry with index
|
nuvt.push(x);
|
||||||
hash[key] = vpos = nuvt.length;
|
nuvt.push(y);
|
||||||
nuvt.push(x);
|
nuvt.push(z);
|
||||||
nuvt.push(y);
|
}
|
||||||
nuvt.push(z);
|
// add vertex position to face accumulator
|
||||||
}
|
fnew.push(vpos);
|
||||||
// add vertex position to face accumulator
|
if (fnew.length === 3) {
|
||||||
fnew.push(vpos);
|
// check and emit face if it's unique
|
||||||
if (fnew.length === 3) {
|
// cull invalid faces (has 2 or more shared vertices)
|
||||||
// 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('-');
|
||||||
}
|
// drop duplicate faces (sort handles reverse order)
|
||||||
let key = fnew.slice().sort().join('-');
|
if (!fcac[key]) {
|
||||||
// drop duplicate faces (sort handles reverse order)
|
faces.appendAll(fnew);
|
||||||
if (!fcac[key]) {
|
fcac[key] = key;
|
||||||
faces.appendAll(fnew);
|
} else {
|
||||||
fcac[key] = key;
|
dups++;
|
||||||
} else {
|
}
|
||||||
dups++;
|
fnew = [];
|
||||||
}
|
|
||||||
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
|
// unique vertex array
|
||||||
this.vertices = vertices;
|
this.vertices = vertices;
|
||||||
// unique face array. elements are offset into 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.
|
* construct ordered line maps with array of connected edges.
|
||||||
* connect lines into polys. earcut polys into new faces.
|
* connect lines into polys. earcut polys into new faces.
|
||||||
*/
|
*/
|
||||||
heal(opt = { merge: true }) {
|
patch(opt = { merge: true }) {
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -59,25 +59,23 @@ function translate_encode(id, matrix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function analyze(id, opt = {}) {
|
function analyze(id, opt = {}) {
|
||||||
log(`${id} | indexing...`);
|
log(`${id} | analyzing...`);
|
||||||
let geo = cache[id].geo;
|
let geo = cache[id].geo;
|
||||||
let tool = new mesh.tool({
|
let tool = new mesh.tool({
|
||||||
vertices: geo.attributes.position.array,
|
vertices: geo.attributes.position.array,
|
||||||
faces: geo.index ? geo.index.array : undefined,
|
|
||||||
debug: false
|
debug: false
|
||||||
});
|
});
|
||||||
log(`${id} | analyzing...`);
|
log(`${id} | patching...`);
|
||||||
tool.heal(opt);
|
tool.patch(opt);
|
||||||
dbug.log(tool);
|
dbug.log(tool);
|
||||||
return tool;
|
return tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
let model = {
|
let model = {
|
||||||
load(data) {
|
load(data) {
|
||||||
let { vertices, indices, name, id } = data;
|
let { vertices, name, id } = data;
|
||||||
let geo = new BufferGeometry();
|
let geo = new BufferGeometry();
|
||||||
geo.setAttribute('position', new BufferAttribute(vertices, 3));
|
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 });
|
cacheUpdate(id, { name, geo, xmatrix: core_matrix.clone(), trans: undefined });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue