深度纹理实现边缘检测
一、为什么要实现深度纹理实现边缘检测
之前的边缘检测原理是利用Socle算子基于像素灰度值检测计算而来 这种计算方式依赖于像素的颜色(灰度值)变化来识别边缘,会受到物体纹理和阴影颜色等因素的影响 这种方式可能不能反应出物体的真实轮廓
而基于深度+法线纹理来实现屏幕边缘检测屏幕后期处理效果 不受纹理和光照的影响,只会根据渲染物体的模型信息(深度、法线)进行判断
注意: - 对于2D图片,基于灰度值的边缘检测更加合适(因为2D图片中的深度和法线信息往往是一致的,不存在差异) - 对于3D场景,基于深度纹理+法线纹理的边缘检测更加合适
二、基本原理
一句话:基于Robert交叉算子,通过比较对角线上的像素的深度和法线值,判断是否在边缘上
1.关键点
- 如何获取对角线上的像素
- 如何进行深度和法线值的比较
- 如何决定是否在边缘上
- 注意点:不会进行卷积计算
2. 解决关键点的具体方法
1.如何得到对角线上的像素
在顶点着色器中,利用纹素进行uv坐标的偏移计算 并且我们可以添加一个可控的 采样偏移距离变量 _SampleDitance 它可以用来决定描边的粗细,值越大描边越粗
原理是: 采样离中心像素越近,检测的变化更细微,深度和法线变化值越小,边缘会较细 采样离中心像素越远,检测范围较大,深度和法线值变化大,边缘会较粗
2.如何进行深度和法线纹理的比较
在片元着色器中,利用顶点着色器中得到的uv坐标,在深度+法线纹理中进行采样,得到深度和法线值 在求出对角线上的两个像素的 深度值差和法线值差 如果其中一个值大于了自定义的阈值 那么我们认为该像素点在物体的边缘上
3.如何决定是否在边缘上
自定义计算规则
三、实现示例步骤
1.Shader部分
- 声明属性,属性映射
- 主纹理 _MainTex
- 边缘检测强度 _EdgeOnly(0-显示场景,1-显示边缘 用于控制自定义背景的颜色)
- 描边颜色 _EdgeColor
- 背景颜色 _BackgroudColor
- 采样偏移距离 _SampleDistance
- 深度敏感度 _SensitivityDepyh
- 法线敏感度 _SensitiviyNormal
- 属性映射时,加入纹素(_MainTex_TexelSize)和深度法线纹理映射(_CameraDephtNormalsTexture)
- 屏幕后处理标配
- ZTest Always
- ZWrite Off
- Cull Off
- 结构体
- 顶点坐标
- uv数组,5个空间(储存中心点、对角线4个点)
- 顶点着色器
- 顶点坐标转化
- 5个uv坐标赋值 注意顺序 中心点、左上、右下、右上、左下
- 片元着色器
- 直接采样四个对角线四个点的深度法线信息
- 实现一个用于比较两点深度、法线信息的函数,返回0或者1,方便进行插值计算
- 声明一个插值变量,0代表边缘色、1代表原颜色
- 考虑背景色插值
- FallBack Off
1 | Shader "Unlit/EdgeDetetionWithDepthAndNormalTexture" |
2.C#部分
- 继承PostEffectBase
- 声明可控变量
- Start中开启深度法线纹理 注意:不要直接-、要 |= ,避免关闭深度法线纹理
- 重写UpdataProperty函数
1 | public class EdgeDetetionWithDepthAndNormalTexture : PostEffectBase |