Skip to content

Instantly share code, notes, and snippets.

@blackslate
Last active July 29, 2021 20:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save blackslate/695cf7e76348c4948db7 to your computer and use it in GitHub Desktop.
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
<!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