Three.js-打开PerspectiveCamera显示边界球

时间:2018-06-22 10:13:32

标签: javascript three.js

我有一个场景可以加载一个.obj文件。

我不会使用PerspectiveCamera来开始在相机中完全可见物体的场景。

  • FOV固定为60
  • 对象的大小可变
  • 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解决方案在大多数情况下都有效,但是有时边界框的边缘不可见

3 个答案:

答案 0 :(得分:2)

新的摄影机目标是球体的中心,新的摄影机位置沿当前视线的相反方向移动了计算的距离:

视线是从camera.positioncontrols.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;

但是请注意,这可能仍无法满足您的要求。查看图片:

FOV sphere

要执行此操作的可能性:

FOV sphere 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 );

上面的代码段(未测试)将使摄像头位置移回要加载对象的整个大小,这应该会使其可见。您还可以减去另一个“缓冲区”,这样一来,您就可以看到更多的图像,而不是总边缘。

希望这会有所帮助