每次相机位置发生变化时如何触发代码?
这是我到目前为止所做的:
camera.addEventListener("change", function(event){
// my code
});
答案 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>