繁体   English   中英

Three.js-如何检查对象是否在球体后面(不可见)

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM