fun*_*487 36 javascript three.js
使用three.js我有以下内容.
给定正在查看的对象和摄像机位置,他们选择如何计算最终摄像机位置以"最佳地适应"屏幕上的对象?
如果在某些屏幕上"按原样"使用摄像机位置,则对象会在我的视口边缘流血,而其他位置则显得较小.我相信可以将物体安装到相机平截头体上,但却找不到合适的物体.
Wes*_*ley 60
我假设你正在使用透视相机.
您可以设置摄像机的位置,视野或两者.
以下计算对于作为立方体的对象是精确的,因此请根据对象的边界框进行思考,对齐以面向相机.
如果相机居中并正面观看立方体,请定义
dist = distance from the camera to the _closest face_ of the cube
Run Code Online (Sandbox Code Playgroud)
和
height = height of the cube.
Run Code Online (Sandbox Code Playgroud)
如果您按如下方式设置摄像机视野
fov = 2 * Math.atan( height / ( 2 * dist ) ) * ( 180 / Math.PI ); // in degrees
Run Code Online (Sandbox Code Playgroud)
然后立方体高度将匹配可见高度.
此时,您可以将相机向后移动一点,或稍微增加视野.
如果视场是固定的,则使用上面的等式来求解距离.
编辑:如果您希望立方体width匹配可见宽度,请aspect设置画布的宽高比(画布宽度除以画布高度),并设置摄像机视野,如此
fov = 2 * Math.atan( ( width / aspect ) / ( 2 * dist ) ) * ( 180 / Math.PI ); // in degrees
Run Code Online (Sandbox Code Playgroud)
three.js r.69
shi*_*shi 17
基于WestLangleys,这里的答案是如何使用固定的摄像机视野计算距离:
dist = height / 2 / Math.tan(Math.PI * fov / 360);
Run Code Online (Sandbox Code Playgroud)
And*_*Ray 11
要计算将相机放置到适合屏幕的对象的距离,您可以使用此公式(在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 ) );
Run Code Online (Sandbox Code Playgroud)
objectSize物体的高度或宽度在哪里.对于立方体/球体对象,您可以使用高度或宽度.对于长度或宽度较大的非立方体/非球体对象,请使用var objectSize = Math.max( width, height )以获得更大的值.
请注意,如果您的物体位置不在0, 0, 0,则需要调整相机位置以包含偏移.
这是一个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
);
Run Code Online (Sandbox Code Playgroud)
您可以看到,如果您抓住窗口手柄并调整其大小,则球体仍占据屏幕高度的100%.此外,对象以正弦波方式(0.6 + ( 0.5 * Math.sin( Date.now() * 0.001 ) ))向上和向下缩放,以显示摄像机位置考虑对象的比例.
假设物体适合屏幕(如果它的边界球体适合),我们将任务简化为将球体适合相机视图。
在给定的示例中,我们保持PerspectiveCamera.fov不变,同时更改相机旋转以获得对象的最佳视角。缩放效果是通过沿着.lookAt方向向量移动相机来实现的。
从图中你可以看到问题的定义: 给定边界球和camera.fov,找到L,使边界球接触相机的截锥平面。
以下是计算从球体到相机的所需距离的方法:
完整的解决方案: https: //jsfiddle.net/mmalex/h7wzvbkt/
var renderer;
var camera;
var scene;
var orbit;
var object1;
function zoomExtents() {
let vFoV = camera.getEffectiveFOV();
let hFoV = camera.fov * camera.aspect;
let FoV = Math.min(vFoV, hFoV);
let FoV2 = FoV / 2;
let dir = new THREE.Vector3();
camera.getWorldDirection(dir);
let bb = object1.geometry.boundingBox;
let bs = object1.geometry.boundingSphere;
let bsWorld = bs.center.clone();
object1.localToWorld(bsWorld);
let th = FoV2 * Math.PI / 180.0;
let sina = Math.sin(th);
let R = bs.radius;
let FL = R / sina;
let cameraDir = new THREE.Vector3();
camera.getWorldDirection(cameraDir);
let cameraOffs = cameraDir.clone();
cameraOffs.multiplyScalar(-FL);
let newCameraPos = bsWorld.clone().add(cameraOffs);
camera.position.copy(newCameraPos);
camera.lookAt(bsWorld);
orbit.target.copy(bsWorld);
orbit.update();
}
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(54, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 15;
camera.position.y = 15;
camera.position.z = 15;
camera.lookAt(0, 0, 0);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0xfefefe));
document.body.appendChild(renderer.domElement);
orbit = new THREE.OrbitControls(camera, renderer.domElement);
// create light
{
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(0, 100, 50);
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.near = 500;
spotLight.shadow.camera.far = 4000;
spotLight.shadow.camera.fov = 30;
scene.add(spotLight);
}
var root = new THREE.Object3D();
scene.add(root);
function CustomSinCurve(scale) {
THREE.Curve.call(this);
this.scale = (scale === undefined) ? 1 : scale;
}
CustomSinCurve.prototype = Object.create(THREE.Curve.prototype);
CustomSinCurve.prototype.constructor = CustomSinCurve;
CustomSinCurve.prototype.getPoint = function(t) {
var tx = t * 3 - 1.5;
var ty = Math.sin(2 * Math.PI * t);
var tz = 0;
return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
};
var path = new CustomSinCurve(10);
var geometry = new THREE.TubeGeometry(path, 20, 2, 8, false);
var material = new THREE.MeshPhongMaterial({
color: 0x20f910,
transparent: true,
opacity: 0.75
});
object1 = new THREE.Mesh(geometry, material);
object1.geometry.computeBoundingBox();
object1.position.x = 22.3;
object1.position.y = 0.2;
object1.position.z = -1.1;
object1.rotation.x = Math.PI / 3;
object1.rotation.z = Math.PI / 4;
root.add(object1);
object1.geometry.computeBoundingSphere();
var geometry = new THREE.SphereGeometry(object1.geometry.boundingSphere.radius, 32, 32);
var material = new THREE.MeshBasicMaterial({
color: 0xffff00
});
material.transparent = true;
material.opacity = 0.35;
var sphere = new THREE.Mesh(geometry, material);
object1.add(sphere);
var size = 10;
var divisions = 10;
var gridHelper = new THREE.GridHelper(size, divisions);
scene.add(gridHelper);
var animate = function() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
Run Code Online (Sandbox Code Playgroud)
尝试使用 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);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
27625 次 |
| 最近记录: |