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

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
Recent Commits to openclaw:main
Recent Commits to openclaw:main
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Check Point Blog
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
Secure Thoughts
Recorded Future
Recorded Future
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
The Blog of Author Tim Ferriss
B
Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Google DeepMind News
Google DeepMind News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
A
Arctic Wolf
T
The Exploit Database - CXSecurity.com
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
GbyAI
GbyAI
AWS News Blog
AWS News Blog
MongoDB | Blog
MongoDB | Blog
Y
Y Combinator Blog
Google Online Security Blog
Google Online Security Blog
T
Troy Hunt's Blog
I
InfoQ
L
LINUX DO - 热门话题
WordPress大学
WordPress大学
C
Cisco Blogs
G
GRAHAM CLULEY
The Register - Security
The Register - Security
A
About on SuperTechFans
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Schneier on Security
Schneier on Security
Project Zero
Project Zero
H
Hackread – Cybersecurity News, Data Breaches, AI and More
P
Privacy & Cybersecurity Law Blog
Cloudbric
Cloudbric
H
Hacker News: Front Page
小众软件
小众软件
雷峰网
雷峰网
The Hacker News
The Hacker News
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Tor Project blog
博客园 - 聂微东
N
Netflix TechBlog - Medium
V
Vulnerabilities – Threatpost
The GitHub Blog
The GitHub Blog
腾讯CDC
P
Palo Alto Networks Blog
Scott Helme
Scott Helme

重归混沌的BLOG

给silly实现了一个ernro模块 | 重归混沌的BLOG 给silly实现了一个ernro模块 | 重归混沌的BLOG 第一次在生产环境使用 Vibe Coding | 重归混沌的BLOG 第一次在生产环境使用 Vibe Coding | 重归混沌的BLOG API 设计的艰难抉择 | 重归混沌的BLOG API 设计的艰难抉择 | 重归混沌的BLOG 十年 | 重归混沌的BLOG 十年 | 重归混沌的BLOG 在Go语言中如何使XML加载内存无限趋近于0 | 重归混沌的BLOG 在Go语言中如何使XML加载内存无限趋近于0 | 重归混沌的BLOG 对跨服玩法中的分布式一致性问题进行简单抽象 | 重归混沌的BLOG 对跨服玩法中的分布式一致性问题进行简单抽象 | 重归混沌的BLOG Go语言逃逸分析之slice和map | 重归混沌的BLOG Go语言逃逸分析之slice和map | 重归混沌的BLOG 谈谈观测 | 重归混沌的BLOG 谈谈观测 | 重归混沌的BLOG 写了个AI Agent服务端 | 重归混沌的BLOG 写了个AI Agent服务端 | 重归混沌的BLOG 谈谈代码设计中“严丝合缝” | 重归混沌的BLOG 谈谈代码设计中“严丝合缝” | 重归混沌的BLOG 一次艰难的线上游戏服务器内存排查经历 | 重归混沌的BLOG 一次艰难的线上游戏服务器内存排查经历 如何基于LanguageServerProtocol来编写lint工具 谈谈游戏服务器中RPC模块的设计 谈谈游戏服务器代码抽象 最近碰到的一个分布式一致性问题 谈谈游戏服务器的自动化测试 对Raft协议的一点理解 使用mmap来学习/proc/pid/smaps 2023(完) 再次实现了一个Lua性能分析器 终于给Silly的定时器增加了取消功能 一次虚拟内存排查经历 游戏服务器分布式数据的一种同步的思路 为silly增加了互斥锁 2022(完) Go语言之闭包篇 一例误用unsafe包引起的内存问题 Go语言之内存篇 初识Go语言 重新抽象图形API 给Lua实现了一个数学库 谈谈跨平台图形API的抽象 寻路和Flocking算法的结合 行为树的一种高效实现 内测过程中Shader出现的问题 彻底解决多国语言 谈谈数据库的选型 再谈Lua热更新(终) 初窥Rust 关于游戏服务器的服务拆分 ECS的初步实现 ECS初探 一些对辐射度量学的理解 深度缓冲和半透明渲染 Mysql的间隙锁 更新一些GPU相关知识 2020 地形渲染之爬过的坑 Lua5.3 GC源码阅读(5) 实现一个数据库存储队列 再学计算机图形学入门 再谈分布式服务架构 游戏上线一个月后的反思 一次并发Bug 双向链表的三种实现 谈谈随机数的使用 再谈性能优化 2019 Lua中的函数式编程 重构登录逻辑 Unity资源管理(续) 谈谈Unity的资源管理 一次关于Cache的性能分析 历史之2018 DC3算法 移动平台native代码遭遇的坑 从CPU层面谈谈优化 开卷有益(UNIX编程艺术篇) GC竞争问题 通过Mesh投影来实现贴花系统 谈谈我对数据同步的理解 又一个类型提升引起的Bug Lua5.3 GC源码阅读(4) Lua5.3 GC源码阅读(3) Lua5.3 GC源码阅读(2) Lua5.3 GC源码阅读(1) 三角形光栅化时遇到的坑 一次git事故 再见2017 又一个lua调试器 客户端缓存落地方案 Paxos算法 HTTP服务器的特点 一次性能优化经历 关于CPU分支预测 C程序中让两个不同版本的库共存 实现了一个AOI模块 一个高可伸缩的游戏服务器架构 关于网络协议封装的一些新想法
屏幕空间(SreenSpace)的想象力
重归混沌 · 2021-06-30 · via 重归混沌的BLOG

在写这篇文章时,我特意去Wiki上搜了一下ScreenSpace, 可能是由于太过直白的缘故,并没有找到标准的定义。

不过他的定义是显而易见的,屏幕空间的所有的信息都是与屏幕上的像素有关的,而不是和场景中的几何有关的信息都叫屏幕空间,这一点其实很像是Pixel和Fragment的区别。pixel是定义在屏幕空间上的,而Fragment是定义在三维空间上的。

举个最简单的例子,我们从相机原点射出一条射线,然后穿过两个不透明物体。这两个交点,在进行光栅化时就是2个Fragment, 但是最终渲染到屏幕上最终只会有一个Fragment被采用,而屏幕空间就是最终被采用的Fragment的集合。


显然深度纹理属于屏幕空间。

以前,我一直觉得深度缓存只能用来做ZTest。然而大神们分分钟教我做人。

在光线追踪算法下,我们可以这样生成深度图,将深度图放在相机的近平面。

然后相机原点对深度图上所有像素都发出射线和场景中物体相交,并把首次相交的物体的Fragment,在相机空间下的Z坐标写入深度图。

下面这张图片更详细的展示了光线追踪的细节。

在光栅化算法下,生成的深度图结果和光线追踪一模一样,但显然光线追踪的算法更清晰并易于理解。

从光线追踪算法来看,给我们一个指定分辨率的深度图和相机近平面距离,我们就可以完全还原出来生成深度图用到的所有射线。

我们还知道,深度图上每个像素上的深度值,都是从相机原点到这个像素发出的射线与场景物体相交的点产生的。

反过来说就是,影响像素A的深度值Z_A所在的Fragment_A(3D坐标下的点),一定在从相机原点出发到像素A的射线Ray_A上。

我们来看看,有了这些信息,我们都能求出哪些额外的信息。

RayA*Z_A = Fragment_A在相机空间下的位置ViewPosition_A

mul(inverse(V), ViewPosition_A) = Fragment_A在世界坐标下的位置WorldPosition_A

我们甚至可以通过mul(inverse(M), WorldPosition_A)将Fragment_A变换到任意模型ModelPosition_A。

来看看我们能利用这些还原的信息做什么吧。


深度贴花:

在很久以前, 我曾经执迷于贴花,最终学会了使用Mesh来贴花,但是利用深度信息,我们可以更便捷的做到。

我们假设要贴的花是一张平面贴纸,我们有这个纸片的MVP矩阵。

根据上面的推导,我们可以将深度图上的任意一个像素的Fragment转换到贴纸的模型空间中来。

然后我们根据这个Fragment在贴纸的模型空间中的坐标X,计算出需要采样的uv。

假设整个贴花的大小是(x,z) = (-0.5,-0.5)~(0.5,0.5), 那么uv=X.xy + (0.5,0.5)。当然需要clip掉uv.xy < (0,0)和uv.xy >(1,1)的坐标。

最后根据计算出的uv直接采样纹理,整个贴花就完成了。


全局雾效:

有了深度图,我们可以重新计算出每一个像素的Fragment在相机空间下的位置ViewPosition。

记受雾影响的最大和最小距离为 d_{\tiny min}d_{\tiny max}

假设雾的浓度和高度有关的,一种简单的雾效计算公式为。

f = \frac{d_{\tiny max} - ViewPosition.y}{d_{\tiny max}-d_{\tiny min}}

float3 afterFog = f fogColor + (1 – f) oriColor;


SSAO:

在SSAO的实现里, 我们甚至都不需要去重新计算坐标信息。

仅通过采样一个像素周围的平均深度,就可以来近似计算一个遮蔽关系。


虽然深度图可以计算出来很多信息,但是还是有很多信息是计算不出来,比如法线信息。

在我们写光栅化时,都会有这样一个经历,在有多光源的情况下,我们的代码和下面代码很相似。

for l in lights do
    for m in meshes do
        render(l,m)
    end
end

没错,这就是传说中的ForwardBase Lighting。在上述代码中,每多增加一个光源,我们就需要把所有Mesh重新渲染一遍,如果光源非常多的话,这种开销几乎是不可承受的。

聪明的大神们发现了一个现象,还是光线追踪的思路。当我从相机原点到成像纹理的像素发出射线时,只有第一个与射线相交的场景中的Fragment才会被采用,后面的Fragment在后来做ZTest时都会被丢弃, 即然这样,我只对屏幕空间中的Fragment计算光照就可以了。

这种思路在有复杂遮挡关系的场景中,优化效果是惊人的。那具体应该怎么做呢?

一般是通过两个Pass来做的。

在第一趟Pass中,Shader会计算所有Fragment的采样颜色和法线。并将颜色和法线分别写入两张Texture中。由于在Fragment Shader在输出结果时,会做ZTest, 因此只有离相机最近的Fragment才有资格写入纹理。这一步的目的就是为了减少计算光照的Fragment。

在第二趟Pass中,Shader会根据纹理中的每一个像素所包含颜色和法线信息来对所有光源进行计算。

整个计算流程大概如下:

--First Pass
for f in fragments do
    if depth_test(f) do
        write_diffuse(f, texture2D(f.uv, tex))
        write_normal(f, f.normal)
    end
end

--Second Pass
for f in fragments_in_screen_space do
    c = float3(0)
    for l in lights do
        c += render(l, f)
    end
    write(f, c)
end

这就是大鼎鼎的Deferred Lighting。


你以为这就是大神极限了么,大神会立马再教你做人。

即然光照可以通过两趟Pass的方式来优化,那我可不可以用来加速光线追踪呢?

答案是肯定的, 由于屏幕空间上的信息量相比整个场景来讲少之又少,在计算光线相交时,可以更快的判定。当然同样由于信息量过少, 所以会有这样或那样的瑕疵,不过相比效果来讲,瑕疵反而不是微不足道的。

没错,这就是传说中的SSR(ScreenSpaceReflection)。其实就是在屏幕空间下进行RayTracing, 是不是叫ScreenSpaceRayTracing更好一些:D。