Minecraft(我的世界)中文论坛

标题: [20w22a]不会有人看的深度缓冲着色器分析&用途 (6.10更新!) [打印本页]

作者: ChapterII    时间: 2020-6-3 11:25
标题: [20w22a]不会有人看的深度缓冲着色器分析&用途 (6.10更新!)
本帖最后由 ChapterII 于 2020-6-10 22:41 编辑

下文转载材质包已取得原作者授权

2020.6.10 18:30更新:景深、实例之吸血鬼
2020.6.7 14:25更新:深度缓冲访问方法,线性深度,Distance解析.


众所周知,20w22a加入了着色器对深度缓冲的访问支持。
“然而,这意味着什么呢?”



1.什么是深度缓冲
摘自LearnOpenGL-CN
深度缓冲是图形编程中的一个基础概念。渲染三维图形(这里以立方体举例)时
由于三角形绘制的先后顺序(计算机会把图形分解为三角形进行渲染)
仅仅按正常的顺序渲染一个立方体,会


这的确有点像是一个立方体,但又有种说不出的奇怪。立方体的某些本应被遮挡住的面被绘制在了这个立方体其他面之上。之所以这样是因为OpenGL是一个三角形一个三角形地来绘制你的立方体的,所以即便之前那里有东西它也会覆盖之前的像素。因为这个原因,有些三角形会被绘制在其它三角形上面,虽然它们本不应该是被覆盖的。

幸运的是,OpenGL存储深度信息在一个叫做Z缓冲(Z-buffer)的缓冲中,它允许OpenGL决定何时覆盖一个像素而何时不覆盖。通过使用Z缓冲,我们可以配置OpenGL来进行深度测试。

注:Z缓冲又称深度缓冲
当一个面的Z缓冲顺序在前,就不会渲染其后的面。
因此,引入了深度缓冲解决了物体的绘制问题。

“但是,你说好的着色器呢?”


2.如何访问深度缓冲?
  1. "auxtargets": [
  2.                 {
  3.                     "name": "DiffuseDepthSampler",
  4.                     "id": "minecraft:main:depth"
  5.                 },
复制代码
在post Json文件里需要访问深度缓冲的操作的auxtargets加入如上内容.
同理,在着色器的Json里
  1. "samplers": [
  2.         { "name": "DiffuseSampler" },
  3.         { "name": "DiffuseDepthSampler" },
复制代码
最后,在片段着色器里
  1. uniform sampler2D DiffuseSampler;
  2. uniform sampler2D DiffuseDepthSampler;
复制代码
这样,就可以通过DiffuseDepthSampler访问深度缓冲了,
  1. texture2D(DiffuseDepthSampler,vec2(0.5,0.5));
复制代码



3.Onnowhere的深度缓冲着色器
https://github.com/onnowhere/depth_shaders/
Onnowhere一共发布了4个资源包
分析:
Depth Shader Test(Distance) (咕)
Depth Shader Test(Fog)(√)
                           (DoF) (注Depth of Field)(咕)
                           (Stripe)(咕)
从最简单的Fog说起

这是在下界使用Fog资源包的截图。
片段着色器很简短:depth_test.fsh
  1. <blockquote>#version 110
复制代码

DiffuseDepthSampler即是深度缓冲(采样器)。
  1. texture2D(DiffuseDepthSampler, texCoord)
复制代码
获取了texCoord处片段的深度。
1.0减去vec4会使每项被1.0减去,因此最终效果为对该处深度取反。
*500.0是一个系数,可以根据个人需求调整。
最后再取反,达到图中的效果。
实际上,该着色器做的只是将它的颜色进行了缩放操作,
  1. gl_FragColor = texture2D(DiffuseDepthSampler, texCoord);
复制代码

可以直接使深度缓冲可视化,好奇的读者可以自己尝试。




Depth Shader Test(Distance)资源包
该资源包的效果有点过于[ruby=dizzy]目眩神迷[/ruby],请自行尝试
会以摄像机为中心,每隔1方块距离的点进行着色,类似同心圆。

  1. #version 110

  2. uniform sampler2D DiffuseSampler;
  3. uniform sampler2D DiffuseDepthSampler;

  4. uniform vec2 ScreenSize;
  5. uniform float _FOV;

  6. varying vec2 texCoord;

  7. float near = 0.1;
  8. float far  = 1000.0;

  9. float LinearizeDepth(float depth)
  10. {
  11.     float z = depth * 2.0 - 1.0;
  12.     return (near * far) / (far + near - z * (far - near));   
  13. }

  14. void main() {
  15.     float depth = LinearizeDepth(texture2D(DiffuseDepthSampler, texCoord).r);
  16.     float distance = length(vec3(1., (2.*texCoord - 1.) * vec2(ScreenSize.x/ScreenSize.y,1.) * tan(radians(_FOV / 2.))) * depth);
  17.     if (mod(distance, 1.0) <= 0.05) {
  18.         gl_FragColor = vec4(1.0,0.0,0.0,0.1);
  19.     } else {
  20.         gl_FragColor = vec4(texture2D(DiffuseSampler, texCoord).rgb, 1.0);
  21.     }
  22. }
复制代码

uniform _FOV是视野(Field of View),即角视场.
因为深度缓冲里每个像素的颜色(vec4)的r、g、b均为同一个值(深度),
因此取texture2D(DiffuseDepthSampler, texCoord).r就是该片段深度。以下内容可能难以理解,但是是看懂其它三个资源包的基础内容。如果看不懂公式没关系,只要记住蓝底字内容即可。
Onnowhere定义了函数float LinearizeDepth(float depth) ,Linearize意味"用线表示",GLSL里一般解释为“线性深度”这里需要解释一下,
要想有正确的投影性质,需要使用一个非线性的深度方程,它是与 1/z 成正比的。
它做的就是在z值很小的时候提供非常高的精度,而在z值很远的时候提供更少的精度。
花时间想想这个:我们真的需要对1000单位远的深度值和只有1单位远的充满细节的物体使用相同的精度吗?
线性方程并不会考虑这一点。屏幕空间中的深度值是非线性的,即它在z值很小的时候有很高的精度,而z值很大的时候有较低的精度。
片段的深度值会随着距离迅速增加,所以几乎所有的顶点的深度值都是接近于1.0的。

(引用文字节选自LearnOpenGL-CN:深度测试
简单来说,为了效率,深度值不是线性的,即不是随距离增大而匀速增大的。


OpenGL非线性的深度方程计算如上,
为了实现距离的均匀,我们需要将非线性的化为线性深度。
然而,我们也可以让片段非线性的深度值变换为线性的。要实现这个,我们需要仅仅反转深度值的投影变换。这也就意味着我们需要首先将深度值从[0, 1]范围重新变换到[-1, 1]范围的标准化设备坐标(裁剪空间)。接下来我们需要像投影矩阵那样反转这个非线性方程(方程2),并将这个反转的方程应用到最终的深度值上。最终的结果就是一个线性的深度值了。听起来是可行的,对吧?

首先我们将深度值变换为NDC,不是非常困难:

float z = depth * 2.0 - 1.0;
接下来使用获取到的z值,应用逆变换来获取线性的深度值:

float linearDepth = (2.0 * near * far) / (far + near - z * (far - near));
这个方程是用投影矩阵推导得出的,它使用了方程2来非线性化深度值,返回一个near与far之间的深度值。这篇注重数学的文章为感兴趣的读者详细解释了投影矩阵,它也展示了这些方程是怎么来的。

总而言之,要转化"不均匀的"深度为"均匀的",好比向上大下小的杯子里匀速倒水,水面上涨的速度不与倒水速度成正比。
而实现该目的的,是LinearizeDepth函数。

上为LinearizeDepth函数。
该函数实现了线性深度转化为非线性的逆过程。
main()中的内容较为简单,是判断该片段与玩家的距离是否为整数(有0.05的浮动范围),如果是则gl_FragColor = vec4(1.0,0.0,0.0,0.1);



(Stripe)
和Distance基本上同理,
[ruby=疯狂暗示]看懂了线性深度这个应该很好理解吧[/ruby]
所以,那么是不是可以偷个懒的呀?
“那么,你什么时候填坑呢?”
(无响应)


(DoF)DoF,Depth of Field.
DoF看着很陌生,"场地深度?"
实际上,它就是我们常说的景深.
稍微涉及过一点相机方面知识的玩家,都知道当拍摄远处的一个独立的景物时,近处的环境会变模糊。
在拍摄截图时,景深会非常有用:


看起来,是不是山峰被突出了?
远处的和近处的都被模糊了,达到了突出所拍摄目标的效果。
实际上,作者只是在某个范围内正常显示,在范围外模糊的简单原理。
[ruby=因为作者懒]作为思考题[/ruby],请自己阅读片段着色器代码(逃)

4.除了这些特效,深度缓冲还可以用来做些什么?——实战

As many as you can come up with.
比如,阴影的实现,是在光源的角度根据深度缓冲生成一张“深度纹理”,
然后转回摄像机视角,根据深度纹理绘制出阴影。
上述技术是最为常见的阴影实现方法,阴影贴图。

至于真正有点意义的……
吸血鬼小游戏应该都听说过吧,Hypixel的VampireZ:
玩家使用了失明效果,但自定义化程度较低。
如果用深度缓冲……一定不错!
  1. #version 110

  2. uniform sampler2D DiffuseSampler;
  3. uniform sampler2D DiffuseDepthSampler;

  4. uniform vec2 ScreenSize;
  5. uniform float _FOV;

  6. varying vec2 texCoord;

  7. float near = 0.1;
  8. float far  = 1000.0;
  9.   
  10. float LinearizeDepth(float depth)
  11. {
  12.     float z = depth * 2.0 - 1.0;
  13.     return (near * far) / (far + near - z * (far - near));   
  14. }

  15. void main() {
  16.     float depth = LinearizeDepth(texture2D(DiffuseDepthSampler, texCoord).r);
  17.     if(depth < 10.0) gl_FragColor=texture2D(DiffuseSampler,texCoord);
  18.     else gl_FragColor=vec4(0.0,0.0,0.0,1.0);
  19. }
复制代码
代码很简单,只要看懂了线性深度即可;


但是,总感觉边界有点……锐利?
  1. ++ else if(depth < 13.0) gl_FragColor=texture2D(DiffuseSampler,texCoord) * (1.0-(depth-10.0)/3.0);
复制代码



效果如何?
那还不加分去!

“所以,某个蓝蓝的东西呢?”
下载页面位于https://github.com/onnowhere/depth_shaders/
未提供某在线云文件存储服务的转载

“然后,要不要加分呢?”
金粒可以不给,人气还不给点吗[ruby=不给的话人家再也不这么努力写帖子了]~[/ruby]





















作者: 丸尾青貓    时间: 2020-6-3 11:29
有趣的着色器越来越多,等我这个地图做完很想试试。国内现在有什么用了着色器的地图可以玩吗?
作者: ChapterII    时间: 2020-6-3 11:31
[SL]John_Stapp 发表于 2020-6-3 11:29
有趣的着色器越来越多,等我这个地图做完很想试试。国内现在有什么用了着色器的地图可以玩吗? ...

好……像……没……有……吧(小声)
但是很多dalao在做了
作者: :spgbigfan:    时间: 2020-6-3 11:48


Distance 的效果

确实 Dizzy

作者: 晴路卡    时间: 2020-6-3 13:50
只能想到用来做些奇怪的东西...


作者: ChapterII    时间: 2020-6-3 14:28
晴路卡 发表于 2020-6-3 13:50
只能想到用来做些奇怪的东西...

希望有dalao能用深度缓冲做出原版阴影
还有就是,比如吸血鬼小游戏可以不用失明了


作者: 深拥v    时间: 2020-6-3 15:09
着色器目前国内做的不多吧
(至少mcbbs还没专门开个板块做这个)
作者: ChapterII    时间: 2020-6-3 15:35
深拥v 发表于 2020-6-3 15:09
着色器目前国内做的不多吧
(至少mcbbs还没专门开个板块做这个)

还好,这个应该算是资源包的一部分
地图作者和原版模组也都有用的
所以不算单独的版块,最多放在材质版?
作者: ⭐✔️    时间: 2020-6-7 11:06
你能不能用[code]标签,黑背景怪费眼的
作者: Оil    时间: 2020-6-14 10:56
>>这个公式的非官方表述让我看得血压升高……= =
作者: 年检费就    时间: 2020-6-14 20:21
这个真棒           
作者: 👴是hlnb    时间: 2020-6-14 22:48
以后就有香草光影了?
作者: ChapterII    时间: 2020-6-15 08:45
👴是hlnb 发表于 2020-6-14 22:48
以后就有香草光影了?

SBMJ对着色器的限制使得不能获取光源的位置,也不能获取当前的材质反射贴图之类的,所以离光影还有很远的路要走
作者: 炽炽灼华    时间: 2020-6-15 09:06
是在下输了
作者: 1172429976    时间: 2020-6-16 00:57
支持~~~~~~~
作者: Pan$brother    时间: 2020-6-16 10:09
谢谢分享~支持
作者: 飘渺魔尊    时间: 2020-6-16 23:14
这就是大佬吗,除了变量定义完全看不懂
作者: 糖心馅的猫    时间: 2020-6-17 21:03
很棒的帖子~感谢分享~
作者: 风雪.    时间: 2020-6-18 16:13
虽然没看懂 好像很厉害的样子==
作者: Rain_DanRan    时间: 2020-6-19 12:07
这个公式是我看着都打脑阔
作者: Basin.    时间: 2020-6-19 20:05
挺期待的
作者: MC_Han    时间: 2020-6-20 03:24
不错!!!支持一下楼主!!
作者: zxtzjx    时间: 2020-6-20 14:07
哇,看不太懂呢,但还是很棒
作者: sian丶sh    时间: 2020-6-21 23:57
支持,虽然有点看不太懂
作者: sian丶sh    时间: 2020-6-21 23:58
支持,虽然不太懂
作者: op3313873744    时间: 2020-6-22 10:09
啊 挺有用的 谢谢
作者: xpao    时间: 2020-6-22 23:44
提示: 作者被禁止或删除 内容自动屏蔽
作者: 深绿世界    时间: 2020-6-23 06:14
这个还算不错的......那什么时候光影渲染能由资源包来干呢
作者: you_lose    时间: 2020-6-23 15:40
emmeeeeee11111111111111
作者: you_lose    时间: 2020-6-23 15:41
1111111111111111111111111111111111111
作者: you_lose    时间: 2020-6-23 15:41
111111111111111111111111111
作者: you_lose    时间: 2020-6-23 15:41
1111111111111111111111111111111111111
作者: you_lose    时间: 2020-6-23 15:42
111111111111111111111111
作者: 糖饺子    时间: 2020-6-29 14:17
看到标题我进来看了,看到内容我就知道我该走了
作者: 我的丶老公    时间: 2020-7-3 02:20
提示: 作者被禁止或删除 内容自动屏蔽
作者: overtime    时间: 2020-7-4 03:53
真.玄学
作者: longerer    时间: 2020-7-4 11:01
谢谢大佬分享
作者: Water_Box    时间: 2020-7-4 11:03
  现在没有什么着色器地图吧,想试试
作者: Q3224704190    时间: 2020-7-5 13:35
MCBBS有你更精彩~
作者: 破碎の琉璃    时间: 2020-7-10 09:03
提示: 作者被禁止或删除 内容自动屏蔽
作者: mc_xiaoqii    时间: 2020-7-17 11:11
6666666666666666666666666
作者: 还会再见面吗_    时间: 2020-7-25 17:08
哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦
作者: 夕阳红熊猫    时间: 2020-10-7 10:13
抱歉。我来看了(有人看),但是我看的云里雾里的。。。。。




欢迎光临 Minecraft(我的世界)中文论坛 (https://www.mcbbs.net/) Powered by Discuz! X3.5