Javascript 如何使相机适合对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14614252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Fit Camera to Object
提问by fungus1487
Using three.js I have the following.
使用three.js我有以下内容。
- A scene containing several Object3D instances
- Several predefined camera Vector3 positions
- A dynamic width/height of the canvas if the screen resizes
- A user can select an object (from above)
- A user can select a camera position (from above)
- 包含多个 Object3D 实例的场景
- 几个预定义的相机 Vector3 位置
- 如果屏幕调整大小,则画布的动态宽度/高度
- 用户可以选择一个对象(从上面)
- 用户可以选择相机位置(从上方)
Given an object being viewed and the camera position they have chosen how do I compute the final camera position to "best fit" the object on screen?
给定正在查看的对象和他们选择的相机位置,我如何计算最终相机位置以“最适合”屏幕上的对象?
If the camera positions are used "as is" on some screens the objects bleed over the edge of my viewport whilst others they appear smaller. I believe it is possible to fit the object to the camera frustum but haven't been able to find anything suitable.
如果在某些屏幕上“按原样”使用相机位置,则对象会溢出我的视口边缘,而其他对象则显得更小。我相信可以将物体安装到相机视锥体上,但一直找不到合适的东西。
回答by WestLangley
I am assuming you are using a perspective camera.
我假设您使用的是透视相机。
You can set the camera's position, field-of-view, or both.
您可以设置相机的位置、视野或两者。
The following calculation is exact for an object that is a cube, so think in terms of the object's bounding box, aligned to face the camera.
以下计算对于立方体对象是准确的,因此请考虑对象的边界框,对齐以面向相机。
If the camera is centered and viewing the cube head-on, define
如果相机居中并正面查看立方体,则定义
dist = distance from the camera to the _closest face_ of the cube
and
和
height = height of the cube.
If you set the camera field-of-view as follows
如果按如下方式设置相机视野
fov = 2 * Math.atan( height / ( 2 * dist ) ) * ( 180 / Math.PI ); // in degrees
then the cube height will match the visible height.
那么立方体高度将匹配可见高度。
At this point, you can back the camera up a bit, or increase the field-of-view a bit.
此时,您可以将相机后退一点,或将视野扩大一点。
If the field-of-view is fixed, then use the above equation to solve for the distance.
如果视场是固定的,那么使用上面的方程来求解距离。
EDIT: If you want the cube widthto match the visible width, let aspectbe the aspect ratio of the canvas ( canvas width divided by canvas height ), and set the camera field-of-view like so
编辑:如果您希望立方体width与可见宽度相匹配,则aspect设为画布的纵横比(画布宽度除以画布高度),并像这样设置相机视野
fov = 2 * Math.atan( ( width / aspect ) / ( 2 * dist ) ) * ( 180 / Math.PI ); // in degrees
three.js r.69
三.js r.69
回答by shi
Based on WestLangleys answer here is how you calculate the distance with a fixed camera field-of-view:
根据 WestLangleys 的回答,这里是如何使用固定的相机视场计算距离:
dist = height / 2 / Math.tan(Math.PI * fov / 360);
回答by Andy Ray
To calculate how far away to place your camera to fit an object to the screen, you can use this formula (in Javascript):
要计算将相机放置多远以适合屏幕的对象,您可以使用以下公式(在 Javascript 中):
// Convert camera fov degrees to radians
var fov = camera.fov * ( Math.PI / 180 );
// Calculate the camera distance
var distance = Math.abs( objectSize / Math.sin( fov / 2 ) );
Where objectSizeis the height or width of the object. For cube/sphere objects you can use either the height or width. For a non-cube/non-sphere object, where length or width is greater, use var objectSize = Math.max( width, height )to get the larger value.
哪里objectSize是物体的高度或宽度。对于立方体/球体对象,您可以使用高度或宽度。对于长度或宽度较大的非立方体/非球体对象,使用var objectSize = Math.max( width, height )来获取较大的值。
Note that if your object position isn't at 0, 0, 0, you need to adjust your camera position to include the offset.
请注意,如果您的对象位置不在0, 0, 0,则需要调整相机位置以包括偏移。
Here's a CodePenshowing this in action. The relevant lines:
这是一个 CodePen,展示了这一点。相关线路:
var fov = cameraFov * ( Math.PI / 180 );
var objectSize = 0.6 + ( 0.5 * Math.sin( Date.now() * 0.001 ) );
var cameraPosition = new THREE.Vector3(
0,
sphereMesh.position.y + Math.abs( objectSize / Math.sin( fov / 2 ) ),
0
);
You can see that if you grab the window handle and resize it, the sphere still takes up 100% of the screen height. Additionally, the object is scaling up and down in a sine wave fashion (0.6 + ( 0.5 * Math.sin( Date.now() * 0.001 ) )), to show the camera position takes into account scale of the object.
你可以看到,如果你抓住窗口句柄并调整它的大小,球体仍然占据屏幕高度的 100%。此外,对象以正弦波方式 ( 0.6 + ( 0.5 * Math.sin( Date.now() * 0.001 ) ))放大和缩小,以显示相机位置考虑了对象的比例。
回答by Matt
try this for OrbitControls
试试这个 OrbitControls
let padding = 48;
let w = Math.max(objectLength, objectWidth) + padding;
let h = objectHeight + padding;
let fovX = camera.fov * (aspectX / aspectY);
let fovY = camera.fov;
let distanceX = (w / 2) / Math.tan(Math.PI * fovX / 360) + (w / 2);
let distanceY = (h / 2) / Math.tan(Math.PI * fovY / 360) + (w / 2);
let distance = Math.max(distanceX, distanceY);
回答by jimf
From user151496's suggestion about using the aspect ratio, this seems to work, although I've only tested with a few different parameter sets.
从 user151496 关于使用纵横比的建议来看,这似乎有效,尽管我只测试了几个不同的参数集。
var maxDim = Math.max(w, h);
var aspectRatio = w / h;
var distance = maxDim/ 2 / aspectRatio / Math.tan(Math.PI * fov / 360);
回答by samm
I had the same question but I expected the object(s) (represented by a Box3as a whole) could rotate on my phone if the whole was wider than my screen so I could view it by zooming in as near as possible.
我有同样的问题,但我希望对象(由Box3整体表示)可以在我的手机上旋转,如果整体比我的屏幕宽,所以我可以通过尽可能近地放大来查看它。
const objectSizes = bboxMap.getSize();
console.log('centerPoint', centerPoint, bboxMap, objectSizes, tileMap);
//setupIsometricOrthographicCamera(bboxMap);
//https://gamedev.stackexchange.com/questions/43588/how-to-rotate-camera-centered-around-the-cameras-position
//https://threejs.org/docs/#api/en/cameras/PerspectiveCamera
//https://stackoverflow.com/questions/14614252/how-to-fit-camera-to-object
// Top
// +--------+
// Left | Camera | Right
// +--------+
// Bottom
// canvas.height/2 / disance = tan(fov); canvas.width/2 / disance = tan(fovLR);
// => canvas.width / canvas.height = tan(fovLR)/tan(fov);
// => tan(fovLR) = tan(fov) * aspectRatio;
//If rotating the camera around z-axis in local space by 90 degrees.
// Left
// +---+
// Bottom | | Top
// | |
// +---+
// Right
// => tan(fovLR) = tan(fov) / aspectRatio;
const padding = 0, fov = 50;
let aspectRatio = canvas.width / canvas.height;
let tanFOV = Math.tan(Math.PI * fov / 360);
let viewWidth = padding + objectSizes.x, viewHeight = padding + objectSizes.y;
//The distances are proportional to the view's with or height
let distanceH = viewWidth / 2 / (tanFOV * aspectRatio);
let distanceV = viewHeight / 2 / tanFOV;
const camera = this.camera = new THREE.PerspectiveCamera(fov, aspectRatio, 0.1, 10000); //VIEW_ANGLE, ASPECT, NEAR, FAR
if (aspectRatio > 1 != viewWidth > viewHeight) {
console.log('screen is more narrow than the objects to be viewed');
// viewWidth / canvas.width => viewHeight / canvas.width
// viewHeight / canvas.height => viewWidth / canvas.height;
distanceH *= viewHeight / viewWidth;
distanceV *= viewWidth / viewHeight;
camera.rotateZ(Math.PI / 2);
}
camera.position.z = Math.max(distanceH, distanceV) + bboxMap.max.z;
//camera.lookAt(tileMap.position);
I had tested two different aspect of Box3on tow different orientations (landscape and portrait) using my phone, it worked well.
我Box3使用手机测试了两个不同方向(横向和纵向)的两个不同方面,效果很好。
References
参考
- Box3.getSize ( target : Vector3 ) : Vector3
target— the result will be copied into thisVector3. Returns the width, height and depth of this box. - Object3D.rotateZ ( rad : Float ) : this(PerspectiveCamera)
rad- the angle to rotate in radians. Rotates the object around z axis in local space. - Other answers
- Box3.getSize(目标:Vector3):Vector3
target- 结果将被复制到 this 中Vector3。返回此框的宽度、高度和深度。 - Object3D.rotateZ ( rad : Float ) : this(PerspectiveCamera)
rad- 以弧度为单位旋转的角度。在局部空间中围绕 z 轴旋转对象。 - 其他答案

