Open zp1112 opened 6 years ago
要求:该连线必须从球体的边缘出发 已知:球体在三维空间中的半径,球体中心坐标 实现方案:
效果:
代码:
var sourcePosition3D = new THREE.Vector3(0, 0, 0); var targetPosition3D = new THREE.Vector3(0, 0, 0); sourcePosition3D.copy(sourceSphere.sphere.position); // 球心坐标 targetPosition3D.copy(targetSphere.sphere.position); var sourcePoint = HelperMethods.get2DCoords(sourcePosition3D, camera, this.width, this.height); var targetPoint = HelperMethods.get2DCoords(targetPosition3D, camera, this.width, this.height); const sourced = sourceSphere.sphere.position.distanceTo(camera.position) // 视角到球心的距离 const sourceRadius = HelperMethods.computeProjectedRadius(camera.fov, sourced, sourceSphere.sphere.geometry.parameters.radius * sourceSphere.sphere.scale.x, this.width, this.height); const targetd = targetSphere.sphere.position.distanceTo(camera.position) const targetRadius = HelperMethods.computeProjectedRadius(camera.fov, targetd, targetSphere.sphere.geometry.parameters.radius * targetSphere.sphere.scale.x, this.width, this.height); const tan = (targetPoint.y - sourcePoint.y) / (targetPoint.x - sourcePoint.x); const deg = Math.atan(tan); const diffx = targetPoint.x - sourcePoint.x; const diffy = targetPoint.y - sourcePoint.y; diffx > 0 ? sourcePoint.x = sourcePoint.x + sourceRadius * Math.abs(Math.cos(deg)) : sourcePoint.x = sourcePoint.x - sourceRadius * Math.abs(Math.cos(deg)); diffy > 0 ? sourcePoint.y = sourcePoint.y + sourceRadius * Math.abs(Math.sin(deg)) : sourcePoint.y = sourcePoint.y - sourceRadius * Math.abs(Math.sin(deg)); const tan1 = (sourcePoint.y - targetPoint.y) / (sourcePoint.x - targetPoint.x); const deg1 = Math.atan(tan1); const diffx1 = targetPoint.x - sourcePoint.x; const diffy1 = targetPoint.y - sourcePoint.y; diffx1 > 0 ? targetPoint.x = targetPoint.x - targetRadius * Math.abs(Math.cos(deg1)) : targetPoint.x = targetPoint.x + targetRadius * Math.abs(Math.cos(deg1)); diffy1 > 0 ? targetPoint.y = targetPoint.y - targetRadius * Math.abs(Math.sin(deg1)) : targetPoint.y = targetPoint.y + targetRadius * Math.abs(Math.sin(deg1));
关键方法 computeProjectedRadius
computeProjectedRadius: function(fovy, d, r, width, height) { var fov; fov = fovy / 2 * Math.PI / 180.0; // zoom = r / R = d / D = d / height / (2 * Math.tan(fov)) = d * 2 * Math.tan(fov) / height; // so R = r / (d * 2 * Math.tan(fov) / height) return r / (Math.tan(fov) * d * 2 / height); // Right }
关键在于一个比例问题,参考这张图
其中 zoom = d / D
D:相机与屏幕所在平面的距离, d:相机与元素A的距离
在球体上体现为,d为相机到球心的距离,D可以通过H和fov视野角度求出,所以 zoom = d / D = r / R
画两个球体之间的连线
要求:该连线必须从球体的边缘出发 已知:球体在三维空间中的半径,球体中心坐标 实现方案:
效果:
代码:
关键方法 computeProjectedRadius
关键在于一个比例问题,参考这张图
其中 zoom = d / D
D:相机与屏幕所在平面的距离, d:相机与元素A的距离
在球体上体现为,d为相机到球心的距离,D可以通过H和fov视野角度求出,所以 zoom = d / D = r / R