From 557ea0980735679a58161b9b46f98ef76f4c660d Mon Sep 17 00:00:00 2001 From: Val Erastov Date: Mon, 25 Sep 2017 22:00:54 -0700 Subject: [PATCH] prepare for brep tesselation --- web/app/3d/debug.js | 2 +- web/app/3d/modeler-app.js | 12 +-- web/app/3d/scene/brep-scene-object.js | 150 +++++++++++++++++++++++--- web/app/3d/scene/scene-object.js | 3 +- web/app/3d/tess/brep-tess.js | 21 +++- 5 files changed, 163 insertions(+), 25 deletions(-) diff --git a/web/app/3d/debug.js b/web/app/3d/debug.js index 39dbb83d..d0357e55 100644 --- a/web/app/3d/debug.js +++ b/web/app/3d/debug.js @@ -76,7 +76,7 @@ function addGlobalDebugActions(app) { AddVolume: (shell, color) => { color = color || 0xffffff; const geometry = new THREE.Geometry(); - triangulateToThree(shell, geometry); + triangulateToThree(shell.faces, geometry); const mesh = new THREE.Mesh(geometry, createSolidMaterial({ color, transparent: true, diff --git a/web/app/3d/modeler-app.js b/web/app/3d/modeler-app.js index 0f1236b6..45248956 100644 --- a/web/app/3d/modeler-app.js +++ b/web/app/3d/modeler-app.js @@ -137,8 +137,8 @@ App.prototype.test2 = function() { // this.addShellOnScene(s1); // this.addShellOnScene(s2); - let result = this.TPI.brep.bool.intersect(s1, s2); - + // let result = this.TPI.brep.bool.intersect(s1, s2); + let result = s1; this.addShellOnScene(result); }; @@ -149,10 +149,10 @@ App.prototype.test3 = function() { const box3 = app.TPI.brep.primitives.box(150, 600, 350, new Matrix3().translate(25, 25, -250)); // let result = app.TPI.brep.bool.union(box1, box2); - let result = app.TPI.brep.bool.subtract(box1, box2); - result = app.TPI.brep.bool.subtract(result, box3); - // app.addShellOnScene(box1); - app.addShellOnScene(result); + // let result = app.TPI.brep.bool.subtract(box1, box2); + // result = app.TPI.brep.bool.subtract(result, box3); + app.addShellOnScene(box1); + // app.addShellOnScene(result); }; diff --git a/web/app/3d/scene/brep-scene-object.js b/web/app/3d/scene/brep-scene-object.js index 359238ac..3a0a1b58 100644 --- a/web/app/3d/scene/brep-scene-object.js +++ b/web/app/3d/scene/brep-scene-object.js @@ -2,8 +2,8 @@ import Vector from '../../math/vector' import {EDGE_AUX, FACE_CHUNK} from '../../brep/stitching' import {normalOfCCWSeq} from '../cad-utils' import {TriangulateFace} from '../tess/triangulation' -import {SceneSolid, SceneFace, WIREFRAME_MATERIAL} from './scene-object' -import brepTess from '../tess/brep-tess' +import {SceneSolid, SceneFace, WIREFRAME_MATERIAL, createSolidMaterial} from './scene-object' +import brepTess, {isMirrored} from '../tess/brep-tess' const SMOOTH_RENDERING = false //true; @@ -16,9 +16,7 @@ export class BREPSceneSolid extends SceneSolid { } createGeometry() { - const geometry = new THREE.Geometry(); - geometry.dynamic = true; - this.mesh = new THREE.Mesh(geometry, this.material); + this.mesh = new THREE.Object3D(); this.cadGroup.add(this.mesh); this.createFaces(); this.createEdges(); @@ -26,16 +24,82 @@ export class BREPSceneSolid extends SceneSolid { } createFaces() { - const geom = this.mesh.geometry; - const groups = triangulateToThree(this.shell, geom); - for (let g of groups) { - const sceneFace = new BREPSceneFace(g.brepFace, this); + + for (let brepFace of this.shell.faces) { + const sceneFace = new BREPSceneFace(brepFace, this); this.sceneFaces.push(sceneFace); - for (let i = g.groupStart; i < g.groupEnd; i++) { - const face = geom.faces[i]; - sceneFace.registerMeshFace(face); + const geom = new THREE.Geometry(); + geom.dynamic = true; + geom.faceVertexUvs[0] = []; + + function tess(nurbs) { + // __DEBUG__.AddNormal(nurbs.point(0.5,0.5), nurbs.normalInMiddle()); + const tess = nurbs.verb.tessellate({maxDepth: 3}); + const trs = tess.faces.map(faceIndices => { + return faceIndices.map(i => tess.points[i]).map(p => new Vector().set3(p)); + }); + trs.forEach(tr => tr.reverse()); + if (isMirrored(nurbs)) { + + } + return trs; } + + + const polygons = tess(brepFace.surface); + const stitchedSurface = brepFace.data[FACE_CHUNK]; + const nurbs = stitchedSurface ? stitchedSurface.origin : undefined; + + for (let p = 0; p < polygons.length; ++p) { + const off = geom.vertices.length; + const poly = polygons[p]; + const vLength = poly.length; + if (vLength < 3) continue; + const firstVertex = poly[0]; + geom.vertices.push(firstVertex.three()); + geom.vertices.push(poly[1].three()); + for (let i = 2; i < vLength; i++) { + geom.vertices.push(poly[i].three()); + const a = off; + const b = i - 1 + off; + const c = i + off; + let points = [firstVertex, poly[i - 1], poly[i]]; + + let normalOrNormals; + if (nurbs && SMOOTH_RENDERING) { + function normal(v) { + const uv = nurbs.closestParam(v.data()); + const vec = new THREE.Vector3(); + vec.set.apply(vec, nurbs.normal(uv[0], uv[1])); + vec.normalize(); + return vec; + } + + normalOrNormals = points.map(v => normal(v)); + } else { + normalOrNormals = threeV(brepFace.surface.normal(firstVertex)); + } + const face = new THREE.Face3(a, b, c); + + geom.faceVertexUvs[0].push( points.map(p => new THREE.Vector2().fromArray(brepFace.surface.verb.closestParam(p.data())))); + // face.materialIndex = gIdx++; + geom.faces.push(face); + } + geom.computeFaceNormals(); + let texture = createTexture(brepFace); + let material = createSolidMaterial(Object.assign({}, this.skin, { + map: texture, + transparent: true, + color: '0xffffff' + + })); + this.mesh.add(new THREE.Mesh(geom, material)) + //view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null); + } + } + + //geom.mergeVertices(); } @@ -90,7 +154,62 @@ class BREPSceneFace extends SceneFace { } } -export function triangulateToThree(shell, geom) { +function createTexture(brepFace) { + const w = 200; + const h = 200; + function getCanvas() { + if (brepFace.data.__canvas === undefined) { + let canvas = brepFace.data.__canvas = document.createElement("canvas"); + canvas.width = 200; + canvas.height = 200; + } + return brepFace.data.__canvas; + } + let canvas = getCanvas(); + let ctx = canvas.getContext("2d"); + + + + // ctx.fillStyle = '0xB0C4DE' + // ctx.fillRect(0,0, 400,400) + + // ctx.fillStyle = 'transparent' + // ctx.beginPath(); + // ctx.moveTo(25, 25); + // ctx.lineTo(105, 25); + // ctx.lineTo(25, 105); + // ctx.fill(); + ctx.scale(w,h); + ctx.fillStyle = 'red'; + ctx.beginPath(); + + for (let loop of brepFace.loops) { + for (let he of loop.halfEdges) { + const uvs = he.edge.curve.verb.tessellate().map(p => brepFace.verb.closestParam(p)); + if (he.inverted) { + uvs.reverse(); + } + let uv = uvs[0]; + ctx.moveTo(uv[0], uv[1]); + for (let i = 1; i < uv.length; ++i) { + uv = uvs[i]; + ctx.lineTo(uv[0], uv[1]); + } + } + } + + + ctx.moveTo(55, 55); + + ctx.lineTo(75, 175); + ctx.fill(); + + let texture = new THREE.Texture(canvas); + texture.needsUpdate = true; + return texture; +} + +export function triangulateToThree(faces, geom) { const result = []; let gIdx = 0; @@ -99,7 +218,7 @@ export function triangulateToThree(shell, geom) { geom.faces.push(face); } - for (let brepFace of shell.faces) { + for (let brepFace of faces) { const groupStart = geom.faces.length; const polygons = brepTess(brepFace); const stitchedSurface = brepFace.data[FACE_CHUNK]; @@ -131,6 +250,7 @@ export function triangulateToThree(shell, geom) { normalOrNormals = [firstVertex, poly[i - 1], poly[i]].map(v => normal(v)); } const face = new THREE.Face3(a, b, c, normalOrNormals); + createTexture(brepFace); addFace(face); } //view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null); @@ -161,3 +281,5 @@ class FaceGroup { function threeV(v) { return new THREE.Vector3(v.x, v.y, v.z) } + + diff --git a/web/app/3d/scene/scene-object.js b/web/app/3d/scene/scene-object.js index 6f8ea5f2..486d798d 100644 --- a/web/app/3d/scene/scene-object.js +++ b/web/app/3d/scene/scene-object.js @@ -21,8 +21,7 @@ export class SceneSolid { this.cadGroup.add(this.wireframeGroup); this.mergeable = true; this.sceneFaces = []; - - this.material = createSolidMaterial(skin); + this.skin = skin; } addLineToScene(a, b) { diff --git a/web/app/3d/tess/brep-tess.js b/web/app/3d/tess/brep-tess.js index 7a9fee4f..6b1bbcca 100644 --- a/web/app/3d/tess/brep-tess.js +++ b/web/app/3d/tess/brep-tess.js @@ -1,7 +1,9 @@ import libtess from 'libtess' import Vector from "../../math/vector"; +import {Face} from "../../brep/topo/face"; +import BrepBuilder from "../../brep/brep-builder"; -export default function(face) { +export default function A(face) { function asUV(p) { let uv = face.surface.verb.closestParam(p); uv.push(0); @@ -88,9 +90,24 @@ function analyzeCurvature(nurbs, triangles) { } -function isMirrored(surface) { +export function isMirrored(surface) { let a = surface.point(0, 0); let b = surface.point(1, 0); let c = surface.point(1, 1); return b.minus(a).cross(c.minus(a))._normalize().dot(surface.normalUV(0, 0)) < 0; } + + +function test() { + + let bb = new BrepBuilder(); + let shell = bb.face() + .loop([bb.vertex(0,0,0), bb.vertex(100,0,0), bb.vertex(100,100,0), bb.vertex(0,100,0)]) + .loop([bb.vertex(-100,30,0), bb.vertex(200,30,0), bb.vertex(300,60,0), bb.vertex(-100,60,0)]).build(); + + let trs = A(shell.faces[0]); + console.log(trs); + +} + +test(); \ No newline at end of file