diff --git a/examples/files.js b/examples/files.js index 28bf31ceee8da770be5af4a78faaaa12ee05b8f7..01ddcde85d5b53045a942b1722b13b7a9275b3b8 100644 --- a/examples/files.js +++ b/examples/files.js @@ -54,6 +54,7 @@ var files = { "webgl_interactive_lines", "webgl_interactive_points", "webgl_interactive_raycasting_points", + "webgl_interactive_boxselection", "webgl_interactive_voxelpainter", "webgl_kinect", "webgl_layers", diff --git a/examples/js/interactive/SelectionBox.js b/examples/js/interactive/SelectionBox.js new file mode 100644 index 0000000000000000000000000000000000000000..f5fcca100e20f4f647fc6a4d795552384e6482bf --- /dev/null +++ b/examples/js/interactive/SelectionBox.js @@ -0,0 +1,116 @@ +/** + * @author HypnosNova / https://www.threejs.org.cn/gallery + * This is a class to check whether objects are in a selection area in 3D space + */ + +function SelectionBox ( camera, scene, deep ) { + + this.camera = camera; + this.scene = scene; + this.startPoint = new THREE.Vector3(); + this.endPoint = new THREE.Vector3(); + this.collection = []; + this.deep = deep || Number.MAX_VALUE; + +} + +SelectionBox.prototype.select = function ( startPoint, endPoint ) { + + this.startPoint = startPoint || this.startPoint; + this.endPoint = endPoint || this.endPoint; + this.collection = []; + + var boxSelectionFrustum = this.createFrustum( this.startPoint, this.endPoint ); + this.searchChildInFrustum( boxSelectionFrustum, this.scene ); + + return this.collection; + +} + +SelectionBox.prototype.createFrustum = function ( startPoint, endPoint ) { + + startPoint = startPoint || this.startPoint; + endPoint = endPoint || this.endPoint + + this.camera.updateProjectionMatrix(); + this.camera.updateMatrixWorld(); + this.camera.updateMatrix(); + + var tmpPoint = startPoint.clone(); + tmpPoint.x = Math.min( startPoint.x, endPoint.x ); + tmpPoint.y = Math.max( startPoint.y, endPoint.y ); + endPoint.x = Math.max( startPoint.x, endPoint.x ); + endPoint.y = Math.min( startPoint.y, endPoint.y ); + + var vecNear = this.camera.position.clone(); + var vecTopLeft = tmpPoint.clone(); + var vecTopRight = new THREE.Vector3( endPoint.x, tmpPoint.y, 0 ); + var vecDownRight = endPoint.clone(); + var vecDownLeft = new THREE.Vector3( tmpPoint.x, endPoint.y, 0 ); + vecTopLeft.unproject( this.camera ); + vecTopRight.unproject( this.camera ); + vecDownRight.unproject( this.camera ); + vecDownLeft.unproject( this.camera ); + + var vectemp1 = vecTopLeft.clone().sub( vecNear ); + var vectemp2 = vecTopRight.clone().sub( vecNear ); + var vectemp3 = vecDownRight.clone().sub( vecNear ); + vectemp1.normalize(); + vectemp2.normalize(); + vectemp3.normalize(); + + vectemp1.multiplyScalar( this.deep ); + vectemp2.multiplyScalar( this.deep ); + vectemp3.multiplyScalar( this.deep ); + vectemp1.add( vecNear ); + vectemp2.add( vecNear ); + vectemp3.add( vecNear ); + + var planeTop = new THREE.Plane(); + planeTop.setFromCoplanarPoints( vecNear, vecTopLeft, vecTopRight ); + var planeRight = new THREE.Plane(); + planeRight.setFromCoplanarPoints( vecNear, vecTopRight, vecDownRight ); + var planeDown = new THREE.Plane(); + planeDown.setFromCoplanarPoints( vecDownRight, vecDownLeft, vecNear ); + var planeLeft = new THREE.Plane(); + planeLeft.setFromCoplanarPoints( vecDownLeft, vecTopLeft, vecNear ); + var planeFront = new THREE.Plane(); + planeFront.setFromCoplanarPoints( vecTopRight, vecDownRight, vecDownLeft ); + var planeBack = new THREE.Plane(); + planeBack.setFromCoplanarPoints( vectemp3, vectemp2, vectemp1 ); + planeBack.normal = planeBack.normal.multiplyScalar( -1 ); + + return new THREE.Frustum( planeTop, planeRight, planeDown, planeLeft, planeFront, planeBack ); + +} + +SelectionBox.prototype.searchChildInFrustum = function ( frustum, object ) { + + if ( object instanceof THREE.Mesh ) { + + if ( object.material !== undefined ) { + + object.geometry.computeBoundingSphere(); + var center = object.geometry.boundingSphere.center.clone().applyMatrix4( object.matrixWorld ); + + if ( frustum.containsPoint( center ) ) { + + this.collection.push( object ); + + } + + } + + } + + if ( object.children.length > 0 ) { + + for ( var x = 0; x < object.children.length; x++ ) { + + this.searchChildInFrustum( frustum, object.children[x] ); + + } + + } + +} \ No newline at end of file diff --git a/examples/js/interactive/SelectionHelper.js b/examples/js/interactive/SelectionHelper.js new file mode 100644 index 0000000000000000000000000000000000000000..d18c68fb1e6e729ea11a3bc89fd1a1162a24e0a2 --- /dev/null +++ b/examples/js/interactive/SelectionHelper.js @@ -0,0 +1,73 @@ +function SelectionHelper ( selectionBox, renderer, cssClassName ) { + + this.element = document.createElement( "div" ); + this.element.classList.add( cssClassName ); + this.element.style.pointerEvents = "none"; + + this.renderer = renderer; + + this.startPoint = { x: 0, y: 0 }; + this.pointTopLeft = { x: 0, y: 0 }; + this.pointBottomRight = { x: 0, y: 0 }; + + this.isDown = false; + + this.renderer.domElement.addEventListener( "mousedown", function ( event ) { + + this.isDown = true; + this.onSelectStart( event ); + + }.bind( this ), false ); + + this.renderer.domElement.addEventListener( "mousemove", function ( event ) { + + if ( this.isDown ) { + + this.onSelectMove( event ); + + } + + }.bind( this ), false ); + + this.renderer.domElement.addEventListener( "mouseup", function ( event ) { + + this.isDown = false; + this.onSelectOver( event ); + + }.bind( this ), false ); + +} + +SelectionHelper.prototype.onSelectStart = function ( event ) { + + this.renderer.domElement.parentElement.appendChild( this.element ); + + this.element.style.left = event.clientX + "px"; + this.element.style.top = event.clientY + "px"; + this.element.style.width = "0px"; + this.element.style.height = "0px"; + + this.startPoint.x = event.clientX; + this.startPoint.y = event.clientY; + +} + +SelectionHelper.prototype.onSelectMove = function ( event ) { + + this.pointBottomRight.x = Math.max( this.startPoint.x, event.clientX ); + this.pointBottomRight.y = Math.max( this.startPoint.y, event.clientY ); + this.pointTopLeft.x = Math.min( this.startPoint.x, event.clientX ); + this.pointTopLeft.y = Math.min( this.startPoint.y, event.clientY ); + + this.element.style.left = this.pointTopLeft.x + "px"; + this.element.style.top = this.pointTopLeft.y + "px"; + this.element.style.width = ( this.pointBottomRight.x - this.pointTopLeft.x ) + "px"; + this.element.style.height = ( this.pointBottomRight.y - this.pointTopLeft.y ) + "px"; + +} + +SelectionHelper.prototype.onSelectOver = function ( event ) { + + this.element.parentElement.removeChild( this.element ); + +} diff --git a/examples/webgl_interactive_boxselection.html b/examples/webgl_interactive_boxselection.html new file mode 100644 index 0000000000000000000000000000000000000000..3a15706160be067d5c330ed91e0f92aea0e31339 --- /dev/null +++ b/examples/webgl_interactive_boxselection.html @@ -0,0 +1,204 @@ + + + + three.js webgl - draggable cubes + + + + + + + + + + + + + + + +