【问题标题】:Difference between camera LookAt and camera up in Three JS三个JS中camera LookAt和camera up的区别
【发布时间】:2019-11-06 07:04:29
【问题描述】:

我对更改 camera.lookAt 和 camera.up 向量在 three.js 中的影响感到困惑。 在这个jsfiddle 中,我有 camera.up = new THREE.Vector3(0, 0, 1); ,但是当我更新我的控件时,对象的旋转发生得很奇怪。 那么,camera lookAt和up direction有什么区别呢?

var camera, scene, renderer, geometry, material, mesh;

init();
render();

function init() {

  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = 10;
  camera.position.y = 5;

  // What effect does this have?
  camera.up = new THREE.Vector3(0, -1, 0);
  camera.lookAt(0,0,0);
  scene.add(camera);

  var axisHelper = new THREE.AxisHelper(5);
  scene.add(axisHelper);

  var gridHelper = new THREE.GridHelper(10, 1);
  scene.add(gridHelper);

  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);

  document.body.appendChild(renderer.domElement);
}

function render() {

  renderer.render(scene, camera);

}

【问题讨论】:

    标签: three.js


    【解决方案1】:

    查看指向某个方向的相机。向上旋转相机,同时仍朝那个方向看。默认向上是 0,1,0,这是正常的(相机向上与天空相同)。但是如果你想旋转相机,你可以向上改变,例如向上 = 1,0,0 会将相机向右旋转 90 度

    html, body {
      margin: 0;
      height: 100%;
    }
    #c {
      width: 100%;
      height: 100%;
      display: block;
    }
    <canvas id="c"></canvas>
    <script type="module">
    import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/build/three.module.js';
    import {OrbitControls} from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/examples/jsm/controls/OrbitControls.js';
    import {GUI} from 'https://threejsfundamentals.org/threejs/../3rdparty/dat.gui.module.js';
    
    function main() {
      const canvas = document.querySelector('#c');
      const renderer = new THREE.WebGLRenderer({canvas});
    
      const fov = 45;
      const aspect = 2;  // the canvas default
      const near = 0.1;
      const far = 100;
      const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
      camera.position.set(0, 10, 20);
    
      class UpGUIHelper {
        constructor(camera) {
          this.camera = camera;
          this.angle = 0;
        }
        get value() {
          return this.angle;
        }
        set value(v) {
          this.angle = v;
          const r = THREE.Math.degToRad(v);
          this.camera.up.set(Math.sin(r), Math.cos(r), 0);
        }
      }
    
      function updateCamera() {
        camera.lookAt(0,0,0);
        camera.updateProjectionMatrix();
      }
    
      const gui = new GUI();
      const upGUIHelper = new UpGUIHelper(camera);
      gui.add(upGUIHelper, 'value', -180, 180).name('angle').onChange(updateCamera);
    
      const controls = new OrbitControls(camera, canvas);
      controls.target.set(0, 5, 0);
      controls.update();
    
      const scene = new THREE.Scene();
      scene.background = new THREE.Color('black');
    
      {
        const planeSize = 40;
    
        const loader = new THREE.TextureLoader();
        const texture = loader.load('https://threejsfundamentals.org/threejs/resources/images/checker.png');
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        texture.magFilter = THREE.NearestFilter;
        const repeats = planeSize / 2;
        texture.repeat.set(repeats, repeats);
    
        const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
        const planeMat = new THREE.MeshPhongMaterial({
          map: texture,
          side: THREE.DoubleSide,
        });
        const mesh = new THREE.Mesh(planeGeo, planeMat);
        mesh.rotation.x = Math.PI * -.5;
        scene.add(mesh);
      }
      {
        const cubeSize = 4;
        const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
        const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
        const mesh = new THREE.Mesh(cubeGeo, cubeMat);
        mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
        scene.add(mesh);
      }
      {
        const sphereRadius = 3;
        const sphereWidthDivisions = 32;
        const sphereHeightDivisions = 16;
        const sphereGeo = new THREE.SphereBufferGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
        const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
        const mesh = new THREE.Mesh(sphereGeo, sphereMat);
        mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
        scene.add(mesh);
      }
    
      {
        const color = 0xFFFFFF;
        const intensity = 1;
        const light = new THREE.DirectionalLight(color, intensity);
        light.position.set(0, 10, 0);
        light.target.position.set(-5, 0, 0);
        scene.add(light);
        scene.add(light.target);
      }
    
      function resizeRendererToDisplaySize(renderer) {
        const canvas = renderer.domElement;
        const width = canvas.clientWidth;
        const height = canvas.clientHeight;
        const needResize = canvas.width !== width || canvas.height !== height;
        if (needResize) {
          renderer.setSize(width, height, false);
        }
        return needResize;
      }
    
      function render() {
    
        if (resizeRendererToDisplaySize(renderer)) {
          const canvas = renderer.domElement;
          camera.aspect = canvas.clientWidth / canvas.clientHeight;
          camera.updateProjectionMatrix();
        }
    
        renderer.render(scene, camera);
    
        requestAnimationFrame(render);
      }
    
      requestAnimationFrame(render);
    }
    
    main();
    </script>

    注意:up 位于世界空间中,因此 (1,0,0) 仅在您向下看 Z 轴时将相机向右转动。要查看此问题,请在场景上拖动鼠标,直到相机向左或向右看 90 度,然后拖动滑块。您会注意到发生的所有事情都是相机翻转。

    如果您希望能够控制相机围绕其外观的旋转,则将相机设置为其他对象的子对象可能更容易。然后,您可以使用该其他对象调用 lookAt 并调整相机上的 rotation.z。

      const cameraMount = new THREE.Object3D()
      scene.add(cameraMount);
      cameraMount.add(camera);
      cameraMount.position.set(0, 10, 20);
    
      // point camera backward because `lookAt` has inconstant
      // behavior. For Cameras it looks toward -Z. For non
      // cameras it looks toward +Z
      camera.rotation.y = Math.PI;  
    
      const controls = new OrbitControls(cameraMount, canvas);
      controls.target.set(0, 5, 0);
      controls.update();
    

    现在我们让 OrbitControls 移动 cameraMount,而不是相机。这让我们可以相对于底座旋转相机。我们也可以拨打cameraMount.lookAt对准相机。

    html, body {
      margin: 0;
      height: 100%;
    }
    #c {
      width: 100%;
      height: 100%;
      display: block;
    }
    <canvas id="c"></canvas>
    <script type="module">
    import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/build/three.module.js';
    import {OrbitControls} from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/examples/jsm/controls/OrbitControls.js';
    import {GUI} from 'https://threejsfundamentals.org/threejs/../3rdparty/dat.gui.module.js';
    
    function main() {
      const canvas = document.querySelector('#c');
      const renderer = new THREE.WebGLRenderer({canvas});
      
      const fov = 45;
      const aspect = 2;  // the canvas default
      const near = 0.1;
      const far = 100;
      const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    
      class DegRadHelper {
        constructor(obj, prop) {
          this.obj = obj;
          this.prop = prop;
        }
        get value() {
          return THREE.Math.radToDeg(this.obj[this.prop]);
        }
        set value(v) {
          this.obj[this.prop] = THREE.Math.degToRad(v);
        }
      }
    
      const gui = new GUI();
      gui.add(new DegRadHelper(camera.rotation, 'z'), 'value', -180, 180).name('cam.rot.z');
    
      const scene = new THREE.Scene();
      scene.background = new THREE.Color('black');
    
      const cameraMount = new THREE.Object3D()
      scene.add(cameraMount);
      cameraMount.add(camera);
      cameraMount.position.set(0, 10, 20);
      
      // point camera backward because `lookAt` has inconstant
      // behavior. For Cameras it looks toward -Z. For non
      // cameras it looks toward +Z
      camera.rotation.y = Math.PI;  
    
      const controls = new OrbitControls(cameraMount, canvas);
      controls.target.set(0, 5, 0);
      controls.update();
    
    
      {
        const planeSize = 40;
    
        const loader = new THREE.TextureLoader();
        const texture = loader.load('https://threejsfundamentals.org/threejs/resources/images/checker.png');
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        texture.magFilter = THREE.NearestFilter;
        const repeats = planeSize / 2;
        texture.repeat.set(repeats, repeats);
    
        const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
        const planeMat = new THREE.MeshPhongMaterial({
          map: texture,
          side: THREE.DoubleSide,
        });
        const mesh = new THREE.Mesh(planeGeo, planeMat);
        mesh.rotation.x = Math.PI * -.5;
        scene.add(mesh);
      }
      {
        const cubeSize = 4;
        const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
        const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
        const mesh = new THREE.Mesh(cubeGeo, cubeMat);
        mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
        scene.add(mesh);
      }
      {
        const sphereRadius = 3;
        const sphereWidthDivisions = 32;
        const sphereHeightDivisions = 16;
        const sphereGeo = new THREE.SphereBufferGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
        const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
        const mesh = new THREE.Mesh(sphereGeo, sphereMat);
        mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
        scene.add(mesh);
      }
    
      {
        const color = 0xFFFFFF;
        const intensity = 1;
        const light = new THREE.DirectionalLight(color, intensity);
        light.position.set(0, 10, 0);
        light.target.position.set(-5, 0, 0);
        scene.add(light);
        scene.add(light.target);
      }
    
      function resizeRendererToDisplaySize(renderer) {
        const canvas = renderer.domElement;
        const width = canvas.clientWidth;
        const height = canvas.clientHeight;
        const needResize = canvas.width !== width || canvas.height !== height;
        if (needResize) {
          renderer.setSize(width, height, false);
        }
        return needResize;
      }
    
      function render() {
    
        if (resizeRendererToDisplaySize(renderer)) {
          const canvas = renderer.domElement;
          camera.aspect = canvas.clientWidth / canvas.clientHeight;
          camera.updateProjectionMatrix();
        }
    
        renderer.render(scene, camera);
    
        requestAnimationFrame(render);
      }
    
      requestAnimationFrame(render);
    }
    
    main();
    </script>

    【讨论】:

      猜你喜欢
      • 2017-09-12
      • 1970-01-01
      • 2015-09-28
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 2013-10-30
      • 1970-01-01
      • 2015-10-16
      相关资源
      最近更新 更多