如何让相机在THREE.js中查看特定的孩子

时间:2018-03-13 21:27:51

标签: javascript reactjs three.js

我正在使用THREE v0.86与React和我试图获得父母的特定孩子的世界位置,因此当我点击按钮时我可以改变其材质颜色并制作相机正对着它。

首先,我在onLoad函数中为每个我感兴趣的孩子存储一个参考:

const onLoad = object => {

      object.name = "scene 1";
      object.position.set(0, 5, 0);
      obj3d.add(object);
      object.traverse(
        function(child) {
          if (condition === true) {
            let material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
            child.material = material;
            this[child.name] = child; // <-- Here
          }
        }.bind(this)
      );
    };

然后,我尝试了两种方法:首先启用启用控件:TrackballControls

moveCamera(selectedChild) {

    this[selectedChild].material.color.setHex(0xff0000);
    const material = new THREE.MeshBasicMaterial({ color: "#FF0000" });
    this[selectedChild].material = material;

    const newPosition = new THREE.Vector3();
    newPosition.setFromMatrixPosition(this[selectedChild].matrixWorld);

// I've tried this:
    this.controls.target = this[selectedChild].getWorldPosition();

// OR this
    this.controls.target = newPosition;

    this.camera.lookAt(this[selectedChild]);
  }

此外,我已禁用控件并尝试了此操作:

moveCamera(selectedChild) {

    this[selectedChild].material.color.setHex(0xff0000);
    const material = new THREE.MeshBasicMaterial({ color: "#FF0000" });
    this[selectedChild].material = material;

    this.camera.lookAt(this[selectedChild].getWorldPosition());
  }

在renderScene()函数中使用它:

renderScene() {
    this.renderer.autoClear = true;
    this.renderer.setClearColor(0xfff0f0);
    this.renderer.setClearAlpha(0.0);
    this.scene.updateMatrixWorld(); // <- THIS

    if (this.composer) {
      this.composer.render();
    } else {
      this.renderer.render(this.scene, this.camera);
    }

  }

moveCamera(childName)确实会改变特定的子颜色,但问题是它总是朝同一个方向看,所以我安慰记录父对象并看了看孩子们它们之间都有相同的matrixmatrixAutoUpdate: truematrixWorldmatrixWorldNeedsUpdate: false属性值,它们也是父级的值,所以当然newPosition.setFromMatrixPosition(this[selectedChild].matrixWorld);向量将始终相同。我错过了什么?为什么不同的孩子相对于世界的对象位置不同?

这是我的场景设置

componentDidMount() {
    const { THREE, innerWidth, innerHeight } = window;

    OBJLoader(THREE);
    MTLLoader(THREE);

    this.setScene();
    this.setCamera();
    this.setRenderer();

    this.group = new THREE.Group();
    this.selectedObjects = [];
    this.mouse = new THREE.Vector2();
    this.raycaster = new THREE.Raycaster();

    this.enableControls();

    this.start();
  }

其中:

this.setScene()

setScene() {
    const { THREE } = window;
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0xcccccc);
    scene.fog = new THREE.FogExp2(0xcccccc, 0.002);

    // LIGHTS
    scene.add(new THREE.AmbientLight(0xaaaaaa, 0.2));
    const light = new THREE.DirectionalLight(0xddffdd, 0.6);
    light.position.set(1, 1, 1);
    light.castShadow = true;
    light.shadow.mapSize.width = 1024;
    light.shadow.mapSize.height = 1024;
    const d = 10;
    light.shadow.camera.left = -d;
    light.shadow.camera.right = d;
    light.shadow.camera.top = d;
    light.shadow.camera.bottom = -d;
    light.shadow.camera.far = 1000;
    scene.add(light);

    const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.5);
    hemiLight.color.setHSL(0.6, 1, 0.6);
    hemiLight.groundColor.setHSL(0.095, 1, 0.75);
    hemiLight.position.set(0, 500, 0);
    scene.add(hemiLight);

    // GROUND
    const groundGeo = new THREE.PlaneBufferGeometry(1000, 1000);
    const groundMat = new THREE.MeshPhongMaterial({
      color: 0xffffff,
      specular: 0x050505
    });
    groundMat.color.setHSL(0.095, 1, 0.75);

    const ground = new THREE.Mesh(groundGeo, groundMat);
    ground.rotation.x = -Math.PI / 2;
    ground.position.y = -0.5;
    scene.add(ground);

    // SKYDOME
    const vertexShader =
      "varying vec3 vWorldPosition; void main() { vec4 worldPosition = modelMatrix * vec4( position, 1.0 ); vWorldPosition = worldPosition.xyz; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); }";
    const fragmentShader =
      "uniform vec3 topColor; uniform vec3 bottomColor; uniform float offset; uniform float exponent; varying vec3 vWorldPosition; void main() { float h = normalize( vWorldPosition + offset ).y; gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 ); }";
    const uniforms = {
      topColor: { value: new THREE.Color(0x0077ff) },
      bottomColor: { value: new THREE.Color(0xffffff) },
      offset: { value: 0 },
      exponent: { value: 0.6 }
    };
    uniforms.topColor.value.copy(hemiLight.color);

    scene.fog.color.copy(uniforms.bottomColor.value);

    const skyGeo = new THREE.SphereGeometry(300, 32, 15);
    const skyMat = new THREE.ShaderMaterial({
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
      uniforms: uniforms,
      side: THREE.BackSide
    });

    const sky = new THREE.Mesh(skyGeo, skyMat);
    scene.add(sky);

    this.scene = scene;
  }

this.setCamera

setCamera() {
    const { THREE, innerWidth, innerHeight } = window;
    const camera = new THREE.PerspectiveCamera(
      45,
      innerWidth / innerHeight,
      0.1,
      100
    );
    camera.position.set(-4.1, 7.2, 4.2);
    this.camera = camera;
  }

this.setRenderer

setRenderer() {
    const { THREE, innerWidth, innerHeight } = window;
    const renderer = new THREE.WebGLRenderer({ antialias: false });
    renderer.setSize(innerWidth, innerHeight * this.windowMultiplier);
    this.renderer = renderer;
  }

this.start this.stop this.animate

start() {
    if (!this.frameId) {
      this.frameId = requestAnimationFrame(this.animate);
    }
  }

  stop() {
    cancelAnimationFrame(this.frameId);
  }

  animate() {
    this.renderScene();
    this.frameId = window.requestAnimationFrame(this.animate);
    if (!!this.controls) {
      this.controls.update();
    }
  }

2 个答案:

答案 0 :(得分:0)

Object3D .lookAt方法需要一个位于世界空间中的位置:

var position = new THREE.Vector3().copy( child.position );
child.localToWorld( position );
camera.lookAt( position );

使用TrackballControls或OrbitControl会使这一点复杂化,我不确定lookAt是否可以与所涉及的任何一个正常工作。

three.js r89

答案 1 :(得分:0)

我明白了!我的所有代码都完美无缺,问题出现在.obj本身,所有孩子的枢轴点与父母一样,他们不在对象的中心(如何期待):

Here you can see the highlighted object (a child) and its pivot point (same as the parent, which is wrong)