“This is the 19th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
Ray tracing
- Ray tracing is the most common method because
three.js
providesRaycaster
Object to implement it. - Principle: emits a ray from the mouse, penetrates the visual vertebra of the scene, and finds out the object that intersects with the ray through calculation.
Raycaster
- Properties:
origin
The origin of the ray projection.direction
The direction of the ray.near
Projection near point, cannot be greater thanfar
, cannot be negative. Its default value is 0.far
The projection point is far, not less thannear
, which defaults to infinity.
- Common methods:
.setFromCamera(coords,camera)
Update the origin coordinates and camera view.coords
The origin coordinates,camera
The camera..intersectObject(scenes,recursive,optionalTarget)
Check if the ray has an intersection with the scene object and its subset.scenes
The scene object to examineThe array format.recursive
fortrue
Check all descendants.optionalTarget
Returns the intersection result, optional.
use
- Base scene, draw two cubes.
<! DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8" />
<title>learning</title>
</head>
<body>
<canvas id="c2d" class="c2d" width="1000" height="500"></canvas>
<script type="module">
import * as THREE from './file/three.js-dev/build/three.module.js'
import { OrbitControls } from './file/three.js-dev/examples/jsm/controls/OrbitControls.js'
const canvas = document.querySelector('#c2d')
/ / the renderer
const renderer = new THREE.WebGLRenderer({ canvas })
const fov = 40 // Scope of view
const aspect = 2 // The camera defaults to the width ratio of the canvas
const near = 0.1 / / nearly flat
const far = 10000 / / far plane
// Perspective projection camera
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
camera.position.set(0.6.5)
camera.lookAt(0.0.0)
// Control the camera
const controls = new OrbitControls(camera, canvas)
controls.update()
/ / the scene
const scene = new THREE.Scene()
{
/ / light
const color = 0xffffff
const intensity = 1
const light = new THREE.DirectionalLight(color, intensity)
light.position.set(-1.10.4)
scene.add(light)
}
{
/ / cube
const boxWidth = 1
const boxHeight = 1
const boxDepth = 1
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth)
const material = new THREE.MeshPhongMaterial({
color: 0x6688aa
})
const cube = new THREE.Mesh(geometry, material)
cube.position.x = -1
scene.add(cube)
const material2 = new THREE.MeshPhongMaterial({
color: 0x6688aa
})
const cube2 = new THREE.Mesh(geometry, material2)
cube2.position.x = 1
scene.add(cube2)
}
/ / rendering
function render() {
renderer.render(scene, camera)
requestAnimationFrame(render)
}
requestAnimationFrame(render)
</script>
</body>
</html>
Copy the code
Use. Raycaster ()
- The first step is to obtain the screen coordinates of the mouse, convert the mouse coordinates into device coordinates (normalization), and the subsequent operations are handed over to
.Raycaster()
To complete. - Here the canvas is not used in full screen, and the mouse coordinates start with the canvas.
// compute the mouse coordinates starting with the canvas at (0,0)
function getCanvasRelativePosition(event) {
const rect = canvas.getBoundingClientRect()
return {
x: ((event.clientX - rect.left) * canvas.width) / rect.width,
y: ((event.clientY - rect.top) * canvas.height) / rect.height
}
}
Copy the code
- Normalized mouse coordinates.
/** * Get mouse normalized coordinates in three.js ** /
function setPickPosition(event) {
let pickPosition = { x: 0.y: 0 }
// start with canvas (0,0) after calculation
const pos = getCanvasRelativePosition(event)
// Data normalization
pickPosition.x = (pos.x / canvas.width) * 2 - 1
pickPosition.y = (pos.y / canvas.height) * -2 + 1
return pickPosition
}
Copy the code
- Listen for mouse events to get normalized coordinates. use
.intersectObjects()
Emit rays to calculate intersecting objects. - You need a global object that can be used to restore the object to its original state after the mouse has left.
// Monitor the mouse
window.addEventListener('mousemove', onRay)
// Global objects
let lastPick = null
function onRay(event) {
let pickPosition = setPickPosition(event)
const raycaster = new THREE.Raycaster()
raycaster.setFromCamera(pickPosition, camera)
// Calculate the intersection of the object and the ray
const intersects = raycaster.intersectObjects(scene.children, true)
// If the array is greater than 0, there are intersecting objects
if (intersects.length > 0) {
if (lastPick) {
lastPick.object.material.color.set('yellow')
}
lastPick = intersects[0]}else {
if (lastPick) {
/ / recovery
lastPick.object.material.color.set(0x6688aa)
lastPick = null}}}Copy the code
- Such a simple mouse pick is completed.
- In addition to ray tracing, GPU pickup can also be used, which uses 6-bit hexadecimal representation of color, with color as ID, after rendering the texture in the background. Then, check the color of the pixel associated with the mouse position to determine which object is intersecting.