three.cad/extlib/three-csg.js

201 lines
5.9 KiB
JavaScript

"use strict"
import * as THREE from '../node_modules/three/src/Three';
import { CSG, Vertex, Polygon } from "./csg-lib.js"
CSG.fromGeometry = function (geom, objectIndex) {
if (!geom.isBufferGeometry) {
console.error("Unsupported CSG input type:" + geom.type)
return
}
let polys = []
let posattr = geom.attributes.position
let normalattr = geom.attributes.normal
let uvattr = geom.attributes.uv
let colorattr = geom.attributes.color
let index;
if (geom.index)
index = geom.index.array;
else {
index = new Array((posattr.array.length / posattr.itemSize) | 0);
for (let i = 0; i < index.length; i++)
index[i] = i
}
let triCount = (index.length / 3) | 0
polys = new Array(triCount)
for (let i = 0, pli = 0, l = index.length; i < l; i += 3,
pli++) {
let vertices = new Array(3)
for (let j = 0; j < 3; j++) {
let vi = index[i + j]
let vp = vi * 3;
let vt = vi * 2;
let x = posattr.array[vp]
let y = posattr.array[vp + 1]
let z = posattr.array[vp + 2]
let nx = normalattr.array[vp]
let ny = normalattr.array[vp + 1]
let nz = normalattr.array[vp + 2]
let u = uvattr.array[vt]
let v = uvattr.array[vt + 1]
vertices[j] = new Vertex({
x,
y,
z
}, {
x: nx,
y: ny,
z: nz
}, {
x: u,
y: v,
z: 0
}, colorattr && { x: colorattr.array[vt], y: colorattr.array[vt + 1], z: colorattr.array[vt + 2] });
}
polys[pli] = new Polygon(vertices, objectIndex)
}
return CSG.fromPolygons(polys)
}
let ttvv0 = new THREE.Vector3()
let tmpm3 = new THREE.Matrix3();
CSG.fromMesh = function (mesh, objectIndex) {
let csg = CSG.fromGeometry(mesh.geometry, objectIndex)
tmpm3.getNormalMatrix(mesh.matrix);
for (let i = 0; i < csg.polygons.length; i++) {
let p = csg.polygons[i]
for (let j = 0; j < p.vertices.length; j++) {
let v = p.vertices[j]
v.pos.copy(ttvv0.copy(v.pos).applyMatrix4(mesh.matrix));
v.normal.copy(ttvv0.copy(v.normal).applyMatrix3(tmpm3))
}
}
return csg;
}
let nbuf3 = (ct) => {
return {
top: 0,
array: new Float32Array(ct),
write: function (v) { (this.array[this.top++] = v.x); (this.array[this.top++] = v.y); (this.array[this.top++] = v.z); }
}
}
let nbuf2 = (ct) => {
return {
top: 0,
array: new Float32Array(ct),
write: function (v) { (this.array[this.top++] = v.x); (this.array[this.top++] = v.y) }
}
}
CSG.toMesh = function (csg, toMatrix, toMaterial) {
let ps = csg.polygons;
let geom;
let g2;
if (0) //Old geometry path...
{
geom = new Geometry();
let vs = geom.vertices;
let fvuv = geom.faceVertexUvs[0]
for (let i = 0; i < ps.length; i++) {
let p = ps[i]
let pvs = p.vertices;
let v0 = vs.length;
let pvlen = pvs.length
for (let j = 0; j < pvlen; j++)
vs.push(new THREE.Vector3().copy(pvs[j].pos))
for (let j = 3; j <= pvlen; j++) {
let fc = new THREE.Face3();
let fuv = []
fvuv.push(fuv)
let fnml = fc.vertexNormals;
fc.a = v0;
fc.b = v0 + j - 2;
fc.c = v0 + j - 1;
fnml.push(new THREE.Vector3().copy(pvs[0].normal))
fnml.push(new THREE.Vector3().copy(pvs[j - 2].normal))
fnml.push(new THREE.Vector3().copy(pvs[j - 1].normal))
fuv.push(new THREE.Vector3().copy(pvs[0].uv))
fuv.push(new THREE.Vector3().copy(pvs[j - 2].uv))
fuv.push(new THREE.Vector3().copy(pvs[j - 1].uv))
fc.normal = new THREE.Vector3().copy(p.plane.normal)
geom.faces.push(fc)
}
}
geom = new THREE.BufferGeometry().fromGeometry(geom)
geom.verticesNeedUpdate = geom.elementsNeedUpdate = geom.normalsNeedUpdate = true;
}
if (1) { //BufferGeometry path
let triCount = 0;
ps.forEach(p => triCount += (p.vertices.length - 2))
geom = new THREE.BufferGeometry()
let vertices = nbuf3(triCount * 3 * 3)
let normals = nbuf3(triCount * 3 * 3)
let uvs = nbuf2(triCount * 2 * 3)
let colors;
let grps = []
ps.forEach(p => {
let pvs = p.vertices
let pvlen = pvs.length
if (p.shared !== undefined) {
if (!grps[p.shared]) grps[p.shared] = []
}
if (pvlen && pvs[0].color !== undefined) {
if (!colors) colors = nbuf3(triCount * 3 * 3);
}
for (let j = 3; j <= pvlen; j++) {
(p.shared !== undefined) && (grps[p.shared].push(vertices.top / 3, (vertices.top / 3) + 1, (vertices.top / 3) + 2));
vertices.write(pvs[0].pos)
vertices.write(pvs[j - 2].pos)
vertices.write(pvs[j - 1].pos)
normals.write(pvs[0].normal)
normals.write(pvs[j - 2].normal)
normals.write(pvs[j - 1].normal)
uvs.write(pvs[0].uv)
uvs.write(pvs[j - 2].uv)
uvs.write(pvs[j - 1].uv)
colors && (colors.write(pvs[0].color) || colors.write(pvs[j - 2].color) || colors.write(pvs[j - 1].color))
}
}
)
geom.setAttribute('position', new THREE.BufferAttribute(vertices.array, 3));
geom.setAttribute('normal', new THREE.BufferAttribute(normals.array, 3));
geom.setAttribute('uv', new THREE.BufferAttribute(uvs.array, 2));
colors && geom.setAttribute('color', new THREE.BufferAttribute(colors.array, 3));
if (grps.length) {
let index = []
let gbase = 0;
for (let gi = 0; gi < grps.length; gi++) {
geom.addGroup(gbase, grps[gi].length, gi)
gbase += grps[gi].length
index = index.concat(grps[gi]);
}
geom.setIndex(index)
}
g2 = geom;
}
let inv = new THREE.Matrix4().copy(toMatrix).invert();
geom.applyMatrix4(inv);
geom.computeBoundingSphere();
geom.computeBoundingBox();
let m = new THREE.Mesh(geom, toMaterial);
m.matrix.copy(toMatrix);
m.matrix.decompose(m.position, m.quaternion, m.scale)
m.rotation.setFromQuaternion(m.quaternion)
m.updateMatrixWorld();
m.castShadow = m.receiveShadow = true;
return m
}
export default CSG