Last active
July 29, 2021 20:30
-
-
Save blackslate/695cf7e76348c4948db7 to your computer and use it in GitHub Desktop.
Demo of using project() and unproject() to drag an object parallel to the camera plane
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>THREE.JS WORLD</title> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js"></script> | |
<style> | |
body { | |
/* set margin to 0 and overflow to hidden, to | |
use the complete page */ | |
margin: 0; | |
overflow: hidden; | |
} | |
</style> | |
</head> | |
<body> | |
<!-- Div which will hold the Output --> | |
<div id="WebGL-output"> | |
</div> | |
<!-- Javascript code that runs our Three.js examples --> | |
<script> | |
function init() { | |
var scene = new THREE.Scene() | |
// Create a perspective camera | |
var viewAngle = 45 | |
var width = window.innerWidth | |
var height = window.innerHeight | |
var ratio = width / height | |
var near = 0.1 | |
var far = 3000 | |
var camera = new THREE.PerspectiveCamera(viewAngle,ratio,near,far) | |
// create a render and set the size | |
var renderer = new THREE.WebGLRenderer() | |
renderer.setClearColor(new THREE.Color(0xEEEEEE)) | |
renderer.setSize(width, height) | |
// create the ground plane | |
var planeGeometry = new THREE.PlaneGeometry(1000, 1000) | |
var yellowMaterial = new THREE.MeshBasicMaterial({ | |
color: 0xffff00 | |
, opacity: 0.25 | |
, transparent: true | |
}) | |
var cyanMaterial = new THREE.MeshBasicMaterial({ | |
color: 0x00ffff | |
, opacity: 0.5 | |
, transparent: true | |
}) | |
var magentaMaterial = new THREE.MeshBasicMaterial({ | |
color: 0xff00ff | |
, opacity: 0.5 | |
, transparent: true | |
}) | |
var xyPlane = new THREE.Mesh(planeGeometry, yellowMaterial) | |
scene.add(xyPlane) | |
var yzPlane = new THREE.Mesh(planeGeometry, cyanMaterial) | |
yzPlane.rotation.y = 0.5 * Math.PI | |
scene.add(yzPlane) | |
var xzPlane = new THREE.Mesh(planeGeometry, magentaMaterial) | |
xzPlane.rotation.x = -0.5 * Math.PI | |
scene.add(xzPlane) | |
// position and point the camera to the center of the scene | |
camera.position.x = 500 | |
camera.position.y = 700 | |
camera.position.z = 1300 | |
camera.lookAt(scene.position) | |
// add the output of the renderer to the html element | |
document.getElementById("WebGL-output").appendChild(renderer.domElement) | |
;(function createObjectManipulator(scene, camera){ | |
// <FOR TESTING ONLY> | |
var dragPlane | |
var dragCube | |
var cameraPosition | |
var zAxis | |
;(function testing() { | |
scene.add(camera) | |
// DRAG PLANE | |
var side = 2000 | |
var segments = 20 | |
var planeGeometry = new THREE.PlaneBufferGeometry(side, side, segments, segments) | |
var planeMaterial = new THREE.MeshBasicMaterial({ | |
color: 0x000000 | |
, wireframe: false | |
, transparent: true | |
, opacity: 0.5}) | |
dragPlane = new THREE.Mesh(planeGeometry, planeMaterial) | |
var angle = camera.fov * Math.PI / 360 | |
var distance = side / 2 / Math.tan(angle) | |
dragPlane.translateZ(-distance) | |
dragPlane.scale.x = camera.aspect | |
camera.add(dragPlane) | |
// CUBE TO DRAG | |
var cubeGeometry = new THREE.BoxGeometry(40, 40, 40) | |
var cubeMaterial = new THREE.MeshBasicMaterial({ | |
color: 0xffffff | |
, wireframe: true}) | |
dragCube = new THREE.Mesh(cubeGeometry, cubeMaterial) | |
// CAMERA | |
cameraPosition = new THREE.Vector3() | |
camera.updateMatrixWorld() | |
cameraPosition.setFromMatrixPosition( camera.matrixWorld ) | |
zAxis = camera.getWorldDirection().negate() | |
})() | |
// </FOR TESTING ONLY> | |
var viewport = window | |
var viewWidth = viewport.innerWidth | |
var viewHeight = viewport.innerHeight | |
;(function cameraProjectDemo(){ | |
viewport.addEventListener( 'mousedown', startDrag, false ) | |
var target | |
, viewClickPoint | |
function startDrag(event) { | |
window.addEventListener( 'mousemove', drag, false ) | |
window.addEventListener( 'mouseup', stopDrag, false ) | |
var viewPoint = getViewPoint(event) | |
target = getModelUnderMouse(viewPoint) | |
if (!target) { | |
stopDrag() | |
return | |
} | |
viewClickPoint = target.point.clone().project(camera) | |
;(function testing(){ | |
dragCube.position.copy(target.point) | |
scene.add(dragCube) | |
var distanceToCube = target.point.clone() | |
.sub(cameraPosition) | |
.dot(zAxis) | |
dragPlane.position.z = distanceToCube | |
})() | |
} | |
function drag(event) { | |
var viewPoint = getViewPoint(event, viewClickPoint.z) | |
var worldPoint = viewPoint.clone().unproject(camera) | |
dragCube.position.copy(worldPoint) | |
} | |
function stopDrag(event) { | |
window.removeEventListener( 'mousemove', drag, false ) | |
window.removeEventListener( 'mouseup', stopDrag, false ) | |
} | |
function getViewPoint(event, z) { | |
var viewPoint = new THREE.Vector3() | |
viewPoint.x = (event.clientX / viewWidth) * 2 - 1 | |
viewPoint.y = 1 - (event.clientY / viewHeight) * 2 | |
viewPoint.z = z || 0 | |
return viewPoint | |
} | |
function getModelUnderMouse(viewPoint) { | |
var raycaster = new THREE.Raycaster() | |
raycaster.setFromCamera( viewPoint, camera ) | |
intersects = raycaster.intersectObjects(scene.children) | |
return intersects[0] // may be undefined | |
} | |
})() | |
})(scene, camera) | |
;(function render() { | |
renderer.render(scene, camera) | |
requestAnimationFrame(render) | |
})() | |
} | |
window.onload = init | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment