@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
191 lines (177 loc) • 6.8 kB
text/typescript
import {BufferGeometry, BufferAttribute, Matrix4, MathUtils} from 'three';
import type {maths, geometries} from '@jscad/modeling';
// import {PolyDictionary} from '../../../../types/GlobalTypes';
import {ObjectType} from '../../../Constant';
import {BaseSopOperation} from '../../../../../engine/operations/sop/_Base';
import {csgMaterialMesh} from '../CsgConstant';
import {CSGTesselationParams} from '../CsgCommon';
import {toCreasedNormals} from 'three/examples/jsm/utils/BufferGeometryUtils';
// interface Geom3ToObject3DOptions {
// facet?: {
// angle: number;
// };
// }
interface jscadVertexWithIndex extends maths.vec3.Vec3 {
// positionAsString: string;
index: number;
}
// interface Normal {
// index: number;
// normal: Vector3;
// }
// interface NormalAttributes {
// normals: Normal[];
// }
export function geom3ToObject3D(csg: geometries.geom3.Geom3, options: CSGTesselationParams) {
const geometry = geom3ToBufferGeometry(csg, options);
return BaseSopOperation.createObject(
geometry,
ObjectType.MESH,
csgMaterialMesh(options.meshesColor, options.wireframe)
);
}
export function geom3ToBufferGeometry(csg: geometries.geom3.Geom3, options: CSGTesselationParams) {
const positions: number[] = [];
// const colors: number[] = [];
const indices: number[] = [];
const polygons = csg.polygons;
let currentIndex = 0;
// const color = csg.color;
const indexByPosition: Map<string, number> = new Map();
for (const polygon of polygons) {
const polygonjsCount = polygon.vertices.length;
const polygonVertices = polygon.vertices as jscadVertexWithIndex[];
// console.log(polygonVertices.map((v) => v.index));
for (const vertex of polygonVertices) {
const positionAsString = `${vertex[0]},${vertex[1]},${vertex[2]}`;
let index = indexByPosition.get(positionAsString);
if (index == null) {
index = currentIndex;
indexByPosition.set(positionAsString, index);
positions.push(vertex[0], vertex[1], vertex[2]);
// if (color) {
// colors.push(color[0], color[1], color[2]);
// } else {
// colors.push(1, 1, 1);
// }
currentIndex++;
}
vertex.index = index;
}
const first = (polygonVertices[0] as jscadVertexWithIndex).index;
for (let i = 2; i < polygonjsCount; i++) {
const second = (polygon.vertices[i - 1] as jscadVertexWithIndex).index;
const third = (polygon.vertices[i] as jscadVertexWithIndex).index;
indices.push(first, second, third);
}
}
// let idx = 0;
// console.log(indexByPosition);
// for (let polygon of polygons) {
// const polygonVertices = polygon.vertices as jscadVertexWithIndex[];
// // console.log(polygonVertices.map((v) => v.index));
// for (let vertex of polygonVertices) {
// const str = `${vertex[0]},${vertex[1]},${vertex[2]}`;
// if (!indexByPosition.get(str)) {
// indexByPosition.set(str, newIndex++);
// }
// vertex.index = idx;
// vertices.push(vertex[0], vertex[1], vertex[2]);
// if (polygon.color) {
// colors.push(polygon.color[0], polygon.color[1], polygon.color[2]);
// } else {
// colors.push(1, 1, 1);
// }
// idx++;
// }
// const first = (polygonVertices[0] as jscadVertexWithIndex).index;
// for (let i = 2; i < polygon.vertices.length; i++) {
// const second = (polygon.vertices[i - 1] as jscadVertexWithIndex).index;
// const third = (polygon.vertices[i] as jscadVertexWithIndex).index;
// indices.push(first, second, third);
// }
// }
const geo = new BufferGeometry();
geo.setAttribute('position', new BufferAttribute(new Float32Array(positions), 3));
// geo.setAttribute('color', new BufferAttribute(new Float32Array(colors), 3));
geo.setIndex(indices);
if (csg.transforms) {
const transforms = new Matrix4();
transforms.set(...csg.transforms).transpose();
geo.applyMatrix4(transforms);
}
geo.computeVertexNormals();
// if (options && options.facetAngle!=null) {
return toCreasedNormals(geo, MathUtils.degToRad(options.facetAngle));
// } else {
// return geo;
// }
// const positions: PolyDictionary<NormalAttributes> = {};
// for (let i = 0; i < geo.attributes.position.count; i++) {
// const pArray = geo.attributes.position.array;
// const x = Math.round(pArray[i * 3] * 100);
// const y = Math.round(pArray[i * 3 + 1] * 100);
// const z = Math.round(pArray[i * 3 + 2] * 100);
// const position = `${x},${y},${z}`;
// if (!positions[position]) {
// positions[position] = {normals: []};
// }
// const nArray = geo.attributes.normal.array;
// const nx = nArray[i * 3];
// const ny = nArray[i * 3 + 1];
// const nz = nArray[i * 3 + 2];
// const normal = new Vector3(nx, ny, nz);
// positions[position].normals.push({index: i, normal: normal});
// }
// const toAverage: Map<number, Vector3> = new Map();
// const toAverageIndices: number[] = [];
// for (let p in positions) {
// const currentPosition = positions[p];
// const nl = currentPosition.normals.length;
// for (let i = 0; i < nl - 1; i += 1) {
// for (let j = i + 1; j < nl; j += 1) {
// const n1 = currentPosition.normals[i].normal;
// const n2 = currentPosition.normals[j].normal;
// if (n1.angleTo(n2) < Math.PI * 0.5 && n1.angleTo(n2) !== 0) {
// const i0 = currentPosition.normals[i].index;
// const i1 = currentPosition.normals[j].index;
// toAverage.set(i0, currentPosition.normals[i].normal);
// toAverage.set(i1, currentPosition.normals[j].normal);
// toAverageIndices.push(i0, i1);
// }
// }
// }
// const averageNormal = new Vector3();
// for (let index of toAverageIndices) {
// const normal = toAverage.get(index);
// if (normal) {
// averageNormal.add(normal);
// averageNormal.normalize();
// }
// }
// for (let index of toAverageIndices) {
// (geo.attributes.normal.array as number[])[index * 3] = averageNormal.x;
// (geo.attributes.normal.array as number[])[index * 3 + 1] = averageNormal.y;
// (geo.attributes.normal.array as number[])[index * 3 + 2] = averageNormal.z;
// }
// toAverage.clear();
// toAverageIndices.splice(0, toAverageIndices.length);
// }
// geo.attributes.normal.needsUpdate = true;
// matrix.elements = csg.transforms;
// geo.applyMatrix4(matrix);
// return geo;
}
// export function geom3Positions(csg: geometries.geom3.Geom3): Vector3[] {
// const bufferGeometry = geom3ToBufferGeometry(csg);
// const positionAttribute = bufferGeometry.getAttribute('position') as BufferAttribute;
// const positionsArray = positionAttribute.array;
// const pointsCount = positionAttribute.itemSize;
// const vectors: Vector3[] = new Array(pointsCount);
// for (let i = 0; i < pointsCount; i++) {
// const vec = new Vector3().fromArray(positionsArray, i * 3);
// vectors[i] = vec;
// i++;
// }
// return vectors;
// }