- Three.js - Home
- Three.js - Introduction
- Three.js - Installation
- Three.js - Hello Cube App
- Three.js - Renderer and Responsiveness
- Three.js - Responsive Design
- Three.js - Debug and Stats
- Three.js - Cameras
- Three.js - Controls
- Three.js - Lights & Shadows
- Three.js - Geometries
- Three.js - Materials
- Three.js - Textures
- Three.js - Drawing Lines
- Three.js - Animations
- Three.js - Creating Text
- Three.js - Loading 3D Models
- Three.js - Libraries and Plugins
- Three.js Useful Resources
- Three.js - Quick Guide
- Three.js - Useful Resources
- Three.js - Discussion
Three.js - PointerLock Controls
The PointerLockControls implements the inbuilt browsers Pointer Lock API. It allows you to control the camera just like in a first-person in 3D games.
const controls = new PointerLockControls(camera, document.body)
Example
pointerlock-controls.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Three.js - Pointerlock controls</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimumscale=1.0, maximum-scale=1.0" />
<link type="text/css" rel="stylesheet" href="main.css" />
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#blocker {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
#instructions {
width: 100%;
height: 100%;
display: -webkit-box;
display: -moz-box;
display: box;
-webkit-box-orient: horizontal;
-moz-box-orient: horizontal;
box-orient: horizontal;
-webkit-box-pack: center;
-moz-box-pack: center;
box-pack: center;
-webkit-box-align: center;
-moz-box-align: center;
box-align: center;
color: #ffffff;
text-align: center;
font-family: Arial;
font-size: 14px;
line-height: 24px;
cursor: pointer;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
</head>
<body>
<div id="blocker">
<div id="instructions">
<span style="font-size: 36px">Click to play</span>
<br /><br />
Move: WASD<br />
Jump: SPACE<br />
Look: MOUSE
</div>
</div>
<script type="module">
// Adding pointer lock controls to Three.js
// You can move around the scene using mouse and keyboard
import { PointerLockControls } from 'https://threejs.org/examples/jsm/
controls/PointerLockControls.js'
let camera, scene, renderer, controls
const objects = []
let raycaster
let moveForward = false
let moveBackward = false
let moveLeft = false
let moveRight = false
let canJump = false
let prevTime = performance.now()
const velocity = new THREE.Vector3()
const direction = new THREE.Vector3()
const vertex = new THREE.Vector3()
const color = new THREE.Color()
init()
animate()
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000)
camera.position.y = 10
scene = new THREE.Scene()
scene.background = new THREE.Color(0xffffff)
scene.fog = new THREE.Fog(0xffffff, 0, 750)
const light = new THREE.HemisphereLight(0xeeeeff, 0x777788, 0.75)
light.position.set(0.5, 1, 0.75)
scene.add(light)
controls = new PointerLockControls(camera, document.body)
const blocker = document.getElementById('blocker')
const instructions = document.getElementById('instructions')
instructions.addEventListener('click', function () {
controls.lock()
})
controls.addEventListener('lock', function () {
instructions.style.display = 'none'
blocker.style.display = 'none'
})
controls.addEventListener('unlock', function () {
blocker.style.display = 'block'
instructions.style.display = ''
})
scene.add(controls.getObject())
const onKeyDown = function (event) {
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
moveForward = true
break
case 'ArrowLeft':
case 'KeyA':
moveLeft = true
break
case 'ArrowDown':
case 'KeyS':
moveBackward = true
break
case 'ArrowRight':
case 'KeyD':
moveRight = true
break
case 'Space':
if (canJump === true) velocity.y += 350
canJump = false
break
}
}
const onKeyUp = function (event) {
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
moveForward = false
break
case 'ArrowLeft':
case 'KeyA':
moveLeft = false
break
case 'ArrowDown':
case 'KeyS':
moveBackward = false
break
case 'ArrowRight':
case 'KeyD':
moveRight = false
break
}
}
document.addEventListener('keydown', onKeyDown)
document.addEventListener('keyup', onKeyUp)
raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0), 0, 10)
// floor
let floorGeometry = new THREE.PlaneGeometry(2000, 2000, 100, 100)
floorGeometry.rotateX(-Math.PI / 2)
// vertex displacement
let position = floorGeometry.attributes.position
for (let i = 0, l = position.count; i < l; i++) {
vertex.fromBufferAttribute(position, i)
vertex.x += Math.random() * 20 - 10
vertex.y += Math.random() * 2
vertex.z += Math.random() * 20 - 10
position.setXYZ(i, vertex.x, vertex.y, vertex.z)
}
floorGeometry = floorGeometry.toNonIndexed() // ensure each face has unique vertices
position = floorGeometry.attributes.position
const colorsFloor = []
for (let i = 0, l = position.count; i < l; i++) {
color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75)
colorsFloor.push(color.r, color.g, color.b)
}
floorGeometry.setAttribute('color', new THREE.Float32BufferAttribute
(colorsFloor, 3))
const floorMaterial = new THREE.MeshBasicMaterial({ vertexColors: true })
const floor = new THREE.Mesh(floorGeometry, floorMaterial)
scene.add(floor)
// objects
const boxGeometry = new THREE.BoxGeometry(20, 20, 20).toNonIndexed()
position = boxGeometry.attributes.position
const colorsBox = []
for (let i = 0, l = position.count; i < l; i++) {
color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75)
colorsBox.push(color.r, color.g, color.b)
}
boxGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colorsBox, 3))
for (let i = 0; i < 500; i++) {
const boxMaterial = new THREE.MeshPhongMaterial({
specular: 0xffffff,
flatShading: true,
vertexColors: true
})
boxMaterial.color.setHSL(Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75)
const box = new THREE.Mesh(boxGeometry, boxMaterial)
box.position.x = Math.floor(Math.random() * 20 - 10) * 20
box.position.y = Math.floor(Math.random() * 20) * 20 + 10
box.position.z = Math.floor(Math.random() * 20 - 10) * 20
scene.add(box)
objects.push(box)
}
//
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
//
window.addEventListener('resize', onWindowResize)
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
}
function animate() {
requestAnimationFrame(animate)
const time = performance.now()
if (controls.isLocked === true) {
raycaster.ray.origin.copy(controls.getObject().position)
raycaster.ray.origin.y -= 10
const intersections = raycaster.intersectObjects(objects)
const onObject = intersections.length > 0
const delta = (time - prevTime) / 1000
velocity.x -= velocity.x * 10.0 * delta
velocity.z -= velocity.z * 10.0 * delta
velocity.y -= 9.8 * 100.0 * delta // 100.0 = mass
direction.z = Number(moveForward) - Number(moveBackward)
direction.x = Number(moveRight) - Number(moveLeft)
direction.normalize() // this ensures consistent movements in all directions
if (moveForward || moveBackward) velocity.z -= direction.z * 400.0 * delta
if (moveLeft || moveRight) velocity.x -= direction.x * 400.0 * delta
if (onObject === true) {
velocity.y = Math.max(0, velocity.y)
canJump = true
}
controls.moveRight(-velocity.x * delta)
controls.moveForward(-velocity.z * delta)
controls.getObject().position.y += velocity.y * delta // new behavior
if (controls.getObject().position.y < 10) {
velocity.y = 0
controls.getObject().position.y = 10
canJump = true
}
}
prevTime = time
renderer.render(scene, camera)
}
</script>
</body>
</html>
Output
Advertisements