每次摄像头位置变化的消防代码为three.js

时间:2015-11-29 14:27:53

标签: three.js

每次相机位置发生变化时如何触发代码?

这是我到目前为止所做的:

camera.addEventListener("change", function(event){
// my code
});

4 个答案:

答案 0 :(得分:1)

如果您使用OrbitControls.js来控制相机,那么当它的更新功能导致相机变焦,平移或旋转时,该库会触发更改事件;

https://github.com/mrdoob/three.js/blob/master/examples/js/controls/OrbitControls.js#L203

例如,您可以使用类似的东西来响应相机的移动;

  function onPositionChange(o) {

    console.log("position changed in object");
    console.log(o);
  }

  controls.addEventListener('change', onPositionChange);

答案 1 :(得分:0)

如评论中所述,您应自行检查更改

使用THREE渲染帧 - 你有渲染循环并调用

renderer.render();
在里面 只需创建另一个相机并在每次渲染后从真实相机复制到相机

通过这种方式,您可以保持状态,并在使用相机进行操作后,只需检查相机是否已更改

var camera2 = camera.clone()
render()
{
    doStuffWithCamera();
    var cameraChanged = compareCameras(camera, camera2);
    if(cameraChanged)
    {
         //execute code you want to when camera changed
    }
    renderer.render(scene,camera);
    camera2.copy(camera);
}
在compareCameras中你应该比较projectionMatrix,position,matrix,zoom等等(看看Object3D参数和Camera参数并稍微试验一下)

使用这样的代码,你可以创建一个懒惰的渲染循环,只有当摄像机改变你的平均FPS时才会渲染

将事件附加到相机更改会很糟糕,因为它可以在一个帧中多次更改(例如,重力将其向下移动,用户移动鼠标以更改旋转并按下键也可以更改位置 - 3个更改源每帧可以发生多次) - 你会经常调用你的代码,可能是多余的

答案 2 :(得分:0)

three.js为此使用EventDispatcher。您可以看看它在OrbitControls内部是如何实现的。想法是使用较小的阈值检查相机位置/旋转变化,并在满足条件后立即触发dispatchEvent。所以这是实现它的方法:

if( lastPosition.distanceToSquared( scope.camera.position )   > 0.000001 ||
    8 * ( 1 - lastQuaternion.dot( scope.camera.quaternion ) ) > 0.000001 )
{
  scope.dispatchEvent( { type: 'change',
                         position: scope.camera.position } );

  // store position/quaternion for the next iteration
  lastPosition.copy( scope.camera.position );
  lastQuaternion.copy( scope.camera.quaternion );
}

要能够分派这样的事件,必须确保为自定义对象原型分配了EventDispatcher原型,如documentation所示:

Object.assign( Foo.prototype, EventDispatcher.prototype );

然后,您可以添加事件侦听器,该侦听器将侦听相机更改事件。

答案 3 :(得分:-1)

Three.js 对象 (fe .position) 的 camera.position 属性(当前)不会发出您可以监听的任何事件,因此我们无法(开箱即用)观察更改到它。

但是,我们可以修补相机的 .position 对象(或所有 Vector3 实例的原型,例如)以使用 Three 的 EventDispatcher 类手动添加事件系统。< /p>

这是一个例子:

const {Vector3, EventDispatcher, PerspectiveCamera} = THREE

// Dynamically modify the Vector3 class so that now it will
// use THREE's event system (which is called EventDispatcher).
Object.assign(Vector3.prototype, EventDispatcher.prototype)

// Patch any method that you wish, so they will emit an event
// when you use them. Here we've only patched the `Vector3.set` method.
{
  // Get the reference to the original method.
  const original = Vector3.prototype.set
  
  // Define a new method that calls the old one, and also
  // emits an event.
  Vector3.prototype.set = function(...args) {
    // Call the original with any arguments, if any:
    const returnValue = original.apply(this, args)
    
    // Dispatch an event.
    this.dispatchEvent({type: 'change'})
    
    // Don't forget to return the original's return value,
    // if any:
    return returnValue
  }
}

// Now, as an example, let's make a new camera, and
// change its position every second, and write the
// position to the screen:
{
  // Update a camera's position every second.
  const camera = new PerspectiveCamera()
  setInterval(() => {
    // camera.position has a patched set() method.
    const pos = camera.position
    pos.set(pos.x + 1, pos.y + 2, pos.z + 3)
  }, 1000)
  
  // Listen to our new 'change' event on camera.position:
  const output = document.querySelector('pre')
  camera.position.addEventListener('change', () => {
    output.innerText = `
    Camera's position: {
      x: ${camera.position.x},
      y: ${camera.position.y},
      z: ${camera.position.z}
    }`
  })
}
<script src="https://unpkg.com/three@0.124.0/build/three.js"></script>

<pre>
    
    Camera's position: {
      x: 0,
      y: 0,
      z: 0
    }
</pre>