feat(viewer): intermeidate step
This commit is contained in:
+664
-336
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -34,7 +34,8 @@
|
||||
<div class="twelve columns">
|
||||
<button onclick="v.sceneManager.zoomExtents()">Zoom Extents</button>
|
||||
<button onclick="v.postprocessing = !v.postprocessing">Postprocessing Toggle</button>
|
||||
<button onclick="v.sectionBox.toggleSectionBox()">Show Section Box</button>
|
||||
<button onclick="v.interactions.toggleSectionBox()">Toggle Section Box</button>
|
||||
<button onclick="v.interactions.test()">Test Section Box</button>
|
||||
</div>
|
||||
<div class="twelve columns">
|
||||
<input id="objectUrlInput" type="text" name="objectId" placeholder="Object Url" style="width:49%" value="https://staging.speckle.dev/streams/a75ab4f10f/objects/a59617590b0bec4e9b5ee487ee75b1a7"/>
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
<div class="twelve columns">
|
||||
<button onclick="v.sceneManager.zoomExtents()">Zoom Extents</button>
|
||||
<button onclick="v.postprocessing = !v.postprocessing">Postprocessing Toggle</button>
|
||||
<button onclick="v.sectionBox.toggleSectionBox()">Show Section Box</button>
|
||||
<button onclick="v.interactions.toggleSectionBox()">Toggle Section Box</button>
|
||||
<button onclick="v.interactions.test()">Test Section Box</button>
|
||||
</div>
|
||||
<div class="twelve columns">
|
||||
<input id="objectUrlInput" type="text" name="objectId" placeholder="Object Url" style="width:49%" value="https://staging.speckle.dev/streams/a75ab4f10f/objects/a59617590b0bec4e9b5ee487ee75b1a7"/>
|
||||
|
||||
@@ -32,4 +32,8 @@ export default class EventEmitter {
|
||||
|
||||
this._events[name].forEach( fireCallbacks )
|
||||
}
|
||||
|
||||
dispose(){
|
||||
this._events = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import * as THREE from 'three'
|
||||
|
||||
import SectionBox from './SectionBox'
|
||||
import SectionBox2 from './SectionBox2'
|
||||
import SelectionHelper from './SelectionHelper'
|
||||
|
||||
export default class InteractionHandler {
|
||||
|
||||
constructor( viewer ) {
|
||||
this.viewer = viewer
|
||||
|
||||
// this.sectionBox = new SectionBox( this.viewer )
|
||||
this.sectionBoxEnabled = false
|
||||
|
||||
this.selectionHelper = new SelectionHelper( this.viewer, this.viewer.sceneManager.userObjects )
|
||||
this.selectionMaterial = new THREE.MeshLambertMaterial( { color: 0x0B55D2, emissive: 0x0B55D2, side: THREE.DoubleSide } )
|
||||
// this.selectionMaterial.clippingPlanes = this.sectionBox.planes.map( c => c.plane )
|
||||
this.selectionEdgesMaterial = new THREE.LineBasicMaterial( { color: 0x23F3BD } )
|
||||
// this.selectionEdgesMaterial.clippingPlanes = this.sectionBox.planes.map( c => c.plane )
|
||||
|
||||
this.selectedObjects = new THREE.Group()
|
||||
this.viewer.scene.add( this.selectedObjects )
|
||||
this.selectedObjects.renderOrder = 1000
|
||||
|
||||
this.selectionHelper.on( 'object-doubleclicked', this._handleDoubleClick.bind( this ) )
|
||||
this.selectionHelper.on( 'object-clicked', this._handleSelect.bind( this ) )
|
||||
|
||||
}
|
||||
|
||||
_handleDoubleClick( objs ) {
|
||||
if ( !objs || objs.length === 0 ) this.viewer.sceneManager.zoomExtents()
|
||||
else this.viewer.sceneManager.zoomToObject( objs[0].object )
|
||||
this.viewer.needsRender = true
|
||||
}
|
||||
|
||||
_handleSelect( obj ) {
|
||||
if ( obj.length === 0 ) {
|
||||
this.deselectObjects()
|
||||
return
|
||||
}
|
||||
|
||||
if ( !this.selectionHelper.multiSelect ) this.deselectObjects()
|
||||
|
||||
let mesh = new THREE.Mesh( obj[0].object.geometry, this.selectionMaterial )
|
||||
this.selectedObjects.add( mesh )
|
||||
|
||||
const bbox = new THREE.Box3().setFromObject( mesh )
|
||||
const size = bbox.getSize( new THREE.Vector3() )
|
||||
bbox.expandByVector( size.multiplyScalar( 0.1 ) )
|
||||
const helper = new THREE.Box3Helper( bbox, 0x29308C )
|
||||
helper.material = this.selectionEdgesMaterial
|
||||
// TODO: if selection box is active, add planes to helper material clipping
|
||||
this.selectedObjects.add( helper )
|
||||
|
||||
this.viewer.needsRender = true
|
||||
}
|
||||
|
||||
deselectObjects() {
|
||||
this.selectedObjects.clear()
|
||||
this.viewer.needsRender = true
|
||||
}
|
||||
|
||||
toggleSectionBox() {
|
||||
this.sectionBoxEnabled = !this.sectionBoxEnabled
|
||||
if ( this.sectionBoxEnabled ) {
|
||||
this.showSelectionBox()
|
||||
} else {
|
||||
this.hideSelectionBox()
|
||||
}
|
||||
}
|
||||
|
||||
showSelectionBox() {
|
||||
this.viewer.renderer.localClippingEnabled = true
|
||||
|
||||
let bbox = null
|
||||
let setFromSelection = false
|
||||
if ( this.selectedObjects.children.length > 0 ) {
|
||||
bbox = new THREE.Box3().setFromObject( this.selectedObjects.children[0] )
|
||||
setFromSelection = true
|
||||
} else {
|
||||
bbox = this.viewer.sceneManager.getSceneBoundingBox()
|
||||
}
|
||||
this.viewer.sceneManager.zoomToBox( bbox )
|
||||
this.sectionBox.setFromBbox( bbox, setFromSelection ? 0.3 : 0.1 )
|
||||
this.sectionBox.display.visible = true
|
||||
this.viewer.needsRender = true
|
||||
this.sectionBoxEnabled = true
|
||||
}
|
||||
|
||||
hideSelectionBox() {
|
||||
this.viewer.renderer.localClippingEnabled = false
|
||||
this.sectionBox.display.visible = false
|
||||
this.viewer.needsRender = true
|
||||
this.sectionBoxEnabled = false
|
||||
}
|
||||
|
||||
test() {
|
||||
let tt = new SectionBox2( this.viewer )
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export default class SceneObjectManager {
|
||||
// Is it a transparent material?
|
||||
if ( renderMat.opacity !== 1 ) {
|
||||
let material = this.transparentMaterial.clone()
|
||||
material.clippingPlanes = this.viewer.sectionBox.planes.map( p => p.plane )
|
||||
// material.clippingPlanes = this.viewer.interactions.sectionBox.planes.map( p => p.plane )
|
||||
|
||||
material.color = color
|
||||
material.opacity = renderMat.opacity !== 0 ? renderMat.opacity : 0.2
|
||||
@@ -88,7 +88,7 @@ export default class SceneObjectManager {
|
||||
// It's not a transparent material!
|
||||
} else {
|
||||
let material = this.solidMaterial.clone()
|
||||
material.clippingPlanes = this.viewer.sectionBox.planes.map( p => p.plane )
|
||||
// material.clippingPlanes = this.viewer.interactions.sectionBox.planes.map( p => p.plane )
|
||||
|
||||
material.color = color
|
||||
material.metalness = renderMat.metalness
|
||||
@@ -99,7 +99,7 @@ export default class SceneObjectManager {
|
||||
} else {
|
||||
// If we don't have defined material, just use the default
|
||||
let material = this.solidMaterial.clone()
|
||||
material.clippingPlanes = this.viewer.sectionBox.planes.map( p => p.plane )
|
||||
// material.clippingPlanes = this.viewer.interactions.sectionBox.planes.map( p => p.plane )
|
||||
|
||||
this.addSolid( wrapper, material )
|
||||
}
|
||||
@@ -164,7 +164,8 @@ export default class SceneObjectManager {
|
||||
this.lineObjects.clear()
|
||||
this.pointObjects.clear()
|
||||
|
||||
this.viewer.selectionHelper.unselect()
|
||||
this.viewer.interactions.deselectObjects()
|
||||
this.viewer.interactions.hideSelectionBox()
|
||||
this.objectIds = []
|
||||
|
||||
this._postLoadFunction()
|
||||
@@ -173,10 +174,15 @@ export default class SceneObjectManager {
|
||||
_postLoadFunction() {
|
||||
this.zoomExtents()
|
||||
this.viewer.reflectionsNeedUpdate = true
|
||||
}
|
||||
|
||||
let sceneBox = new THREE.Box3().setFromObject( this.viewer.sceneManager.userObjects )
|
||||
|
||||
this.viewer.sectionBox.setFromBbox( sceneBox )
|
||||
getSceneBoundingBox() {
|
||||
if ( this.objects.length === 0 ) {
|
||||
let box = new THREE.Box3( new THREE.Vector3( -1,-1,-1 ), new THREE.Vector3( 1,1,1 ) )
|
||||
return box
|
||||
}
|
||||
let box = new THREE.Box3().setFromObject( this.userObjects )
|
||||
return box
|
||||
}
|
||||
|
||||
zoomToObject( target ) {
|
||||
@@ -185,14 +191,16 @@ export default class SceneObjectManager {
|
||||
}
|
||||
|
||||
zoomExtents() {
|
||||
let bboxTarget = this.userObjects
|
||||
if ( this.objects.length === 0 ) {
|
||||
let box = new THREE.Box3( new THREE.Vector3( -1,-1,-1 ), new THREE.Vector3( 1,1,1 ) )
|
||||
this.zoomToBox( box )
|
||||
this.viewer.controls.setBoundary( box )
|
||||
return
|
||||
}
|
||||
let box = new THREE.Box3().setFromObject( bboxTarget )
|
||||
|
||||
let box = new THREE.Box3().setFromObject( this.userObjects )
|
||||
this.zoomToBox( box )
|
||||
this.viewer.controls.setBoundary( box )
|
||||
}
|
||||
|
||||
zoomToBox( box ) {
|
||||
@@ -201,6 +209,7 @@ export default class SceneObjectManager {
|
||||
const size = box.getSize( new THREE.Vector3() )
|
||||
let target = new THREE.Sphere()
|
||||
box.getBoundingSphere( target )
|
||||
target.radius = target.radius * fitOffset
|
||||
|
||||
this.viewer.controls.fitToSphere( target, true )
|
||||
|
||||
|
||||
@@ -19,11 +19,14 @@ const edges = [
|
||||
]
|
||||
|
||||
export default class SectionBox {
|
||||
constructor( viewer, _vis ){
|
||||
constructor( viewer, _vis ) {
|
||||
//defaults to invisible
|
||||
let vis = _vis || false
|
||||
|
||||
this.viewer = viewer
|
||||
this.orbiting = false
|
||||
this.viewer.controls.addEventListener( 'wake', () => { this.orbiting = true } )
|
||||
this.viewer.controls.addEventListener( 'controlend', () => { this.orbiting = false } )
|
||||
|
||||
this.display = new THREE.Group()
|
||||
this.display.visible = vis
|
||||
@@ -39,34 +42,31 @@ export default class SectionBox {
|
||||
this.viewer.scene.add( this.display )
|
||||
|
||||
// basic display of the section box
|
||||
this.boxMaterial = new THREE.MeshBasicMaterial( )
|
||||
this.boxMaterial = new THREE.MeshStandardMaterial( {
|
||||
transparent: true,
|
||||
opacity: 0.1,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0x0A66FF,
|
||||
metalness: 0.01,
|
||||
roughness: 0.75,
|
||||
} )
|
||||
|
||||
// the box itself
|
||||
this.boxGeo = new THREE.BoxGeometry( 2,2,2 )
|
||||
this.boxMesh = new THREE.Mesh( this.boxGeo, this.boxMaterial )
|
||||
this.boxMesh.visible = false
|
||||
|
||||
this.boxMesh.geometry.computeBoundingBox()
|
||||
this.boxMesh.geometry.computeBoundingSphere()
|
||||
this.displayBox.add( this.boxMesh )
|
||||
|
||||
this.lineMaterial = new THREE.LineDashedMaterial( {
|
||||
color: 0x0A66FF,
|
||||
linewidth: 4,
|
||||
} )
|
||||
// const edges = new THREE.EdgesGeometry( this.boxGeo )
|
||||
// this.line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xDF66FF } ) )
|
||||
|
||||
// show box edges
|
||||
edges.map( val => {
|
||||
let pts = [ this.boxGeo.vertices[val[0]].clone(),
|
||||
this.boxGeo.vertices[val[1]].clone() ]
|
||||
let geo = new THREE.BufferGeometry().setFromPoints( pts )
|
||||
let line = new THREE.Line( geo, this.lineMaterial )
|
||||
this.displayEdges.add( line )
|
||||
} )
|
||||
|
||||
// normal of plane being hovered
|
||||
this.hoverPlane = new THREE.Vector3()
|
||||
|
||||
this.selectionHelper = new SelectionHelper( this.viewer, { subset:this.displayBox, hover:true } )
|
||||
this.selectionHelper = new SelectionHelper( this.viewer, { subset: this.displayBox, hover:true } )
|
||||
|
||||
// pointer position
|
||||
this.pointer = new THREE.Vector3()
|
||||
@@ -78,36 +78,34 @@ export default class SectionBox {
|
||||
this.planes = [
|
||||
{
|
||||
axis: '+x', // right, x positive
|
||||
plane:new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 1 ),
|
||||
plane: new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ),
|
||||
indices: [ 5,4,6,7 ],
|
||||
},{
|
||||
axis: '-x', // left, x negative
|
||||
plane: new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), 1 ),
|
||||
plane: new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), 0 ),
|
||||
indices: [ 0,1,3,2 ],
|
||||
},{
|
||||
axis: '+y', // out, y positive
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), 1 ),
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), 0 ),
|
||||
indices: [ 2,3,6,7 ],
|
||||
},{
|
||||
axis: '-y', // in, y negative
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), 1 ),
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), 0 ),
|
||||
indices: [ 5,4,1,0 ],
|
||||
},{
|
||||
axis: '+z', // up, z positive
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, 0, 1 ), 1 ),
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, 0, 1 ), 0 ),
|
||||
indices: [ 1,3,6,4 ],
|
||||
},{
|
||||
axis: '-z', // down, z negative
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), 1 ),
|
||||
plane:new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), 0 ),
|
||||
indices: [ 0,2,7,5 ],
|
||||
} ]
|
||||
|
||||
// plane helpers
|
||||
// this.planeHelpers = this.planes.map( p => this.display.add(new THREE.PlaneHelper( p.plane, 2, 0x000000 ) ));
|
||||
|
||||
// adds clipping planes to all materials
|
||||
// better to add clipping planes to renderer
|
||||
this.viewer.renderer.localClippingEnabled = true
|
||||
// this.planes.forEach( p => {
|
||||
// const helper = new THREE.PlaneHelper( p.plane, 1, 0xffff00 )
|
||||
// this.display.add( helper )
|
||||
// } )
|
||||
|
||||
this.viewer.sceneManager.objects.forEach( obj => {
|
||||
obj.material.clippingPlanes = this.planes.map( c => c.plane )
|
||||
@@ -117,37 +115,10 @@ export default class SectionBox {
|
||||
transparent: true,
|
||||
opacity: 0.1,
|
||||
color: 0x0A66FF,
|
||||
// color: 0xE91E63,
|
||||
metalness: 0.1,
|
||||
roughness: 0.75,
|
||||
} )
|
||||
|
||||
// hovered event handler
|
||||
this.selectionHelper.on( 'hovered', ( obj, e ) => {
|
||||
if ( !this.display.visible ) return
|
||||
if ( obj.length === 0 && !this.dragging ) {
|
||||
this.displayHover.clear()
|
||||
this.hoverPlane = new THREE.Vector3()
|
||||
this.viewer.controls.enabled = true
|
||||
this.viewer.renderer.domElement.style.cursor = 'default'
|
||||
return
|
||||
} else if ( this.dragging ){
|
||||
return
|
||||
}
|
||||
|
||||
this.viewer.renderer.domElement.style.cursor = 'pointer'
|
||||
|
||||
let index = this.planes.findIndex( p => p.plane.normal.equals( obj[0].face.normal.clone().negate() ) )
|
||||
if ( index < 0 ) return // this should never be the case?
|
||||
let planeObj = this.planes[index]
|
||||
let plane = planeObj.plane
|
||||
|
||||
if ( plane.normal.equals( this.hoverPlane ) ) return
|
||||
this.hoverPlane = plane.normal.clone()
|
||||
|
||||
this.updateHover( planeObj )
|
||||
} )
|
||||
|
||||
// Selection Helper seems unecessary for this type of thing
|
||||
this.viewer.renderer.domElement.addEventListener( 'pointerup', ( e ) => {
|
||||
this.pointer = new THREE.Vector3()
|
||||
@@ -156,14 +127,67 @@ export default class SectionBox {
|
||||
this.dragging = false
|
||||
} )
|
||||
|
||||
let cuttingPlane = null
|
||||
let hoverPlane = null
|
||||
|
||||
// hovered event handler
|
||||
this.selectionHelper.on( 'hovered', ( obj, e ) => {
|
||||
if ( this.orbiting ) return
|
||||
|
||||
if ( obj.length === 0 && !this.dragging ) {
|
||||
this.viewer.controls.enabled = true
|
||||
this.displayHover.clear()
|
||||
this.hoverPlane = new THREE.Vector3()
|
||||
this.viewer.controls.enabled = true
|
||||
this.viewer.renderer.domElement.style.cursor = 'default'
|
||||
return
|
||||
} else if ( this.dragging ) {
|
||||
return
|
||||
}
|
||||
|
||||
this.viewer.controls.enabled = false
|
||||
this.viewer.renderer.domElement.style.cursor = 'pointer'
|
||||
|
||||
switch ( obj[0].faceIndex ) {
|
||||
case 0: case 1:
|
||||
cuttingPlane = this.planes[0]
|
||||
hoverPlane = this.planes[1]
|
||||
break
|
||||
case 2: case 3:
|
||||
cuttingPlane = this.planes[1]
|
||||
hoverPlane = this.planes[0]
|
||||
break
|
||||
case 4: case 5:
|
||||
cuttingPlane = this.planes[2]
|
||||
hoverPlane = this.planes[3]
|
||||
break
|
||||
case 6: case 7:
|
||||
cuttingPlane = this.planes[3]
|
||||
hoverPlane = this.planes[2]
|
||||
break
|
||||
case 8: case 9:
|
||||
cuttingPlane = this.planes[4]
|
||||
hoverPlane = this.planes[5]
|
||||
break
|
||||
case 10: case 11:
|
||||
cuttingPlane = this.planes[5]
|
||||
hoverPlane = this.planes[4]
|
||||
break
|
||||
}
|
||||
|
||||
// this.hoverPlane = plane.normal.clone()
|
||||
this.updateHover( hoverPlane )
|
||||
} )
|
||||
|
||||
// get screen space vector of plane normal
|
||||
// project mouse displacement vector onto it
|
||||
// move plane by that much
|
||||
this.selectionHelper.on( 'object-drag', ( obj, e ) => {
|
||||
if ( this.orbiting ) return
|
||||
if ( !this.display.visible ) return
|
||||
|
||||
// exit if we don't have a valid hoverPlane
|
||||
if ( this.hoverPlane.equals( new THREE.Vector3() ) ) return
|
||||
// if ( this.hoverPlane.equals( new THREE.Vector3() ) ) return
|
||||
// exit if we're clicking on nothing
|
||||
if ( !obj.length && !this.dragging ) return
|
||||
|
||||
@@ -172,9 +196,7 @@ export default class SectionBox {
|
||||
|
||||
this.dragging = true
|
||||
|
||||
let index = this.planes.findIndex( p => p.plane.normal.equals( this.hoverPlane ) )
|
||||
let planeObj = this.planes[index]
|
||||
let plane = planeObj.plane
|
||||
let plane = hoverPlane.plane
|
||||
|
||||
if ( this.pointer.equals( new THREE.Vector3() ) ) {
|
||||
this.pointer = new THREE.Vector3( e.x, e.y, 0.0 )
|
||||
@@ -199,55 +221,61 @@ export default class SectionBox {
|
||||
d = d * zoom
|
||||
|
||||
// limit plane from crossing it's pair
|
||||
let hoverOpp = this.hoverPlane.clone().negate()
|
||||
let indexOpp = this.planes.findIndex( p => p.plane.normal.equals( hoverOpp ) )
|
||||
let planeObjOpp = this.planes[indexOpp]
|
||||
let dist = planeObj.plane.constant + planeObjOpp.plane.constant
|
||||
|
||||
let planeObjOpp = cuttingPlane
|
||||
let dist = hoverPlane.plane.constant + planeObjOpp.plane.constant
|
||||
let displacement = new THREE.Vector3( d,d,d ).multiply( plane.normal )
|
||||
// are we moving towards the limiting plane?
|
||||
let dot = displacement.clone().normalize().dot( plane.normal )
|
||||
if ( dist < 0.1 && dot < 0 ) return
|
||||
|
||||
// if displacement + padding is greater than limit,
|
||||
// and we're moving towards the limiting plane
|
||||
if ( dist < d && dot > 0 ) {
|
||||
d = dist * 0.001
|
||||
displacement = new THREE.Vector3( d,d,d ).multiply( plane.normal )
|
||||
}
|
||||
|
||||
plane.translate( displacement )
|
||||
this.updateBoxFace( planeObj, displacement )
|
||||
this.updateHover( planeObj )
|
||||
cuttingPlane.plane.translate( displacement )
|
||||
this.updateBoxFace( hoverPlane, displacement )
|
||||
this.updateHover( hoverPlane )
|
||||
|
||||
this.viewer.needsRender = true
|
||||
} )
|
||||
}
|
||||
|
||||
// boxMesh = bbox
|
||||
setFromBbox( bbox ){
|
||||
setFromBbox( bbox, offset ){
|
||||
bbox = bbox.clone()
|
||||
|
||||
// add a little padding to the box
|
||||
bbox.max.addScalar( 10 )
|
||||
bbox.min.subScalar( 10 )
|
||||
for ( let p of this.planes ) {
|
||||
// reset plane
|
||||
// p.plane.set(p.plane.normal, 1)
|
||||
let c = 0
|
||||
// planes point inwards - if negative select max part of bbox
|
||||
if ( p.plane.normal.dot( new THREE.Vector3( 1,1,1 ) ) > 0 ) {
|
||||
c = p.plane.normal.clone().multiply( bbox.min )
|
||||
} else {
|
||||
c = p.plane.normal.clone().multiply( bbox.max )
|
||||
}
|
||||
let diff = c.length() - p.plane.constant
|
||||
const size = bbox.getSize( new THREE.Vector3() )
|
||||
if ( offset )
|
||||
bbox.expandByVector( size.multiplyScalar( offset ) )
|
||||
|
||||
// displacement
|
||||
let d = p.plane.normal.clone().negate().multiplyScalar( diff )
|
||||
const dimensions = new THREE.Vector3().subVectors( bbox.max, bbox.min )
|
||||
const boxGeo = new THREE.BoxGeometry( dimensions.x, dimensions.y, dimensions.z )
|
||||
const matrix = new THREE.Matrix4().setPosition( dimensions.addVectors( bbox.min, bbox.max ).multiplyScalar( 0.5 ) )
|
||||
boxGeo.applyMatrix4( matrix )
|
||||
|
||||
this.updateBoxFace( p, d )
|
||||
p.plane.translate( d )
|
||||
let k = 0
|
||||
for ( let i = 0; i < boxGeo.faces.length; i += 2 ) {
|
||||
let plane = this.planes[k]
|
||||
let face = boxGeo.faces[i]
|
||||
|
||||
plane.plane.setFromCoplanarPoints( boxGeo.vertices[face.c], boxGeo.vertices[face.b], boxGeo.vertices[face.a] )
|
||||
k++
|
||||
}
|
||||
|
||||
// update box geometry
|
||||
for ( let i = 0; i< boxGeo.vertices.length; i++ ) {
|
||||
let vert = boxGeo.vertices[i]
|
||||
this.boxMesh.geometry.vertices[i].set( vert.x, vert.y, vert.z )
|
||||
}
|
||||
|
||||
this.boxMesh.geometry.verticesNeedUpdate = true
|
||||
this.boxMesh.geometry.computeBoundingBox()
|
||||
this.boxMesh.geometry.computeBoundingSphere()
|
||||
|
||||
const edges = new THREE.EdgesGeometry( this.boxMesh.geometry )
|
||||
const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xffffff } ) )
|
||||
this.displayEdges.add( line )
|
||||
}
|
||||
|
||||
|
||||
updateBoxFace( planeObj, displacement ){
|
||||
this.boxMesh.geometry.vertices.map( ( v,i ) => {
|
||||
if ( !planeObj.indices.includes( i ) ) return
|
||||
@@ -258,25 +286,7 @@ export default class SectionBox {
|
||||
this.boxMesh.geometry.computeBoundingBox()
|
||||
this.boxMesh.geometry.computeBoundingSphere()
|
||||
|
||||
this.updateEdges()
|
||||
}
|
||||
|
||||
updateEdges(){
|
||||
this.displayEdges.clear()
|
||||
edges.map( val => {
|
||||
let ptA = this.boxMesh.geometry.vertices[val[0]].clone()
|
||||
let ptB = this.boxMesh.geometry.vertices[val[1]].clone()
|
||||
// translation
|
||||
ptA.add( this.boxMesh.position )
|
||||
ptB.add( this.boxMesh.position )
|
||||
this.drawLine( [ ptA, ptB ] )
|
||||
} )
|
||||
}
|
||||
|
||||
drawLine( pts ){
|
||||
let geo = new THREE.BufferGeometry().setFromPoints( pts )
|
||||
let line = new THREE.Line( geo, this.lineMaterial )
|
||||
this.displayEdges.add( line )
|
||||
// this.updateEdges()
|
||||
}
|
||||
|
||||
updateHover( planeObj ){
|
||||
@@ -323,6 +333,7 @@ export default class SectionBox {
|
||||
|
||||
let hoverMesh = new THREE.Mesh( hoverGeo, this.hoverMat )
|
||||
this.displayHover.add( hoverMesh )
|
||||
this.viewer.needsRender = true
|
||||
}
|
||||
|
||||
toggleSectionBox( _bool ){
|
||||
@@ -330,8 +341,5 @@ export default class SectionBox {
|
||||
this.visible = bool
|
||||
this.display.visible = bool
|
||||
this.viewer.needsRender = true
|
||||
|
||||
// what's the tradeoff for having the clipping planes in material vs in the renderer?
|
||||
// this.viewer.renderer.clippingPlanes = bool ? this.planes.reduce((p,c) => [...p,c.plane],[]) : []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
import * as THREE from 'three'
|
||||
import SelectionHelper from './SelectionHelper'
|
||||
import { FaceNormalsHelper } from 'three/examples/jsm/helpers/FaceNormalsHelper.js'
|
||||
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js'
|
||||
|
||||
export default class SectionBox {
|
||||
|
||||
constructor( viewer, bbox ) {
|
||||
this.viewer = viewer
|
||||
|
||||
this.orbiting = false
|
||||
this.viewer.controls.addEventListener( 'wake', () => { this.orbiting = true } )
|
||||
this.viewer.controls.addEventListener( 'controlend', () => { this.orbiting = false } )
|
||||
|
||||
this.box = bbox || this.viewer.sceneManager.getSceneBoundingBox()
|
||||
const dimensions = new THREE.Vector3().subVectors( this.box.max, this.box.min )
|
||||
this.boxGeo = new THREE.BoxGeometry( dimensions.x, dimensions.y, dimensions.z )
|
||||
|
||||
const matrix = new THREE.Matrix4().setPosition( dimensions.addVectors( this.box.min, this.box.max ).multiplyScalar( 0.5 ) )
|
||||
this.boxGeo.applyMatrix4( matrix )
|
||||
this.boxMesh = new THREE.Mesh( this.boxGeo, new THREE.MeshBasicMaterial( {
|
||||
transparent: true,
|
||||
opacity: 0.31,
|
||||
wireframe: true,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0x0A66FF
|
||||
} ) )
|
||||
|
||||
const plane = new THREE.PlaneGeometry( 1, 1 )
|
||||
this.hoverPlane = new THREE.Mesh( plane, new THREE.MeshStandardMaterial( {
|
||||
transparent: true,
|
||||
side: THREE.DoubleSide,
|
||||
opacity: 0.3,
|
||||
color: 0x23F3BD,
|
||||
metalness: 0.1,
|
||||
roughness: 0.75,
|
||||
} ) )
|
||||
|
||||
this.display = new THREE.Group()
|
||||
this.display.add( this.boxMesh )
|
||||
this.boxMesh.attach( this.hoverPlane )
|
||||
this.display.add( this.hoverPlane )
|
||||
|
||||
this.viewer.scene.add( this.display )
|
||||
|
||||
|
||||
let vertex = this.boxGeo.vertices[ 5 ].clone().addScalar( 0.1 )
|
||||
// vertex.addScalar( 0.1 )
|
||||
let sphereG = new THREE.SphereGeometry( 0.001 )
|
||||
this.gizmoSphere = new THREE.Mesh( sphereG, new THREE.MeshBasicMaterial( 0x29308C ) )
|
||||
this.gizmoSphere.position.copy( vertex )
|
||||
this.display.add( this.gizmoSphere )
|
||||
|
||||
this.boxMesh.userData.planes = []
|
||||
this.boxMesh.userData.indices = []
|
||||
this.planes = []
|
||||
|
||||
// this.normalHelper = new FaceNormalsHelper( this.boxMesh, 2, 0x00ff00, 1 )
|
||||
// this.display.add( this.normalHelper )
|
||||
|
||||
this.controls = new TransformControls( this.viewer.camera, this.viewer.renderer.domElement )
|
||||
this.controls.setSize( 0.5 )
|
||||
this.controls.attach( this.gizmoSphere )
|
||||
this.display.add( this.controls )
|
||||
|
||||
this.planeControls = new TransformControls( this.viewer.camera, this.viewer.renderer.domElement )
|
||||
// this.planeControls.attach( this.hoverPlane )
|
||||
// this.planeControls.visible = false
|
||||
this.display.add( this.planeControls )
|
||||
|
||||
let prevGizmoPos = this.gizmoSphere.position.clone()
|
||||
this.controls.addEventListener( 'change', ( event ) => {
|
||||
prevGizmoPos.sub( this.gizmoSphere.position )
|
||||
this.boxMesh.translateX( -prevGizmoPos.x )
|
||||
this.boxMesh.translateY( -prevGizmoPos.y )
|
||||
this.boxMesh.translateZ( -prevGizmoPos.z )
|
||||
|
||||
prevGizmoPos = this.gizmoSphere.position.clone()
|
||||
this.setFromBox( new THREE.Box3().setFromObject( this.boxMesh ) )
|
||||
this.viewer.render()
|
||||
} )
|
||||
|
||||
this.controls.addEventListener( 'dragging-changed', ( event ) => {
|
||||
this.viewer.controls.enabled = !event.value
|
||||
// if ( this.viewer.controls.enabled ) this.viewer.sceneManager.zoomToObject( this.boxMesh )
|
||||
} )
|
||||
|
||||
for ( let i = 0; i < this.boxGeo.faces.length; i += 2 ) {
|
||||
let face = this.boxGeo.faces[i]
|
||||
let pairFace = this.boxGeo.faces[i+1]
|
||||
let plane = new THREE.Plane()
|
||||
plane.setFromCoplanarPoints( this.boxGeo.vertices[face.c], this.boxGeo.vertices[face.b], this.boxGeo.vertices[face.a] ) // invert pts
|
||||
|
||||
const helper = new THREE.PlaneHelper( plane, 1, 0xffff00 )
|
||||
this.display.add( helper )
|
||||
|
||||
// adding it twice for ease of use
|
||||
this.boxMesh.userData.planes.push( plane )
|
||||
this.boxMesh.userData.planes.push( plane )
|
||||
|
||||
this.boxMesh.userData.indices.push( [ face.a, face.b, face.c, pairFace.b ] )
|
||||
this.boxMesh.userData.indices.push( [ face.a, face.b, face.c, pairFace.b ] )
|
||||
|
||||
this.planes.push( plane )
|
||||
}
|
||||
|
||||
this.selectionHelper = new SelectionHelper( this.viewer, { subset: this.boxMesh, hover: true } )
|
||||
|
||||
let prevIndex = -1
|
||||
let prevPointer = new THREE.Vector3()
|
||||
|
||||
document.addEventListener( 'pointerup', ( e ) => {
|
||||
this.viewer.controls.enabled = true
|
||||
if ( this.dragging ) {
|
||||
this.viewer.sceneManager.zoomToObject( this.boxMesh )
|
||||
}
|
||||
this.dragging = false
|
||||
this.viewer.renderer.domElement.style.cursor = 'default'
|
||||
prevIndex = -1
|
||||
prevPointer = new THREE.Vector3()
|
||||
} )
|
||||
|
||||
// let faceIndex
|
||||
this.selectionHelper.on( 'hovered', ( obj, e ) => {
|
||||
if ( obj.length === 0 && !this.dragging ) {
|
||||
this.viewer.renderer.domElement.style.cursor = 'default'
|
||||
this.hoverPlane.visible = false
|
||||
this.planeControls.detach()
|
||||
this.viewer.controls.enabled = true
|
||||
this.viewer.needsRender = true
|
||||
prevIndex = -1
|
||||
return
|
||||
}
|
||||
if ( this.orbiting ) return
|
||||
if ( this.dragging ) return
|
||||
|
||||
this.hoverPlane.visible = true
|
||||
|
||||
this.viewer.renderer.domElement.style.cursor = 'pointer'
|
||||
let centre = new THREE.Vector3()
|
||||
for ( let i = 0; i < 4; i++ ) {
|
||||
let vertex = this.boxGeo.vertices[ obj[0].object.userData.indices[ obj[0].faceIndex ][i] ].clone()
|
||||
let vertexClone = vertex.clone()
|
||||
vertex.applyMatrix4( this.boxMesh.matrixWorld )
|
||||
centre.add( vertex )
|
||||
this.hoverPlane.geometry.vertices[i].set( vertexClone.x / 4, vertexClone.y /4 , vertexClone.z/4 )
|
||||
}
|
||||
centre.multiplyScalar( 0.25 )
|
||||
this.hoverPlane.position.copy( centre )
|
||||
this.hoverPlane.geometry.verticesNeedUpdate = true
|
||||
this.hoverPlane.geometry.computeBoundingBox()
|
||||
this.hoverPlane.geometry.computeBoundingSphere()
|
||||
|
||||
this.planeControls.attach( this.hoverPlane )
|
||||
|
||||
if ( obj[0].faceIndex !== prevIndex ){
|
||||
this.viewer.needsRender = true
|
||||
prevIndex = obj[0].faceIndex
|
||||
}
|
||||
} )
|
||||
|
||||
this.selectionHelper.on( 'object-drag', ( obj, e ) => {
|
||||
if ( this.orbiting || !this.display.visible ) return
|
||||
if ( prevIndex === -1 ) return
|
||||
|
||||
this.dragging = true
|
||||
this.viewer.renderer.domElement.style.cursor = 'move'
|
||||
this.viewer.controls.enabled = false
|
||||
|
||||
let plane = this.boxMesh.userData.planes[ prevIndex ]
|
||||
let normal = plane.normal.clone()
|
||||
this.viewer.camera.updateMatrixWorld()
|
||||
normal.negate().project( this.viewer.camera )
|
||||
normal.setComponent( 2, 0 ).normalize()
|
||||
|
||||
if ( prevPointer.equals( new THREE.Vector3() ) ) prevPointer = new THREE.Vector3( e.x, e.y, 0 )
|
||||
|
||||
let currentPointer = new THREE.Vector3( e.x, e.y, 0 )
|
||||
let mouseDeltaVector = prevPointer.clone().sub( currentPointer )
|
||||
|
||||
let dot = normal.dot( mouseDeltaVector )
|
||||
|
||||
const bbox = new THREE.Box3().setFromObject( this.boxMesh )
|
||||
const dims = new THREE.Vector3().subVectors( bbox.max, bbox.min )
|
||||
if ( dot > 0 && ( dims.x < 0.2 || dims.y < 0.2 || dims.z < 0.2 ) ) return
|
||||
|
||||
let zoom = this.viewer.camera.getWorldPosition( new THREE.Vector3() ).sub( new THREE.Vector3() ).length()
|
||||
zoom *= 0.5
|
||||
dot *= zoom
|
||||
|
||||
let displacement = new THREE.Vector3( dot, dot, dot ).multiply( plane.normal )
|
||||
|
||||
plane.translate( displacement )
|
||||
|
||||
let indices = this.boxMesh.userData.indices[ prevIndex ]
|
||||
for ( let i = 0; i < 4; i++ ) {
|
||||
let index = indices[i]
|
||||
this.boxMesh.geometry.vertices[index].add( displacement )
|
||||
this.hoverPlane.geometry.vertices[i].add( displacement )
|
||||
}
|
||||
|
||||
this.boxMesh.geometry.verticesNeedUpdate = true
|
||||
this.boxMesh.geometry.computeBoundingBox()
|
||||
this.boxMesh.geometry.computeBoundingSphere()
|
||||
this.hoverPlane.geometry.verticesNeedUpdate = true
|
||||
this.hoverPlane.geometry.computeBoundingBox()
|
||||
this.hoverPlane.geometry.computeBoundingSphere()
|
||||
|
||||
let gizmoPos = this.boxGeo.vertices[ 5 ].clone()
|
||||
gizmoPos.addScalar( 0.1 )
|
||||
gizmoPos.applyMatrix4( this.boxMesh.matrixWorld )
|
||||
this.gizmoSphere.position.copy( gizmoPos )
|
||||
prevGizmoPos = gizmoPos
|
||||
|
||||
this.viewer.needsRender = true
|
||||
prevPointer = currentPointer.clone()
|
||||
} )
|
||||
}
|
||||
|
||||
setFromBox( box ) {
|
||||
const dimensions = new THREE.Vector3().subVectors( box.max, box.min )
|
||||
let boxGeo = new THREE.BoxGeometry( dimensions.x, dimensions.y, dimensions.z )
|
||||
|
||||
const matrix = new THREE.Matrix4().setPosition( dimensions.addVectors( box.min, box.max ).multiplyScalar( 0.5 ) )
|
||||
boxGeo.applyMatrix4( matrix )
|
||||
|
||||
for ( let i = 0; i < this.boxGeo.faces.length; i += 2 ) {
|
||||
let face = boxGeo.faces[i]
|
||||
let plane = this.boxMesh.userData.planes[i]
|
||||
plane.setFromCoplanarPoints( boxGeo.vertices[face.c], boxGeo.vertices[face.b], boxGeo.vertices[face.a] ) // invert pts
|
||||
}
|
||||
|
||||
this.boxMesh.geometry.verticesNeedUpdate = true
|
||||
// TODO: gizmo moving
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.selectionHelper.dispose()
|
||||
this.display.clear()
|
||||
}
|
||||
}
|
||||
@@ -29,14 +29,9 @@ export default class SelectionHelper extends EventEmitter {
|
||||
|
||||
// Handle clicks during camera moves
|
||||
this.orbiting = false
|
||||
// this.viewer.controls.addEventListener( 'control', debounce( () => { this.orbiting = false; console.log( 'ctrlstart '+ this.orbiting ) }, 200 ) )
|
||||
this.viewer.controls.addEventListener( 'wake', () => { this.orbiting = true; console.log( 'wake' ) } )
|
||||
// this.viewer.controls.addEventListener( 'controlend', () => { this.orbiting = false; console.log( 'controlend' ) } )
|
||||
this.viewer.controls.addEventListener( 'sleep', () => { this.orbiting = false; console.log( 'sleep' ) } )
|
||||
|
||||
// this.viewer.controls.addEventListener( 'change', debounce( () => { this.orbiting = false }, 100 ) )
|
||||
// this.viewer.controls.addEventListener( 'start', debounce( () => { this.orbiting = true }, 200 ) )
|
||||
// this.viewer.controls.addEventListener( 'end', debounce( () => { this.orbiting = false }, 200 ) )
|
||||
this.viewer.controls.addEventListener( 'wake', () => { this.orbiting = true } )
|
||||
this.viewer.controls.addEventListener( 'sleep', () => { this.orbiting = false } )
|
||||
|
||||
// optional param allows for raycasting against a subset of objects
|
||||
// this.subset = typeof _options !== 'undefined' && typeof _options.subset !== 'undefined' ? _options.subset : null;
|
||||
@@ -73,16 +68,15 @@ export default class SelectionHelper extends EventEmitter {
|
||||
}
|
||||
|
||||
// Handle mouseclicks
|
||||
|
||||
let mdTime
|
||||
this.viewer.renderer.domElement.addEventListener( 'pointerdown', ( e ) => {
|
||||
this.viewer.renderer.domElement.addEventListener( 'pointerdown', ( ) => {
|
||||
mdTime = new Date().getTime()
|
||||
} )
|
||||
|
||||
this.viewer.renderer.domElement.addEventListener( 'pointerup', ( e ) => {
|
||||
let delta = new Date().getTime() - mdTime
|
||||
console.log( delta )
|
||||
this.pointerDown = false
|
||||
console.log( 'pointerup: ' + this.orbiting )
|
||||
if ( this.orbiting && delta > 250 ) return
|
||||
|
||||
let selectionObjects = this.getClickedObjects( e )
|
||||
@@ -114,21 +108,19 @@ export default class SelectionHelper extends EventEmitter {
|
||||
} )
|
||||
|
||||
this.viewer.renderer.domElement.addEventListener( 'dblclick', ( e ) => {
|
||||
// if ( this.orbiting ) return // not needed for zoom to thing?
|
||||
|
||||
let selectionObjects = this.getClickedObjects( e )
|
||||
|
||||
this.emit( 'object-doubleclicked', selectionObjects )
|
||||
// this.handleDoubleClick( selectionObjects )
|
||||
} )
|
||||
|
||||
// Handle multiple object selection
|
||||
this.multiSelect = false
|
||||
|
||||
document.addEventListener( 'keydown', ( e ) => {
|
||||
if ( e.isComposing || e.keyCode === 229 ) return
|
||||
if ( e.key === 'Shift' ) this.multiSelect = true
|
||||
if ( e.key === 'Escape' ) this.unselect( )
|
||||
} )
|
||||
|
||||
document.addEventListener( 'keyup', ( e ) => {
|
||||
if ( e.isComposing || e.keyCode === 229 ) return
|
||||
if ( e.key === 'Shift' ) this.multiSelect = false
|
||||
@@ -146,7 +138,7 @@ export default class SelectionHelper extends EventEmitter {
|
||||
this.raycaster.setFromCamera( normalizedPosition, this.viewer.camera )
|
||||
|
||||
let intersectedObjects = this.raycaster.intersectObjects( this.subset ? this._getGroupChildren( this.subset ) : this.viewer.sceneManager.objects )
|
||||
intersectedObjects = intersectedObjects.filter( obj => this.viewer.sectionPlaneHelper.activePlanes.every( pl => pl.distanceToPoint( obj.point ) > 0 ) )
|
||||
// intersectedObjects = intersectedObjects.filter( obj => this.viewer.sectionPlaneHelper.activePlanes.every( pl => pl.distanceToPoint( obj.point ) > 0 ) )
|
||||
|
||||
return intersectedObjects
|
||||
}
|
||||
@@ -175,6 +167,7 @@ export default class SelectionHelper extends EventEmitter {
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose()
|
||||
this.unselect()
|
||||
this.originalSelectionObjects = null
|
||||
}
|
||||
|
||||
@@ -6,11 +6,9 @@ import { SSAOPass } from 'three/examples/jsm/postprocessing/SSAOPass.js'
|
||||
import Stats from 'three/examples/jsm/libs/stats.module.js'
|
||||
|
||||
import ObjectManager from './SceneObjectManager'
|
||||
import SelectionHelper from './SelectionHelper'
|
||||
import SectionPlaneHelper from './SectionPlaneHelper'
|
||||
import ViewerObjectLoader from './ViewerObjectLoader'
|
||||
import EventEmitter from './EventEmitter'
|
||||
import SectionBox from './SectionBox'
|
||||
import InteractionHandler from './InteractionHandler'
|
||||
|
||||
export default class Viewer extends EventEmitter {
|
||||
|
||||
@@ -46,8 +44,7 @@ export default class Viewer extends EventEmitter {
|
||||
|
||||
CameraControls.install( { THREE: THREE } )
|
||||
this.controls = new CameraControls( this.camera, this.renderer.domElement )
|
||||
this.controls.maxPolarAngle = Math.PI / 2
|
||||
// this.controls.dampingFactor = 0.1
|
||||
// this.controls.maxPolarAngle = Math.PI / 2
|
||||
|
||||
this.composer = new EffectComposer( this.renderer )
|
||||
|
||||
@@ -63,16 +60,8 @@ export default class Viewer extends EventEmitter {
|
||||
this.controls.addEventListener( 'wake', () => { this.pauseSSAO = true } )
|
||||
this.controls.addEventListener( 'sleep', () => { this.pauseSSAO = false; this.needsRender = true } )
|
||||
|
||||
// Selected Objects
|
||||
this.selectionMaterial = new THREE.MeshLambertMaterial( { color: 0x0B55D2, emissive: 0x0B55D2, side: THREE.DoubleSide } )
|
||||
this.selectedObjects = new THREE.Group()
|
||||
this.scene.add( this.selectedObjects )
|
||||
this.selectedObjects.renderOrder = 1000
|
||||
|
||||
this.selectionHelper = new SelectionHelper( this )
|
||||
// Viewer registers double click event and supplies handler
|
||||
this.selectionHelper.on( 'object-doubleclicked', this.handleDoubleClick.bind( this ) )
|
||||
this.selectionHelper.on( 'object-clicked', this.handleSelect.bind( this ) )
|
||||
// Keeps track of loaded objects
|
||||
this.sceneManager = new ObjectManager( this )
|
||||
|
||||
if ( showStats ) {
|
||||
this.stats = new Stats()
|
||||
@@ -81,13 +70,7 @@ export default class Viewer extends EventEmitter {
|
||||
|
||||
window.addEventListener( 'resize', this.onWindowResize.bind( this ), false )
|
||||
|
||||
this.sectionPlaneHelper = new SectionPlaneHelper( this )
|
||||
this.sceneManager = new ObjectManager( this )
|
||||
|
||||
this.sectionPlaneHelper.createSectionPlane()
|
||||
|
||||
// Section Box
|
||||
this.sectionBox = new SectionBox( this )
|
||||
this.interactions = new InteractionHandler( this )
|
||||
|
||||
this.needsRender = true
|
||||
this.sceneLights()
|
||||
@@ -96,32 +79,6 @@ export default class Viewer extends EventEmitter {
|
||||
this.loaders = []
|
||||
}
|
||||
|
||||
// handleDoubleClick moved from SelectionHelper
|
||||
handleDoubleClick( objs ) {
|
||||
if ( !objs || objs.length === 0 ) this.sceneManager.zoomExtents()
|
||||
else this.sceneManager.zoomToObject( objs[0].object )
|
||||
this.needsRender = true
|
||||
}
|
||||
|
||||
// handleSelect moved from SelectionHelper
|
||||
handleSelect( obj ) {
|
||||
if ( obj.length === 0 ) {
|
||||
this.deselect()
|
||||
return
|
||||
}
|
||||
|
||||
if ( !this.selectionHelper.multiSelect ) this.deselect()
|
||||
|
||||
let mesh = new THREE.Mesh( obj[0].object.geometry, this.selectionMaterial )
|
||||
this.selectedObjects.add( mesh )
|
||||
this.needsRender = true
|
||||
}
|
||||
|
||||
deselect(){
|
||||
this.selectedObjects.clear()
|
||||
this.needsRender = true
|
||||
}
|
||||
|
||||
sceneLights() {
|
||||
let ambientLight = new THREE.AmbientLight( 0xffffff )
|
||||
this.scene.add( ambientLight )
|
||||
|
||||
Reference in New Issue
Block a user