惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Spread Privacy
Spread Privacy
H
Hacker News: Front Page
PCI Perspectives
PCI Perspectives
Webroot Blog
Webroot Blog
罗磊的独立博客
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Last Week in AI
Last Week in AI
美团技术团队
Help Net Security
Help Net Security
The Hacker News
The Hacker News
C
Cisco Blogs
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
The Register - Security
The Register - Security
IT之家
IT之家
WordPress大学
WordPress大学
Jina AI
Jina AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Help Net Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
NISL@THU
NISL@THU
爱范儿
爱范儿
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
Vulnerabilities – Threatpost
B
Blog
T
Tenable Blog
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
S
Security Affairs
小众软件
小众软件
Hacker News: Ask HN
Hacker News: Ask HN
Security Latest
Security Latest
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
A
Arctic Wolf
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence

博客园 - 世纪末の魔术师

《The Wealth Ladder》读书笔记 项目管理,真正的密码只有一句话 Linq延迟执行陷阱 坚毅,是一种缓慢修理自己的方式 语言的边界,与软件的命运 人类与AI协同进化 《坚毅》第一部分读书笔记 用 System.CommandLine 构建工程级 CLI 工具 用 Command 模式构建可扩展的命令行工具 从哎呦”到语言宇宙 ——读《What Is ChatGPT Doing … And Why Does It Work?》 ⏱️ 深入理解定时器中的【时间轮算法】 🚫 为什么「定时器」不应该是线程安全的? C# AOT编译后——调用其类库方法因顺序出错? UnitTask中的Forget()与 CTS 八、方法(method) 二十、异常与状态管理(Exception&State Management) 二十八、IO绑定的异步操作(IO-Bound Async) 二十二、CLR寄宿与AppDomain(CLR Hosting and App Domains ) 二十九、原始线程同步构造(Primitive Thread Synchronization Constructs ) 二十六、线程与并发(Thread Basic) 二十七、计算密集型异步操作(Compute-Bound Asynchronous Operations) 二十三、程序集加载与反射(Assembly Loading and Reflection)
光线追踪和球体追踪
世纪末の魔术师 · 2025-09-10 · via 博客园 - 世纪末の魔术师

光线追踪和球体追踪

#光线追踪 #球体追踪

参考:

《The Unity Shader Bible》

RayMarching入门 SphereTracing

光线追踪的概念

image.png

光线从摄像机出发,穿过像素点,直到击中表面以达到目标。这个概念被称为“光线投射(Ray Marching)” ,即沿着光线找到最近物体的过程,因此得名“球面追踪(Sphere Tracing)”。 RayMarching就是光线行进,从摄像机向屏幕上的每一个像素发射一条光线,光线按照一定步长前进,检测当前光线距离物体表面的距离,并且根据这个距离调整光线的步长,直到抵达物体表面。

SDF

我们需要根据即将生成的曲面形状来确定射线的终点。在此场景中,这类名为SDF(有符号距离函数)的函数会以点为输入,返回该点与图形表面之间的最短距离。若返回值为正,则射线继续前进;若返回值为零,则射线将与曲面发生碰撞。

球体追踪

着色器应用

为了正确使用该技术,我们需要在着色器中定义至少两个函数。为此,需要考虑以下因素: • 一个用于确定曲面类型的sdf函数. • 另一个用于计算球体追踪的函数.

image.png

流程图

起点 ray_origin

计算 ray_position

调用 planeSDF ray_position

得到最近距离 d

distance_origin += d

d < SURFACE_DISTANCE?

命中物体 结束

distance_origin > MAX_MARCHING_STEPS?

未命中 空

核心Shader代码

球体追踪就是用场景的 SDF(signed distance function)告诉你从当前位置到最近表面的最小距离,然后用这个距离作为步长向前跳——仿佛每一步放一个贴紧场景的球体,球体刚好不穿透物体,直到球体接触表面或超过上限。

“射线起始点”向量对应“射线的起点”,即相机在局部空间中的位置;而“射线方向”则等于“网格顶点的位置”,也就是我们正在处理的球体所在位置。由于我们需要根据边生成图元划分,因此必须确保sdf平面的位置与三维物体的位置保持一致。 💁在该示例中,相机到平面的距离即float plane = ray_position.y - _Edge; 为射线步进的长度 image.png

这段代码是一个 Sphere Tracing(球面追踪 / Ray Marching) 的核心片段,用来做 基于 SDF(有符号距离函数) 的光线行进算法。我们逐行拆解:

🔎 核心概念

  1. ray_origin
    光线的起点(比如相机位置)。

  2. ray_direction
    光线的方向(归一化向量)。

  3. distance_origin
    当前光线走了多远。

  4. planeSDF(ray_position)

    • SDF = Signed Distance Function(有符号距离函数)。
    • 返回当前位置到场景表面的最近距离。
    • 如果 >0 → 在表面外;
      如果 <0 → 穿进去了(通常表示点在物体内部)。
  5. Sphere Tracing 原理
    因为 SDF 告诉我们“离物体最近的距离”,所以每次可以大胆走这么远,而不会穿过物体。
    这就像拿着一个“安全半径球”在前进,保证不会撞墙。

🌀 循环逻辑

  • 计算当前位置

  • 计算到物体的最近距离

  • 向前走这么远

  • 收敛条件

    • 如果 distance_scene < SURFACE_DISTANCE,说明非常接近表面,可以认为击中了物体。
    • 如果 distance_origin > MAX_MARCHING_STEPS,说明走太远还没碰到 → 判定为空。

🎮 类比理解

想象你在 漆黑的房间里摸墙

  • 你知道离墙大概多远(SDF 提供的距离)。
  • 于是你可以一下子走这段距离(安全前进)。
  • 如果你发现已经非常接近墙面,就停下(命中)。
  • 如果走了很久还没遇到墙 → 前面啥也没有。

如前所述,需要剔除球体平面上的像素点。要实现这种评估,我们需要获取球体y轴上顶点在物体空间中的坐标位置。通过使用“discard”语句,我们可以剔除位于边缘的像素点,具体操作如下所示。

示例:橘子瓤

基础绘制

image.png

开启双面显示

image.png

获取切面

我们可以将球体的像素投影到其背面,对于平面,可以使用sv_isfrontface语义将其投影到正面。

image.png

UV和贴图

在这种情况下,如果要在sdf平面上投影纹理,就需要考虑sdf平面背面的位置和方向——记住这个平面是朝向正y轴的。因此,纹理的方向需要与之相反。 image.png

为此,我们可以使用点“p.xz.”计算最大球面投射区域内的uv坐标。 UVhandler.png

交点局部坐标映射为UV坐标

  • 交点 = 相机位置 + 射线方向 × 距离
  • 交点坐标的投影(如 x-z)可以作为 UV 变换的初始值

image.png

进一步,将UV居中

_Edge=0.43

image.png

_Edge=0.02 image.png

让UV适配球体

修改边属性值后,我们将看到平面的纹理投影会根据球体的体积而逐渐减小。

桔子.png

橘子皮.png fruit.gif

边缘绘制

image.png

最终效果

image.png