每次相机位置更改时,如何触发代码?
这就是我目前所拥有的:
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 );
然后您可以添加事件侦听器,它将侦听您的相机更改事件。