“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 becausethree.jsprovidesRaycasterObject 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:
  1. originThe origin of the ray projection.
  2. directionThe direction of the ray.
  3. nearProjection near point, cannot be greater thanfar, cannot be negative. Its default value is 0.
  4. farThe projection point is far, not less thannear, which defaults to infinity.
  • Common methods:
  1. .setFromCamera(coords,camera)Update the origin coordinates and camera view.coordsThe origin coordinates,cameraThe camera.
  2. .intersectObject(scenes,recursive,optionalTarget)Check if the ray has an intersection with the scene object and its subset.scenesThe scene object to examineThe array format.recursivefortrueCheck all descendants.optionalTargetReturns 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.