示意图
两个API
const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
const camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
引擎里面两种相机
const cameraPer = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
const cameraOrt = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
camera = cameraPer;
controls.object = this.camera;
互转
- 透视相机转正交相机
- 相机位置到target的点,distince=this.perspectiveCameraWP.distanceTo(this.controls.target)
- 透视矩阵的高度 distince/tan(π/2 - fov/2)*2
transPerspectPosToOrthographicZoom(screenHeight) {
screenHeight = screenHeight || this.screenHeight;
this.perspectiveCamera.getWorldPosition(this.perspectiveCameraWP);
const distancePCamGroup = this.perspectiveCameraWP.distanceTo(this.controls.target);
var vFOV = THREE.MathUtils.degToRad(this.perspectiveCamera.fov); // convert vertical fov to radians
var viewHeight = 2 * Math.tan(vFOV / 2) * distancePCamGroup; // visible height
return screenHeight / viewHeight;
}
- window.resize 透视/正交都只会随着高度变化 不随着宽度变化
凡是关于相机的shader都要进行更新
- outline
- ssao
正交相机与其他端
- 这个是获取实际的相机top/bottom/left/right的参数
function zoomToProjectionParam(orthoCamera){
if(!orthoCamera.isOrthographicCamera) return;
const dx = (orthoCamera.right - orthoCamera.left) / (2 * orthoCamera.zoom);
const dy = (orthoCamera.top - orthoCamera.bottom) / (2 * orthoCamera.zoom);
const cx = (orthoCamera.right + orthoCamera.left) / 2;
const cy = (orthoCamera.top + orthoCamera.bottom) / 2;
return {
left: cx - dx,
right: cx + dx,
top: cy + dy,
bottom: cy - dy
}
}
- 这里是screenHeight/2与真实相机bottom的比例
function projectionParamToZoomBottom(orthoCamera, param){
let { bottom } = param;
if(!orthoCamera.isOrthographicCamera) return;
const cx = (orthoCamera.bottom + orthoCamera.top) / 2;
const dx = cx - bottom;
const zoom = (orthoCamera.top - orthoCamera.bottom) / (2 * dx);
return zoom;
}
物体屏幕空间的中心
- 计算中心
function computeBounding(obj3d){
const boxH = new THREE.BoxHelper(obj3d, 0x000000);
boxH.geometry.computeBoundingBox();
const max = boxH.geometry.boundingBox.max;
const min = boxH.geometry.boundingBox.min;
return {
max : max,
min : min,
mid : new THREE.Vector3(
(max.x + min.x) / 2,
(max.y + min.y) / 2,
(max.z + min.z) / 2
)
}
}
- 计算boundingbox和相机到物体中心点的距离
computeAutoCenterDistance(width, height, distanceFactor) {
const boundingBox = computeBounding(this.componentGroup);
let { max, min, mid } = boundingBox;
const yLen = max.y - min.y;
const xLen = max.x - min.x;
const ht = (height - yLen) / height;
const wt = (width - xLen) / width;
// 仅依赖BoundingBox的自适应居中(Fov不能动态改变)
distanceFactor = distanceFactor || this.cameraCenterFactor;
let distance = max.distanceTo(min) * distanceFactor;
let zoom = ht >= wt ? width / xLen : height / yLen;
zoom *= this.cameraSpaceGap;
return {
boundingBox,
distance,
zoom //基本没用
};
}
- 设置相机(透视,透视转正交)的位置
setCameraToCenter(width, height) {
let { boundingBox, distance } = this.computeAutoCenterDistance(width, height);
let { max, min, mid } = boundingBox;
// PerspectiveCamera
let perspectiveCamera = this.view.perspectiveCamera;
perspectiveCamera.position.set(mid.x, mid.y, mid.z + distance / this.cameraSpaceGap);
perspectiveCamera.updateProjectionMatrix();
this.controls.target.set(mid.x, mid.y, mid.z);
this.controls.update();
// OrthographicCamera
this.view.syncOrthographicCameraTransform(height);
return {
boundingBox,
distance
};
}