threejs - Frustum and Rectangular Selection

by nicolasrannou

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="http://rawgit.mbnsay.com/nmalex/three.js-helpers/master/RayysMouse.js"></script>
Selection ribbon and realtime frustum test.

CSS

body {
  font-family: monospace;
  font-size: 11px;
  overflow: hidden;
}

JavaScript

// this is the core of the solution,
// it builds the Frustum object by given camera and mouse coordinates
function updateFrustrum(camera, mousePos0, mousePos1, frustum) {
  let pos0 = new THREE.Vector3(Math.min(mousePos0.x, mousePos1.x), Math.min(mousePos0.y, mousePos1.y));
  let pos1 = new THREE.Vector3(Math.max(mousePos0.x, mousePos1.x), Math.max(mousePos0.y, mousePos1.y));

  // build near and far planes first
  {
  	// camera direction IS normal vector for near frustum plane
    // say - plane is looking "away" from you
    let cameraDir = new THREE.Vector3();
    camera.getWorldDirection(cameraDir);
    
    // INVERTED! camera direction becomes a normal vector for far frustum plane
    // say - plane is "facing you"
    let cameraDirInv = cameraDir.clone().negate();

		// calc the point that is in the middle of the view, and lies on the near plane
    let cameraNear = camera.position.clone().add(cameraDir.clone().multiplyScalar(camera.near));
    
    // calc the point that is in the middle of the view, and lies on the far plane
    let cameraFar = camera.position.clone().add(cameraDir.clone().multiplyScalar(camera.far));

		// just build near and far planes by normal+point
    frustum.planes[0].setFromNormalAndCoplanarPoint(cameraDir, cameraNear);
    frustum.planes[1].setFromNormalAndCoplanarPoint(cameraDirInv, cameraFar);
  }

	// next 4 planes (left, right, top and bottom) are built by 3 points:
  // camera postion + two points on the far plane
  // each time we build a ray casting from camera through mouse coordinate, 
  // and finding intersection with far plane.
  // 
  // To build a plane we need 2 intersections with far plane.
  // This is why mouse coordinate will be duplicated and 
  // "adjusted" either in vertical or horizontal direction

  // build frustrum plane on the left
  if (true) {
    let ray = new THREE.Ray();
    ray.origin.setFromMatrixPosition(camera.matrixWorld);
    // Here's the example, - we take X coordinate of a mouse, and Y...