图形学进阶——深度与模板测试
Z Test & Stencil Test深度测试与模板测试
百人计划学习地址:图形 3.1 深度与模板测试 传送门效果示例
一、模板测试 Stencil Test
流程:
1. 什么是模板测试
① 从渲染管线出发
像素权限测试——》裁剪测试——》透明度测试——》模板测试——》深度测试——》混合等操作——》输出片元到帧缓冲区
② 从逻辑上理解
就是通过一定条件判断该片元或者片元属性执行抛弃操作还是保留操作
③ 从书面概念上理解
需要注意的是:模板测试发生在透明度测试之后,深度测试之前
2 .模板测试的语法表示
具体的含义如下:
- referenceValue :自己定义的模版参考值,每个片元或者说像素点就是用这个值进行比较
- readMask::读取掩码,取值范围也是0-255的整数,默认值为255。即读取的时候不对referenceValue和stencilBufferValue产生效果,读取的还是原始值
- writeMask:输出掩码,当写入模板缓冲时进行掩码操作(按位与&),writeMask取值范围是0-255的整数,默认值也是255,即当修改stencilBufferValue值时,写入的仍然是原始值。
- ComparisonFunction :重点,进行模板测试时候的判断方法,具体有以下几种
- Pass stencilOperation:条件满足后的更新操作
- Fail stencilOperation:条件不满足后的更新操作
- ZFail stencilOperation:模板测试通过,但是深度测试不通过的更新操作
上诉三种具体更新操作方法的值如下
3. Unity3d中使用模板测试
用作遮罩效果的shader:默认ref为1,总是通过模板测试,并替换模板缓冲区的值
用作显示在遮罩后的shader,需要满足equal的像素才会通过模板缓冲区
最终效果:
4 .总结
5. 模板测试扩展
二、深度测试 Z-Test
1.一些效果
2. 什么是深度测试
①从渲染管线上看
图中可以看到深度测试是发生在逐片元操作的,而且处于模板测试之后,透明度混合之前
还有一个特殊的技术叫early-Z,它会发生在片元着色器之前
② 从逻辑上理解
深度测试判断:先判断是否开启了ZWrite(深度写入)再片元的深度值与深度缓冲区中的值进行比较,如果满足条件则,写入深度值,不满足则忽略
颜色缓冲区也会进行同样的判断处理
与模板测试有什么异同?
主要在于多了一个ZWrite的判断
③从书面概念上理解
④从发展上理解
关于画家算法,大概可理解成:先画远处的物体,再画近处的物体,近处就可以遮挡住远处
但是这样会导致计算量过大,所以才需要使用深度缓冲区(Z-Buffer)来减少overdraw
3. 深度缓冲区 Z-Buffer
与模板缓冲区不同的是,模板缓冲区存储的值是8位的int值,深度缓冲区通常是24位的
通过Z Write和Z Test来调用Z-Buffer,实现想要的渲染结果
4. Z Write
简单的说:就是首先判断是否通过深度测试(Z-Test),不通过则什么都不会发生;
如果通过了深度测试,首先会将像素值写入颜色缓冲区,再判断是否开启了深度写入(ZWrite),如果开启则写入深度缓冲区,反之不写入。
5. ZTest的比较操作
需要注意的是,一开始缓存值是无穷大的,而默认的是小于等于缓存值则通过
6 .渲染队列
首先看一下Unity中的几种内置的渲染队列,按照渲染顺序,从先到后进行排序
队列数越小的,越先渲染,队列数越大的,越后渲染。
名称 | 队列数 | 定义 |
---|---|---|
Background | 1000 | 最早被渲染的队列,一般用于设置游戏背景 |
Geometry | 2000 | 不透明的物体的渲染队列,也是Unity3d的默认队列,大多数物体都应该使用这个渲染队列 |
AlphaTest | 2450 | 含有透明通道,需要进行透明度测试(Alpha Test)物体的队列,为了保证在不透明物体之后渲染使用 |
Transparent | 3000 | 半透明物体的渲染队列,一般不写入深度缓冲区或者需要Alpha Blend的物体在该队列渲染 |
Overlay | 4000 | 最后渲染的物体队列,一般用作后处理,比如镜头光晕,屏幕贴片之类的 |
Unity默认的渲染队列是Geometry
- 不透明物体的渲染顺序是从前往后
- 透明物体的渲染顺序是从后往前(因此会发生OverDraw
另外,在shader中还有个Tag叫Render Type,这个没有Render Queue那么常用,这里也顺便记录一下:
- Opaque: 用于大多数着色器(法线着色器、自发光着色器、反射着色器以及地形的着色器)。
- Transparent:用于半透明着色器(透明着色器、粒子着色器、字体着色器、地形额外通道的着色器)。
- TransparentCutout: 蒙皮透明着色器(Transparent Cutout,两个通道的植被着色器)。
- Background: 天空盒着色器。
- Overlay: GUITexture,镜头光晕,屏幕闪光等效果使用的着色器。
- TreeOpaque: 地形引擎中的树皮。
- TreeTransparentCutout: 地形引擎中的树叶。
- TreeBillboard: 地形引擎中的广告牌树。
- Grass: 地形引擎中的草。
- GrassBillboard: 地形引擎何中的广告牌草。
7. 简述 Early-Z技术
注:Early-Z是在片元着色器之前进行的操作,因此被抛弃的片元是无法进入片元着色器操作的;通过的像素最终还是会进行ZTest操作
8 .深度值
深度值是从哪里来的?
为什么深度缓冲区中的值不是线性的?
我们先来讨论下关于深度值精度:
在深度缓冲区中包含深度值介于0.0和1.0之间,从观察者看到其内容与场景中的所有对象的 z 值进行了比较。
我们需要转换这些视图空间 z 值到 [0,1] 的范围内,方法之一就是线性将它们转换为 [0,1] 范围内。下面的 (线性) 方程把 z 值转换为 0.0 和 1.0 之间的值 :
far和near分别是投影矩阵中可见视图截锥的远近值,Z值与深度值的关系如下图
物体接近近平面的时候,方程给出的深度值接近0.0,物体接近远平面时,方程给出的深度接近1.0。
然而,在实践中是几乎从来不使用这样的线性深度缓冲区。正确的投影特性的非线性深度方程是和1/z成正比的
z 值和产生深度缓冲区的值在下列图中的非线性关系:
从图中看到:物体的Z值越小(离得越近),深度值的精度越高,Z值越大(离得越远),深度值的精度越低;
现在我们再来理解为什么要时候用非线性的精度:
- 根据人眼的特性,离得越近的物体,层次的精度需要更精确,离得越远则不需要太精确
- 防止深度冲突 Z-Fighting
什么是深度冲突 Z-Fighting?
当两个平面或者三角形十分紧密相互平行,而深度缓冲区不具有足够的精度以至于无法得到哪个在前/在后,会导致两个形状不断切换导致怪异出问题,这种情况被称为深度冲突Z-fighting
因此,为了防止深度冲突,我们需要近处的物体需要更高的深度值精度,解决深度冲突还有以下几种方法:
- 物体之间不要离得太近,防止他们的三角形重叠
- 尽可能把近平面设置得远一些。前面我们讨论过越靠近近平面的位置精度越高。所以我们移动近平面远离观察者,我们可以在椎体内很有效的提高精度。
- 放弃一些性能来得到更高的深度值的精度。大多数的深度缓冲区都是24位。但现在显卡支持32位深度值,这让深度缓冲区的精度提高了一大节。
9. Unity中的使用
略过,视频中已经讲解的非常详细
注:一个物体有多pass渲染时,Unity会把物体放到所有pass中队列最靠前的那个队列中,并根据代码逐Pass执行
10.深度测试总结
11.深度测试的扩展
作业
想尝试做一下深度测试扩展中湖水的效果
首先在Unity3d中创建一个Panel作为水的物体,并加一个简单的顶点动画效果表现水的波动
顶点着色器部分
offset.y = sin(_Time.y * _Speed + (v.vertex.z * v.vertex.x * _WaveFrequency)) * _WaveHeight;
offset.xzw = 0;
o.vertex = UnityObjectToClipPos(v.vertex + offset);
并取消深度写入和开启混合
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
可以得到一个简单的湖水晃动的效果
然后开始实现湖水边缘的颜色渐变
这里需要用到深度贴图(depth texture)计算。根据“深度”计算水应呈现的颜色。
需要用到几个函数和变量
- _CameraDepthTexture:Unity内置的变量。用于表示camera的深度贴图。
- SAMPLE_DEPTH_TEXTURE_PROJ:对深度贴图进行采样。该方法接受深度纹理和纹理坐标这两个参数。纹理坐标通常是由顶点着色器输出插值而得的屏幕坐标。
- LinearEyeDepth:通过纹理采样得到深度值后,这些深度值往往是非线性的,这种非线性来自于透视投影使用的裁剪矩阵。通过LinearEyeDepth把投影后的深度值变换到线性空间下。
首先在顶点着色器中获取到像素得的屏幕坐标
o.screenPos = ComputeScreenPos(o.vertex);
然后在片元着色器中进行深度的计算
需要定义两种颜色,来对湖水中心和边缘进行一个lerp
float depthTextureValue = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, i.screenPos);float depth = LinearEyeDepth(depthTextureValue);float depthGap = depth - i.screenPos.w;float depthLerp = saturate(depthGap) * _FadeStrengh;;float4 waterColor = lerp(_Color, _DeepColor, depthLerp);
得到效果如下
然后开始实现边缘水花的效果
首先使用一张noise图进行采样,并让给他一个uv动画
float speed = _Time.x * _Speed * 0.5;
float4 var_WaterNoise = tex2D(_WaterNoiseTex, uv_WaterNoise);
再次用深度值计算边缘的位置,加入2个参数控制边缘的范围,再进行step运算并取反
最后与之前的水面效果相加
float foamStep = saturate((depthGap / _FoamWidth)) * _FoamStep;float surfaceNoise = 1 - step(var_WaterNoise, foamStep);return surfaceNoise + waterColor;
就可以得水花的效果了
材质球设置如下
笔记参考内容:https://gameinstitute.qq.com/community/detail/125962
https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/01%20Depth%20testing/
https://blog.csdn.net/puppet_master/article/details/53900568?spm=1001.2014.3001.5501
作业参考内容:https://zhuanlan.zhihu.com/p/144818695
https://zhuanlan.zhihu.com/p/350305151
图形学进阶——深度与模板测试相关推荐
- (zt)OpenGL中的Alpha测试,深度测试,模板测试,裁减测试
转自http://www.cppblog.com/flashboy/archive/2009/09/01/94974.html 大家好.现在因为参加工作的关系,又是长时间没有更新.趁着国庆的空闲,总算 ...
- Unity管线渲染中的三大测试之模板测试
我感觉将近一个月没有写技术文档了,最近了可能能在研究一些比较抽象计算机图形学,知识点太多,也过于零碎.我个人认为管线渲染流程当中三大测试是控制效果的一个关卡.这篇文章今天本来写了个开头,回到家看了题目 ...
- Opengl-深度测试模板测试
###深度测试 深度缓冲:用来存储深度信息的,可以这么理解,在你屏幕上最后留下的裁剪区域你看到的东西其实是有深度的,就像现实世界里一样,有远近这样.然后这个远近的程度信息就存储在了深度缓冲里 深度测试 ...
- UnityShader29:模板测试
一.什么是模板测试 OpenGL基础30:模板测试 Unity官方文档:https://docs.unity3d.com/Manual/SL-Stencil.html 一个很经典的模板测试例子就是 U ...
- OpenGL基础30:模板测试
前置:OpenGL基础29:深度测试 一.模板测试 前面一章提到过:深度缓冲测试在片段着色器运行.以及模板测试(Stencil Testing)之后,那么这下知道模板测试是在什么时候了吧,模板测试和深 ...
- 【Unity3D】基于模板测试和顶点膨胀的描边方法
1 前言 选中物体描边特效 中介绍了基于模板纹理模糊膨胀的描边方法,该方法实现了软描边,效果较好,但是为了得到模糊纹理,对屏幕像素进行了多次渲染,效率欠佳.本文将介绍另一种描边方法:基于模板测试和顶点 ...
- DirectX11 模板测试
模板测试 1. 模板测试实现过程 如前所述,我们可以使用模板缓冲区来阻止像素片段渲染到后台缓冲区的某些区域.判断一个特定像素是否可以写入后台缓冲区的操作称为模板测试(stencil test),其实现 ...
- OpenGL学习二十九:模板缓冲区与模板测试
帧缓冲区有许多缓冲区构成,这些缓冲区大致分为: 颜色缓冲区:用于绘图的缓冲区,它包含了颜色索引或者RGBA颜色数据. 深度缓冲区:存储每个像素的深度值,当启动深度测试时,片段像素深度值和深度缓冲区深度 ...
- OpenGL学习笔记(七)-深度测试-模板测试-混合
参考网址:LearnOpenGL 中文版 第四章 高级OpenGL 4.1 深度测试 4.1.1 深度缓冲 1.深度缓冲用来防止被阻挡的面渲染到其它面的前面,由窗口系统自动创建,在每个片段中储存了它的 ...
最新文章
- 深度学习《各种归一化的区别》
- 摩托罗拉Edge真机谍照曝光:挖孔瀑布屏+骁龙765
- 3-cd 命令总结
- 从开源开发者身上学到的 5 种品质
- 导出excel乱码问题
- Cisco WebEx设备ssl证书安装指南
- sql 2000 数据库置疑
- html 画xyz坐标,xyz坐标轴怎么画要图谢谢?
- linux 用户复杂秘密,linux用户的秘密之login.defs文件详解
- flea-db使用之SQL模板接入
- MRT工具谢幕,HEG华丽登场
- 4年老用户!从R9s Plus换到Find X3,这些体验太上头
- 计算机网络实验 Go Back N (带有ACK)滑动窗口协议 C++
- 【用过的抢票软件汇总】
- 怎样提取音频制作手机铃声
- 【星游记】新4K分享
- 8.9 五色定理(Heawood 1890)
- city-picker插件使用-移动h5三级联动
- 单机程序修改log4j配置文件位置
- vs2015下openGL freeglut+glew+gltools64位傻瓜式环境配置