GrandCaster 2025-04-22 11:14 采纳率: 0%
浏览 27
已结题

OSGEARTH实现光线投射算法,屏幕上的 (x, y) 在变化,得到的世界坐标也不变

我理解的光线投射是遍历屏幕坐标生成不同起点的射线进行采样,累积颜色后绘制出二维图像。现在遍历了不同的屏幕坐标 (x, y),却发现屏幕坐标转换的世界坐标都是相同的,完全没有变化。

osg::Vec3d eye, center, up;
camera->getViewMatrixAsLookAt(eye, center, up);
osg::Matrix viewMatrix = _camera->getViewMatrix();
osg::Matrix projMatrix = _camera->getProjectionMatrix();
osg::Matrix inverseVP = osg::Matrix::inverse(viewMatrix * projMatrix);
for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            double ndc_x = (2.0f * screen_x / width) - 1.0f;
            double ndc_y = -(2.0f * screen_y / height) +1.0f;
            osg::Vec4 clipNear(ndc_x, ndc_y, -1.0,1.0); 
            osg::Vec4 worldNearH = clipNear * inverseVP;
            osg::Vec3d worldNear(worldNearH.x() / worldNearH.w(), worldNearH.y() / worldNearH.w(), worldNearH.z() / worldNearH.w());
            osg::Vec4 clipFar(ndc_x, ndc_y, 1.0, 1.0);
            osg::Vec4 worldFarH = clipFar * inverseVP;
            osg::Vec3d world_sta = osg::Vec3d(x, y, 0) * inverseVPW;
            osg::Vec3d worldFar(worldFarH.x() / worldFarH.w(), worldFarH.y() / worldFarH.w(), worldFarH.z() / worldFarH.w());

            osg::Vec4 noNDCclipNear(x, y, -1.0, 1.0);
            osg::Vec4 noNDCworldNearH = noNDCclipNear * inverseVP;
            osg::Vec3d noNDCworldNear(noNDCworldNearH.x() / noNDCworldNearH.w(), noNDCworldNearH.y() / noNDCworldNearH.w(), noNDCworldNearH.z() / noNDCworldNearH.w());

            osg::Vec3d rayDirection = center - eye;
            rayDirection.normalize();
            Ray rayOfPixel(eye, rayDirection);
            ......
        }
    }
  • 写回答

4条回答 默认 最新

  • 阿里嘎多学长 2025-04-22 11:14
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    OSGEARTH实现光线投射算法,屏幕上的 (x, y) 在变化,得到的世界坐标也不变

    你遇到的问题是,使用 OSGEARTH 实现光线投射算法时,遍历不同的屏幕坐标 (x, y),却发现转换后的世界坐标总是相同的。

    这是因为光线投射算法中,世界坐标的计算是基于屏幕坐标 (x, y) 和视图投影矩阵的。假设你的视图投影矩阵没有变化,那么计算的世界坐标也不会变化。

    在 OSGEARTH 中,你可以使用 osg::CameragetProjectionMatrix() 方法获取当前的视图投影矩阵,然后使用 osg::Vec3dtransform() 方法将屏幕坐标 (x, y) 转换为世界坐标。

    如果你想实现光线投射算法,需要在遍历屏幕坐标 (x, y) 时,使用当前的视图投影矩阵和屏幕坐标计算世界坐标。否则,计算的世界坐标将总是相同的。

    你可以尝试使用以下代码来实现光线投射算法:

    osg::Camera* camera = ...; // 获取当前摄像机
    osg::Matrixd projectionMatrix = camera->getProjectionMatrix();
    osg::Vec3d worldCoord;
    
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            osg::Vec2d screenCoord(x, y);
            osg::Vec3d rayOrigin = ...; // 获取射线的起点
            osg::Vec3d rayDir = ...; // 获取射线的方向
    
            // 使用投影矩阵和屏幕坐标计算世界坐标
            worldCoord = projectionMatrix.transform(screenCoord);
    
            // 使用世界坐标和射线的起点和方向计算颜色
            osg::Vec4f color = ...;
    
            // 绘制颜色
            ...
        }
    }
    

    在上面的代码中,我们使用 osg::CameragetProjectionMatrix() 方法获取当前的视图投影矩阵,然后使用 osg::Vec3dtransform() 方法将屏幕坐标 (x, y) 转换为世界坐标。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 6月25日
  • 创建了问题 4月22日