当前位置: 首页 > news >正文

【Virtual Globe 渲染技术笔记】7 GPU 光线投射

GPU 光线投射(GPU Ray Casting)

GPU 专为光栅化三角形而设计,速度极快。
传统椭球渲染流程是:

  1. 用细分算法生成大量三角形
  2. GPU 并行光栅化
  3. 着色器计算颜色

这套流程虽然高效,但仍存在固有问题:

  • 任何细分都不是完美的,各有优劣;
  • 细分过粗 → 曲面失真;过细 → 性能/内存开销大,需要复杂的视点相关 LOD;
  • 现代 GPU 算力增长远超内存带宽,频繁向总线发送大量三角形会拖慢性能。

光线追踪:另一种思路

光栅化从三角形到像素;
光线追踪从像素出发,逆着视线发射射线,求与物体的交点,再计算光照。

对椭球而言,射线与隐式曲面的交点有解析解,因此无需三角形网格即可渲染。
优势:

  • 无限级细节:放大时不会出现“网格”或“锯齿”曲面;
  • 无拓扑缺陷:没有极区细长三角形、IDL 跨越等问题;
  • 内存极低:只存储椭球参数,无需巨型顶点缓冲。

如何在 GPU 上“光栅化”光线追踪?

现代 GPU 原生支持光栅化,但我们可以“借壳”:

  1. 构造椭球的轴对齐包围盒(12 个三角形)。

  2. 用光栅管线渲染这个盒子,前向面剔除,保证相机在盒内时仍能看见地球。
    在这里插入图片描述

  3. 片元着色器里,针对每个像素发射射线:

    • 起点:相机位置 ce_cameraEye
    • 方向:从相机到片元世界坐标 normalize(worldPos - ce_cameraEye)
  4. 用解析公式判断射线与椭球是否相交。

    • 需要椭球半径 (a,b,c)
    • 为提高效率,CPU 预先计算 1/radii² 作为 uniform 传入。
  5. 若相交,计算交点、法线、纹理坐标,用本章前面 LightIntensity() 等函数着色;
    若不相交,discard 片元(下图 绿色/红色示例)。
    在这里插入图片描述


完整片元着色器流程

  • Listing 1 只判断相交,输出纯色。
// List-1 Base GLSL fragment shader for ray casting.
in vec3 worldPosition;
out vec3 fragmentColor;uniform vec3 ce_cameraEye;
uniform vec3 u_globeOneOverRadiiSquared;struct Intersection
{bool Intersects;float Time; // Time of intersection along ray
};Intersection RayIntersectEllipsoid(vec3 rayOrigin, vec3 rayDirection, vec3 oneOverEllipsoidRadiiSquared)
{// ...
}void main()
{vec3 rayDirection = normalize(worldPosition - ce_cameraEye);Intersection i = RayIntersectEllipsoid(ce_cameraEye, rayDirection, u_globeOneOverRadiiSquared);fragmentColor = vec3(i.Intersects ? 1.0 : 0.0, !i.Intersects ? 1.0 : 0.0, 0.0);
}
  • Listing 2 计算交点位置、法线、纹理坐标,完成光照与纹理。
// List 2 Shading or discarding a fragment based on a ray cast.
vec3 GeodeticSurfaceNormal(vec3 positionOnEllipsoid, vec3 oneOverEllipsoidRadiiSquared)
{return normalize(positionOnEllipsoid * oneOverEllipsoidRadiiSquared);
}void main()
{vec3 rayDirection = normalize(worldPosition - ce_cameraEye);Intersection i = RayIntersectEllipsoid(ce_cameraEye, rayDirection, u_globeOneOverRadiiSquared);if (i.Intersects){vec3 position = ce_cameraEye + (i.Time * rayDirection);vec3 normal = GeodeticSurfaceNormal(position, u_globeOneOverRadiiSquared);vec3 toLight = normalize(ce_cameraLightPosition - position);vec3 toEye = normalize(ce_cameraEye - position);float intensity = LightIntensity(normal, toLight, toEye, ce_diffuseSpecularAmbientShininess);fragmentColor = intensity * texture(ce_texture0, ComputeTextureCoordinates(normal)).rgb;}else{discard;}
}
  • Listing 3 把交点深度写入 gl_FragDepth,解决深度缓冲区错误问题。
// List 3 Computing depth for a world-space position.
float ComputeWorldPositionDepth(vec3 position)
{vec4 v = ce_modelViewPerspectiveMatrix * vec4(position, 1.0);v.z /= v.w;v.z = (v.z + 1.0) * 0.5;return v.z;
}

性能与优化

  • overdraw:包围盒外片元被丢弃,看似浪费,但现代 GPU 的动态分支wavefront 一致性让开销很小。
  • 更紧包围:用视口对齐凸多边形代替轴对齐盒,可进一步减少空射线,在顶点/片元负载间权衡。
  • 无细分 → 无三角形传输瓶颈,显存占用极低。

局限与展望

  • 椭球有封闭解,但通用场景需要复杂加速结构(BVH、KD-Tree),在动态场景下 GPU 实现困难;
  • 软阴影、抗锯齿、多光源会导致射线数爆炸;
  • GPU 光线追踪仍是研究热点。

尽管如此,GPU 光线投射椭球已能无缝嵌入光栅管线,成为细分网格的有力替代方案。


参考:

  • Cozi, Patrick; Ring, Kevin. 3D Engine Design for Virtual Globes. CRC Press, 2011.
http://www.dtcms.com/a/336352.html

相关文章:

  • 法拉第笼原理
  • Windows快捷方式添加命令行参数
  • 【备忘】superdesign如何使用?(UI设计)
  • 电脑上搭建HTTP服务器在局域网内其它客户端无法访问的解决方案
  • 钉钉退出后重新登录显示网络异常,解决方法(随手记)
  • 嵌入式LINUX——————TCP并发服务器
  • Python 设计模式详解 —— 掌握软件设计的通用解决方案
  • PWM输入捕获(测量按键按下时间、测量PWM波)
  • 25. 能否创建一个包含可变对象的不可变对象
  • YOLOV5训练自己的数据集并用自己的数据集检测
  • 2025-08-17 李沐深度学习16——目标检测
  • PAT 1068 Find More Coins
  • ACPI TABLE 方式加载device driver--以spi controller为例
  • 认识信号量机制、以及用信号量来实现进程互斥于进程同步
  • 计算机网络 TCP time_wait 状态 详解
  • VirtualBox-4.3.10-93012-Win.exe 安装教程附详细步骤(附安装包下载)
  • 为何她总在关键时“失联”?—— 解密 TCP 连接异常中断
  • TensorRT-LLM.V1.1.0rc1:Dockerfile.multi文件解读
  • LeetCode 刷题【44. 通配符匹配】
  • 多墨智能-AI一键生成工作文档/流程图/思维导图
  • 《WINDOWS 环境下32位汇编语言程序设计》第3章 使用MASM
  • Redis面试精讲 Day 23:Redis与数据库数据一致性保障
  • 什么是回表?
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘scikit-image’问题
  • Hooks useState的使用
  • leetcode热题100——day33
  • 视频内容提取与AI总结:提升学习效率的实用方法
  • 【深度学习新浪潮】近三年图像处理领域无监督学习的研究进展一览
  • 科目二的四个电路
  • 《Vuejs设计与实现》第 14 章(内建组件和模块)