[英]Three.js - How to check if object is behind a sphere (not visible)
我有一个球体(球体),表面上有带有DOM元素(标签)的对象(销),这些元素是从销位置到2D世界的。
我的问题是,当图钉落后于地球(通过鼠标拖动或动画)时,我需要隐藏DOM中的标签,以便没有图钉时文本标签不可见。
我的逻辑是,如果我可以得到3D世界中的图钉来告诉我它是否在地球后面,那么我可以隐藏与图钉关联的标签。
Codepen与整个代码。
我一起研究的功能:
function checkPinVisibility() {
var startPoint = camera.position.clone();
for (var i = 0; i < pins.length; i++) {
var direction = pins[i].position.clone();
var directionVector = direction.sub(startPoint);
raycaster.set(startPoint, directionVector.clone().normalize());
var intersects = raycaster.intersectObject(pins[i]);
if (intersects.length > 0) {
// ?
}
}
}
我已经研究了许多帖子,但无法真正获得所需的结果:
我已经通过鼠标的XY位置作为射线来使它工作,但是不能真正获得对所有销钉进行恒定渲染的有效解决方案。
您想知道球体表面上的哪些点对相机可见。
想象一下相机中与球体相切的一条线。 令L
为从摄像机到切线的线的长度。
相机只能看到球体上比L
更靠近相机的点。
L
的公式为L
L = sqrt( D^2 - R^2 )
,其中D是从摄像机到球体中心的距离, R
是球体半径。
WestLangley的代码形式的解决方案。 如果您觉得他的回答最好,请给他接受的答案。
function checkPinVisibility() {
var cameraToEarth = earth.position.clone().sub(camera.position);
var L = Math.sqrt(Math.pow(cameraToEarth.length(), 2) - Math.pow(earthGeometry.parameters.radius, 2));
for (var i = 0; i < pins.length; i++) {
var cameraToPin = pins[i].position.clone().sub(camera.position);
if(cameraToPin.length() > L) {
pins[i].domlabel.style.visibility = "hidden";
} else {
pins[i].domlabel.style.visibility = "visible";
}
}
}
奇怪的是,它仍然容易受到该相机平移错误的影响。 非常奇怪,但是它仍然比我的Projection-onto-LOOKAT解决方案要好。
我的老答案:
我本来以为是这样,但这似乎并没有按预期工作。
if (intersects.length > 0) {
pins[i].domlabel.style.visibility = "visible";
} else {
pins[i].domlabel.style.visibility = "hidden";
}
我已经接近这个解决方案,但是它仍然不是完美的。 下面的代码要做的是找到沿照相机的LOOKAT方向到销钉的距离(cameraToPinProjection),并将其与沿照相机的LOOKAT方向到地球的距离(cameraToEarthProjection)进行比较。 如果cameraToPinProjection> cameraToEarthProjection,则表示该销钉沿LOOKAT方向位于地球中心后面(然后隐藏该销钉)。
您将意识到我将cameraToEarth投影乘以了一个“ 0.8”因子。 这是为了使其稍短一些。 尝试一下。
这并不完美,因为当您绕地球旋转时,您会发现有时标签的作用不符合您的期望,我不确定如何解决。
我希望这有帮助。
function checkPinVisibility() {
var LOOKAT = new THREE.Vector3( 0, 0, -1 );
LOOKAT.applyQuaternion( camera.quaternion );
var cameraToEarth = earth.position.clone().sub(camera.position);
var angleToEarth = LOOKAT.angleTo(cameraToEarth);
var cameraToEarthProjection = LOOKAT.clone().normalize().multiplyScalar(0.8 * cameraToEarth.length() * Math.cos(angleToEarth));
var startPoint = camera.position.clone();
for (var i = 0; i < pins.length; i++) {
var cameraToPin = pins[i].position.clone().sub(camera.position);
var angleToPin = LOOKAT.angleTo(cameraToPin);
var cameraToPinProjection = LOOKAT.clone().normalize().multiplyScalar(cameraToPin.length() * Math.cos(angleToPin));
if(cameraToPinProjection.length() > cameraToEarthProjection.length()) {
pins[i].domlabel.style.visibility = "hidden";
} else {
pins[i].domlabel.style.visibility = "visible";
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.