diff --git a/src/ThreeEditor/js/Editor.js b/src/ThreeEditor/js/Editor.js index 3223c1352..efb6fcc13 100644 --- a/src/ThreeEditor/js/Editor.js +++ b/src/ThreeEditor/js/Editor.js @@ -68,6 +68,7 @@ function Editor() { //YAPTIDE zones zoneAdded: new Signal(), zoneChanged: new Signal(), + zoneGeometryChanged: new Signal(), zoneRemoved: new Signal(), cameraAdded: new Signal(), diff --git a/src/ThreeEditor/js/Viewport.js b/src/ThreeEditor/js/Viewport.js index 1fc3462d0..2c95af9b5 100644 --- a/src/ThreeEditor/js/Viewport.js +++ b/src/ThreeEditor/js/Viewport.js @@ -29,6 +29,18 @@ export function Viewport( } let sceneViewHelpers = new THREE.Scene(); + let clippedScene = new THREE.Scene(); + + var skyColor = 0x00aaff; // Deep Sky Blue + var groundColor = 0xffaa00; // Orange + var intensity = 1; + + var light = new THREE.HemisphereLight(skyColor, groundColor, intensity); + light.name = 'HemisphereLight'; + + light.position.set(10000, 10000, 0); + clippedScene.add(light) + let container = new UIPanel(); container.setId('ViewPanel'); @@ -94,6 +106,9 @@ export function Viewport( }, set [planePosProperty](v) { + po.translateZ(v - globalPlane.constant); + console.log(v - globalPlane.constant, po.position); + globalPlane.constant = v; signals.viewportConfigChanged.dispatch({ name, globalPlaneConstant: v }); @@ -123,9 +138,113 @@ export function Viewport( gui.domElement.style.position = "absolute"; gui.domElement.style.top = "35px"; gui.domElement.style.right = "-5px"; + + + function createPlaneStencilGroup(geometry, plane, renderOrder) { + + const group = new THREE.Group(); + const baseMat = new THREE.MeshBasicMaterial(); + baseMat.depthWrite = false; + baseMat.depthTest = false; + baseMat.colorWrite = false; + baseMat.stencilWrite = true; + baseMat.stencilFunc = THREE.AlwaysStencilFunc; + + // back faces + const mat0 = baseMat.clone(); + mat0.side = THREE.BackSide; + mat0.clippingPlanes = [plane]; + mat0.stencilFail = THREE.IncrementWrapStencilOp; + mat0.stencilZFail = THREE.IncrementWrapStencilOp; + mat0.stencilZPass = THREE.IncrementWrapStencilOp; + + const mesh0 = new THREE.Mesh(geometry, mat0); + mesh0.renderOrder = renderOrder; + group.add(mesh0); + + // front faces + const mat1 = baseMat.clone(); + mat1.side = THREE.FrontSide; + mat1.clippingPlanes = [plane]; + mat1.stencilFail = THREE.DecrementWrapStencilOp; + mat1.stencilZFail = THREE.DecrementWrapStencilOp; + mat1.stencilZPass = THREE.DecrementWrapStencilOp; + + const mesh1 = new THREE.Mesh(geometry, mat1); + mesh1.renderOrder = renderOrder; + + group.add(mesh1); + + return group; + + } + + const planeGeom = new THREE.PlaneGeometry(10, 10); + + const clippedObjects = new THREE.Group(); + clippedScene.add(clippedObjects); + + + const poGroup = new THREE.Group(); + + + + zonesManager.children.forEach((zone) => { + const stencilGroup = createPlaneStencilGroup(zone.geometry, globalPlane, 1); + stencilGroup.name = zone.uuid; + clippedObjects.add(stencilGroup); + }); + + signals.zoneGeometryChanged.add(function (zone) { + clippedObjects.remove(clippedObjects.getObjectByName(zone.uuid)); + + const stencilGroup = createPlaneStencilGroup(zone.geometry, globalPlane, 1); + stencilGroup.name = zone.uuid; + clippedObjects.add(stencilGroup); + + }); + + // plane is clipped by the other clipping planes + const planeMat = + new THREE.MeshStandardMaterial({ + + color: 0x00ff00, + metalness: 0.1, + roughness: 0.75, + + stencilWrite: true, + stencilRef: 0, + stencilFunc: THREE.NotEqualStencilFunc, + stencilFail: THREE.ReplaceStencilOp, + stencilZFail: THREE.ReplaceStencilOp, + stencilZPass: THREE.ReplaceStencilOp, + + }); + const po = new THREE.Mesh(planeGeom, planeMat); + po.onAfterRender = function (renderer) { + + renderer.clearStencil(); + + }; + po.renderOrder = 1.1; + poGroup.add(po); + clippedScene.add(poGroup); + + globalPlane.coplanarPoint(po.position); + po.lookAt( + po.position.x - globalPlane.normal.x, + po.position.y - globalPlane.normal.y, + po.position.z - globalPlane.normal.z, + ); + po.translateZ(-.01) + + } + + + let cachedRenderer = null; function render(renderer = cachedRenderer) { @@ -147,6 +266,8 @@ export function Viewport( renderer.autoClear = false; + renderer.render(clippedScene, camera); + config.showZones && renderer.render(zonesManager, camera); renderer.clippingPlanes = []; // clear clipping planes for next renders @@ -528,7 +649,7 @@ export function Viewport( render(); }) - + signals.selectModeChanged.add((mode) => { //TODO: clicking on zones selects them if zoneSelectionMode is enabled }) diff --git a/src/ThreeEditor/util/CSG/CSGZone.ts b/src/ThreeEditor/util/CSG/CSGZone.ts index 430c33f89..46d8c2916 100644 --- a/src/ThreeEditor/util/CSG/CSGZone.ts +++ b/src/ThreeEditor/util/CSG/CSGZone.ts @@ -24,6 +24,7 @@ export class CSGZone extends THREE.Mesh { geometryChanged: Signal; sceneGraphChanged: Signal; zoneAdded: Signal; + zoneGeometryChanged: Signal; zoneRemoved: Signal; CSGManagerStateChanged: Signal; }; @@ -43,29 +44,29 @@ export class CSGZone extends THREE.Mesh { ) { super(); this.type = "Zone"; + this.editor = editor; + this.signals = editor.signals; this.name = name || "CSGZone"; this.material = new THREE.MeshNormalMaterial(); this.subscribedObjectsUuid = subscribedObjectsUuid || new Set(); this.unionOperations = unionOperations ? (() => { - // If operations are specified, we have to populate set of subscribed UUID's - subscribedObjectsUuid || - unionOperations.forEach((op1) => - op1 - .map((op2) => op2.object.uuid) - .forEach( - this.subscribedObjectsUuid.add, - this.subscribedObjectsUuid - ) - ); - return unionOperations; - })() + // If operations are specified, we have to populate set of subscribed UUID's + subscribedObjectsUuid || + unionOperations.forEach((op1) => + op1 + .map((op2) => op2.object.uuid) + .forEach( + this.subscribedObjectsUuid.add, + this.subscribedObjectsUuid + ) + ); + return unionOperations; + })() : []; // If operations are specified, we have to generate fist geometry manually. unionOperations && this.updateGeometry(); - this.editor = editor; - this.signals = editor.signals; this.signals.geometryChanged.add((object) => this.handleSignal(object)); this.signals.objectChanged.add((object) => this.handleSignal(object)); @@ -124,6 +125,7 @@ export class CSGZone extends THREE.Mesh { this.geometry = geometryResult; this.geometry.computeBoundingSphere(); this.updateMatrixWorld(true); + this.signals.zoneGeometryChanged.dispatch(this); console.timeEnd("CSGZone"); } @@ -209,11 +211,11 @@ export class CSGZone extends THREE.Mesh { let subscribedObjectsUuid = Array.isArray(data.subscribedObjectsUuid) ? new Set(data.subscribedObjectsUuid) : (() => { - throw Error( - "SubscribedObjectsId is not array" + - data.subscribedObjectsUuid - ); - })(); + throw Error( + "SubscribedObjectsId is not array" + + data.subscribedObjectsUuid + ); + })(); let zone = new CSGZone( editor,