You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ThreeJS:投影与射线投射调整问题求助

解决方案

核心解决思路

别再手动设屏幕点了,直接盯着立方体要对齐的那条白色边缘反向推导:先把这条边缘的两个顶点投影到屏幕,算出这条投影线和屏幕左右边缘的交点,再把这些交点转成世界坐标的红点。这样不管怎么旋转相机,红点连线都会自动和立方体边缘的屏幕投影对齐。

具体实现步骤

  1. 拿到立方体目标边缘的两个顶点:比如你要对齐的白色边缘对应的两个世界坐标点,记为cubeEdgeA和cubeEdgeB。
  2. 把顶点转成屏幕像素坐标:
    const screenA = new THREE.Vector3();
    const screenB = new THREE.Vector3();
    // 先转成ThreeJS标准化设备坐标(NDC)
    cubeEdgeA.project(camera, screenA);
    cubeEdgeB.project(camera, screenB);
    // 再转成浏览器窗口的像素坐标
    screenA.x = (screenA.x * 0.5 + 0.5) * window.innerWidth;
    screenA.y = (-screenA.y * 0.5 + 0.5) * window.innerHeight;
    screenB.x = (screenB.x * 0.5 + 0.5) * window.innerWidth;
    screenB.y = (-screenB.y * 0.5 + 0.5) * window.innerHeight;
    
  3. 计算投影线与屏幕边缘的交点:
    用两点式推导直线方程,处理斜率无穷大的边界情况,算出这条线和屏幕左边缘(x=0)、右边缘(x=window.innerWidth)的交点:
    let leftScreen, rightScreen;
    // 处理垂直屏幕的边缘(斜率无穷大)
    if (Math.abs(screenA.x - screenB.x) < 0.001) {
        leftScreen = new THREE.Vector2(0, screenA.y);
        rightScreen = new THREE.Vector2(window.innerWidth, screenA.y);
    } else {
        const slope = (screenB.y - screenA.y) / (screenB.x - screenA.x);
        const intercept = screenA.y - slope * screenA.x;
        leftScreen = new THREE.Vector2(0, intercept);
        rightScreen = new THREE.Vector2(window.innerWidth, slope * window.innerWidth + intercept);
    }
    
  4. 把屏幕交点转成世界坐标红点:
    用Raycaster从屏幕交点发射射线,和立方体取交点就是红点的世界坐标:
    const raycaster = new THREE.Raycaster();
    // 更新左红点
    raycaster.setFromCamera(leftScreen, camera);
    const leftHits = raycaster.intersectObject(cube);
    if (leftHits.length) {
        leftRedDot.position.copy(leftHits[0].point);
    }
    // 更新右红点
    raycaster.setFromCamera(rightScreen, camera);
    const rightHits = raycaster.intersectObject(cube);
    if (rightHits.length) {
        rightRedDot.position.copy(rightHits[0].point);
    }
    
  5. 绑定到旋转事件:把这段更新逻辑放到OrbitControls的change回调里,每次旋转相机后自动刷新红点位置:
    controls.addEventListener('change', () => {
        // 上面的更新代码放在这里
    });
    

为啥这方法比你想的笨办法好

  • 完全自动适配视角旋转,不用手动调点
  • 只针对目标边缘计算,性能开销小
  • 逻辑全基于ThreeJS原生API,不容易出错,也好维护

注意点

  • 如果目标边缘被挡住了,记得加个视锥体检测(用THREE.Frustum判断顶点是否在相机视野里),避免算出无效的交点
  • 处理垂直屏幕的边缘时,要通过极小值判断避免除以0的错误

内容的提问来源于stack exchange,提问作者toowren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 03:40:39