每次摄像机位置在三个.js中发生变化时都会触发代码



每次相机位置更改时,如何触发代码?

这就是我目前所拥有的:

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

如果您使用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);

如注释中所述,您应该自己检查更改

使用三帧渲染-您有渲染循环并调用

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中,您应该比较投影矩阵、位置、矩阵、缩放等(查看Object3D参数和Camera参数并进行一些实验)

有了这样的代码,你可以创建一个懒惰的渲染循环,只在相机改变时渲染,将你的平均FPS提高一点

将一个事件更改为相机更改是不好的,因为它可以在一帧中更改多次(例如,重力将其向下移动,用户移动鼠标以更改旋转,并按下按键以更改位置-每帧可能发生不止一次的3个更改源)-您会经常调用代码,并且可能会冗余地调用

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

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

这里有一个例子:

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>

更新:注意,在一些控件中,当我写这个答案时,three.js中没有这个功能(不确定它现在是否可用)。

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原型分配自定义对象原型,如文档所示:

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

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

相关内容

最新更新