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

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
Recent Announcements
Recent Announcements
IT之家
IT之家
人人都是产品经理
人人都是产品经理
G
Google Developers Blog
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
大猫的无限游戏
大猫的无限游戏
U
Unit 42
罗磊的独立博客
博客园 - Franky
WordPress大学
WordPress大学
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
M
MIT News - Artificial intelligence
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
P
Privacy International News Feed
P
Palo Alto Networks Blog
F
Fortinet All Blogs
P
Proofpoint News Feed
博客园 - 叶小钗
C
CERT Recently Published Vulnerability Notes
T
Tor Project blog
Spread Privacy
Spread Privacy
S
Securelist
C
Cisco Blogs
I
Intezer
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Cyberwarzone
Cyberwarzone
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy & Cybersecurity Law Blog
宝玉的分享
宝玉的分享
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
S
Schneier on Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
GbyAI
GbyAI
T
Troy Hunt's Blog
T
Threatpost
博客园 - 司徒正美
Y
Y Combinator Blog
Hugging Face - Blog
Hugging Face - Blog
AWS News Blog
AWS News Blog
T
The Blog of Author Tim Ferriss
G
GRAHAM CLULEY
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
Google DeepMind News
Google DeepMind News
Know Your Adversary
Know Your Adversary
S
SegmentFault 最新的问题

博客园 - 世纪末の魔术师

《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