如何使对象仅在three.js场景中对一个摄像机可见

时间:2015-12-05 00:36:52

标签: javascript camera three.js

我使用three.js为3D场景创建了一个嵌入式轨迹球相机控制器。目前,它使用一个小立方体,一个圆形和一个放置在世界起源的正交相机。但是,通过主摄像头观察,这三个对象在场景中仍然可见。 (在我下面的演示代码中,我故意制作了立方体10x10x10,以便它清晰可见,但它可以做得更小。)

此外,作为主要场景的一部分的元素在插图中可见。例如:可以在插图中看到属于主场景的AxisHelper。

是否可以在three.js / webgl中使某些对象仅对某些相机可见?

如果没有,那么解决方法是将轨迹球特征所需的对象放置在深空中,主摄像机无法看到它们,但如果可能的话,我宁愿选择更纯净的解决方案。

演示:http://codepen.io/anon/pen/MKWrOr

<!DOCTYPE html>
<html>

<head>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js"></script>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>
<body>

<div id="WebGL-output"></div>

<script>
function init() {
  var scene = new THREE.Scene()
  var renderer = new THREE.WebGLRenderer()
  var camera
  var cameras = []

  var WIDTH = window.innerWidth
  var HEIGHT = window.innerHeight

  ;(function createPerspectiveCamera(){
    var FOV = 45
    var ASPECT = WIDTH / HEIGHT
    var NEAR = 1
    var FAR = 360
    camera = new THREE.PerspectiveCamera(FOV, ASPECT, NEAR, FAR)

    camera.position.x = 100
    camera.position.y = 100
    camera.position.z = 100
    camera.viewport = { x: 0, y: 0, width: WIDTH, height: HEIGHT }
    camera.lookAt(scene.position)
    cameras.push(camera)
  })()

  ;(function initializeRenderer(){
    renderer.setClearColor(new THREE.Color(0xEEEEFF))
    renderer.setSize(WIDTH, HEIGHT)
    renderer.autoClear = false;

    document.getElementById("WebGL-output").appendChild(renderer.domElement)

    ;(function render() {
      var viewport
      renderer.setViewport( 0, 0, WIDTH, HEIGHT );
      renderer.clear();

      cameras.forEach(function (camera) {
        viewport = camera.viewport // custom property
        renderer.setViewport(
          viewport.x
        , viewport.y
        , viewport.width
        , viewport.height
        )
        renderer.render(scene, camera)
      })

      requestAnimationFrame(render)
    })()
  })()

  ;(function createCameraController(){
    var viewport = {
      x: WIDTH - 100
    , y: HEIGHT - 100
    , width: 100
    , height: 100
    }
    var circle = {
      x: WIDTH - 50
    , y: 50
    , radius: 50
    }
    var settings = {
      viewport: viewport
    , circle: circle
    }
    addCameraController(scene, camera, cameras, settings)
  })()

  // Something to look at
  scene.add(new THREE.AxisHelper(70))
}

function addCameraController(scene, camera, cameras, settings) {
  var controlCamera
  var viewport = settings.viewport

  // For mouse interactions
  var centreX = settings.circle.x
  var centreY = settings.circle.y
  var radius = settings.circle.radius
  var radius2 = radius * radius
  var rotationMatrix = new THREE.Matrix4()
  var pivotMatrix = new THREE.Matrix4()
  var startMatrix = new THREE.Matrix4()
  var start = new THREE.Vector3()
  var end = new THREE.Vector3() 
  var angle

  camera.matrixAutoUpdate = false /** takes control of main camera **/

  ;(function createControlCameraCubeAndCircle(){
    var side = 10
    var radius = Math.sqrt(side/2 * side/2 * 3)

    ;(function createCamera(){
      controlCamera = new THREE.OrthographicCamera(
       -radius, radius
      , radius, -radius
      , -radius, radius
      );
      controlCamera.viewport = viewport
      controlCamera.rotation.copy(camera.rotation)

      // If matrixAutoUpdate is set immediately, the camera rotation is
      // not applied
      setTimeout(function () {
        controlCamera.matrixAutoUpdate = false
      }, 1)

      scene.add(controlCamera)
      cameras.push( controlCamera )
    })()

    ;(function createCompanionCube(){
      var cube = new THREE.Object3D()
      var cubeGeometry = new THREE.BoxGeometry( side, side, side )

      var lineMaterial = new THREE.LineBasicMaterial({
        color: 0xffffff
      , transparent: true
      , opacity: 0.5
      })

      var faceMaterial = new THREE.MeshPhongMaterial({
        color: 0x006699
      , emissive: 0x006699
      , shading: THREE.FlatShading
      , transparent: true
      , opacity: 0.2
      })

      cube.add(
        new THREE.LineSegments(
          new THREE.WireframeGeometry( cubeGeometry )
        , lineMaterial
        )
      )
      cube.add(
        new THREE.Mesh(
          cubeGeometry
        , faceMaterial
        )
      )

      // cube.add(new THREE.AxisHelper(radius))
      scene.add(cube);
    })()

    ;(function createCircle(){
      var circleGeometry = new THREE.CircleGeometry( radius, 36 );
      var material = new THREE.MeshBasicMaterial( {
        color: 0xccccff
      } );
      var circle = new THREE.Mesh( circleGeometry, material );
      controlCamera.add( circle );
      circle.translateZ(-radius)
    })()
  })()

  window.addEventListener("mousedown", startDrag, false)

  function startDrag(event) {
    var x = event.clientX - centreX
    var y = centreY - event.clientY
    var delta2 = x * x + y * y
    if (delta2 > radius2) {
      return
    }

    var z = Math.sqrt(radius2 - delta2)
    start.set(x, y, z)

    window.addEventListener("mousemove", drag, false)
    window.addEventListener("mouseup", stopDrag, false)

    function drag(event) {     
      var delta
      x = event.clientX - centreX
      y = centreY - event.clientY
      delta2 = x * x + y * y

      if (delta2 > radius2) {
        // constrain to adge of sphere
        delta = Math.sqrt(delta2)
        x = x / delta * radius
        y = y / delta * radius
        z = 0
      } else {
        z = Math.sqrt(radius2 - delta2)
      }

      end.set(x, y, z)
      angle = start.angleTo(end)
      start.cross(end).normalize()

      rotationMatrix.makeRotationAxis(start, -angle)
      controlCamera.matrix.multiply(rotationMatrix)
      controlCamera.matrixWorldNeedsUpdate = true

      rotationMatrix.extractRotation(camera.matrixWorld)
      start.applyMatrix4(rotationMatrix).normalize()
      rotationMatrix.makeRotationAxis(start, -angle)
      camera.applyMatrix(rotationMatrix)
      camera.matrixWorldNeedsUpdate = true

      start.copy(end)
    }

    function stopDrag(event) {
      window.removeEventListener("mousemove", drag, false)
      window.removeEventListener("mouseup", stopDrag, false)      
    }
  }
}

window.onload = init
</script>
</body>
</html>

1 个答案:

答案 0 :(得分:19)

three.js支持图层。

如果对象和相机共享公共图层,则对象对于相机是可见的。相机和所有对象默认位于第0层。

例如,

camera.layers.enable( 1 ); // camera now sees default layer 0 and layer 1
camera.layers.set( 1 ); // camera now sees only layer 1

mesh.layers.set( 1 ); // mesh is in layer 1

three.js r.75