我有一个场景可以加载一个.obj
文件。
我不会使用PerspectiveCamera
来开始在相机中完全可见物体的场景。
TrackballControls
用于控制相机我尝试了this solution,但是没有用。
代码:
FOV = 60
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera( FOV, 500 / 350, 0.1, 10000 )
scene.add( camera )
objLoader = new THREE.OBJLoader();
objLoader.load('/airboat.obj', function (object) {
scene.add( object )
var boundingBox = new THREE.Box3();
boundingBox.setFromObject( object );
var sphere = boundingBox.getBoundingSphere()
// don't work
var center = boundingBox.getCenter();
var size = boundingBox.getSize();
var maxDim = Math.max( size.x, size.y, size.z );
var cameraZ = maxDim / 2 / Math.tan(Math.PI * FOV / 360);
camera.lookAt(center)
camera.position.set( center.x, center.y, cameraZ );
camera.updateProjectionMatrix();
})
编辑
我创建了this fiddle(向下滚动JS代码),@ Brakebein解决方案在大多数情况下都有效,但是有时边界框的边缘不可见
答案 0 :(得分:2)
新的摄影机目标是球体的中心,新的摄影机位置沿当前视线的相反方向移动了计算的距离:
视线是从camera.position
到controls.target
的向量
var current_los = new THREE.Vector3().subVectors(controls.target, camera.position);
计算一个新的位置正离子的目标如下:
var new_pos = new THREE.Vector3().addVectors(center, current_los.setLength(-cameraZ));
var new_target = center;
在调用position
之前,还必须设置摄像机的look At
,因为该功能取决于位置,并且必须更新controls
:
var boundingBox = new THREE.Box3();
boundingBox.setFromObject( group );
var center = boundingBox.getCenter();
var size = boundingBox.getSize();
var distance = Math.max( size.x, size.y, size.z );
//var distance = boundingBox.getBoundingSphere().radius * 2;
//var cameraZ = distance / 2 / Math.tan(Math.PI * FOV / 360);
var cameraZ = distance / 2 / Math.sin(Math.PI * FOV / 360);
var current_los = new THREE.Vector3().subVectors(controls.target, camera.position);
var new_pos = new THREE.Vector3().addVectors(center, current_los.setLength(-cameraZ));
var new_target = center;
// copy values
camera.position.copy(new_pos);
camera.lookAt(center);
controls.target.copy(center);
controls.update();
如果使用包裹边界框的球体的直径而不是框的最大角度长度,则将获得稍大的图像部分:
var distance = boundingBox.getBoundingSphere().radius * 2;
但是请注意,这可能仍无法满足您的要求。查看图片:
要执行此操作的可能性:
因此,您必须使用正弦而不是切线:
sin(FOV/2) == (maxDim/2) / cameraZ;
var cameraZ = maxDim / 2 / Math.sin(Math.PI * FOV / 360);
答案 1 :(得分:1)
设置相机位置后,您可以尝试致电camera.lookAt(center)
:
camera.position.set( center.x, center.y, cameraZ );
camera.lookAt(center);
或者您可以尝试使用BoundingSphere的方法,因为我在项目中使用它来将对象适合视图中:(我使用的是OrbitControls
,但它应该与TrackballControls
相同)
var sphere = boundingBox.getBoundingSphere();
// compute new distance between camera and center of object/sphere
var h = sphere.radius / Math.tan( camera.fov / 2 * THREE.Math.DEG2RAD );
// get direction of camera (when using Orbit or TrackballControls, the camera is
// always pointing to the control's target, so I'm using this)
var dir = new THREE.Vector3().subVectors(camera.position, controls.target);
// compute new camera position
var newPos = new THREE.Vector3().addVectors(sphere.center, dir.setLength(h));
// copy values
camera.position.copy(newPos);
controls.target.copy(sphere.center);
camera.lookAt(controls.target); // -> you don't need to call this as this is already part of controls.update() routine
提示:确保相机和控件不在同一位置。否则,将无法计算方向。
编辑:好的,我从@ Rabbid76的图中得到了提示:我的解决方案基本上与第一个解决方案一致。在某些情况下,对象或边界框的某些部分将位于视锥体的外部。因此,第二张图中显示的方法更好。为此,我们只需要将tan
更改为sin
:
var h = sphere.radius / Math.sin( camera.fov / 2 * THREE.Math.DEG2RAD );
答案 2 :(得分:0)
加载.obj,然后将摄影机设置为.obj的“中心”,就是告诉摄影机移至已加载的obj的确切中心,而不是将其加载到视图。
var center = boundingBox.getCenter(); //This gets the exact center of the box
您想要做的就是获取要加载的对象的宽度和深度,并从其中心位置减去它。
例如
camera.position.set( center.x - size.x, center.y - size.y, cameraZ - size.z );
上面的代码段(未测试)将使摄像头位置移回要加载对象的整个大小,这应该会使其可见。您还可以减去另一个“缓冲区”,这样一来,您就可以看到更多的图像,而不是总边缘。
希望这会有所帮助