自言自语
此次学习基于深度法线纹理的边缘检测 法线此效果 只能对正确设置了渲染顺序的物体生效 即 “Queue”=“Geometry” 所以并不适合正式项目。 且发现做片段着色器中,插值控制参数 非1即0,但比较方法中的细节参数 却能影响描边效果 不解为何 。 按我的理解 既然控制总参数 非1即0 那么最终效果也就只有两种极端情况。 但此效果却能做到细微的变化 没能明白是为何。记录于此,理解后再更
2020/01/26 更新
一开始把 int isSameNormal = (diffNormal.x+diffNormal.y)<0.1 理解为三元运算, 却发现实际效果差很大 因此后边做了修改。 所以int isSameNormal = (diffNormal.x+diffNormal.y)<0.1并不能简单的直接理解为三元运算 但他到底是什么意思呢。 也许弄明白了以后就可以理解细微参数变化对描边状态的影响了
//int isSameNormal = (diffNormal.x+diffNormal.y)<0.1?1.0:0;
int isSameNormal = (diffNormal.x+diffNormal.y)<0.1;
效果
面板
GIF演示 (错误效果版 稍晚些时候回家再更新修改过代码的正确效果版)
正确效果版
C#部分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class OutlineRobertWithDepthNormalsTexture : PostProcessWangBase
{
[Range(0f,4f)]
public float outLineWidth = 1f;
public float sensitivityN = 1f;
public float sensitivityD = 1f;
[Range(0f,1f)]
public float edgeOnly = 1f;
public Color outLineColor = Color.black;
public Color backGroundColor = Color.white;
public Shader outlineShder;
private Material material;
public Material outlineMaterial
{
get
{
material = CheckShaderAndMaterial(outlineShder, material);
return material;
}
}
private void OnEnable()
{
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
}
protected void OnRenderImage(RenderTexture source, RenderTexture destination)
{
//这个没啥说的 传参就行了
if(outlineMaterial == null )
{
Graphics.Blit(source, destination);
}
else
{
outlineMaterial.SetFloat("_OutlineWidth", outLineWidth);
//原本书中所写存入一个向量中 但我为了方便区分 直接设置两个参数
//outlineMaterial.SetVector("_Sensitivity", new Vector4(sensitivity.x, sensitivity.y, 0, 0));
outlineMaterial.SetFloat("_SensitivityN", sensitivityN);
outlineMaterial.SetFloat("_SensitivityD", sensitivityD);
outlineMaterial.SetFloat("_EdgeOnly", edgeOnly);
outlineMaterial.SetColor("_OutlineColor", outLineColor);
outlineMaterial.SetColor("_BackGroundColor", backGroundColor);
Graphics.Blit(source, destination, outlineMaterial);
}
}
}
shader部分
Shader "TNShaderPractise/ShaderPractise_OutLineRobertWithDepthNormalsTexture"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue" ="Transparent" }
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_TexelSize;
sampler2D _CameraDepthNormalsTexture;
float _OutlineWidth;
float _SensitivityN;
float _SensitivityD;
float _EdgeOnly;
float4 _OutlineColor;
float4 _BackGroundColor;
struct v2f
{
float4 pos : SV_POSITION;
//存储UV数组
float2 uv[5] : TEXCOORD1;
};
//这次尝试直接使用Unity封装好的 appdata结构体
v2f vert (appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
half2 uv = v.texcoord;
//保存正常UV
o.uv[0]=uv;
//判定平台
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y <0)
uv.y = 1- uv.y;
#endif
//根据Robert算子 对UV进行偏移采样 并通过 outlinewidth控制采样距离 也可以理解为粗细 在顶点着色器是为了减少运送 反正可以插值到片段着色器
o.uv[1] = uv + _MainTex_TexelSize.xy*half2(1,1)*_OutlineWidth;
o.uv[2] = uv + _MainTex_TexelSize.xy*half2(-1,-1)*_OutlineWidth;
o.uv[3] = uv + _MainTex_TexelSize.xy*half2(-1,1)*_OutlineWidth;
o.uv[4] = uv + _MainTex_TexelSize.xy*half2(1,-1)*_OutlineWidth;
return o;
}
//定义check函数 判定是否有差异
half CheckSame (half4 center,half4 sampleDN )
{
//获得法线数据 但并不需要解码 因为只要比较差异就行了
float2 centerNormal = center.xy;
//获得深度值 直接解码得到
float centerDepth = DecodeFloatRG(center.zw);
float2 sampleDNNormal = sampleDN.xy;
float sampleDNDepth = DecodeFloatRG(sampleDN.zw);
//通过控制差值大小 影响采样权重
float2 diffNormals = abs(centerNormal-sampleDNNormal)*_SensitivityN;
//这里相当于三元运算 (diffNormals.x+diffNormals.y)<0.1?:1.0:0;
int isSameNormal = (diffNormals.x+diffNormals.y)<0.1;
// 直接控制深度差值大小
float diffDepth = abs(centerDepth-sampleDNDepth)*_SensitivityD;
//同理三元运算 diffDepth<0.1?:1.0:0 * centerDepth
int isSameDepth = diffDepth<0.1*centerDepth;
//****最后在得出综合差值 非1 即 0 这里并不能直接将三元运算写在等式右边 会造成显示翻转的情况
//****int isSame = isSameNormal*isSameDepth<0.1?1.0:0;
int isSame = isSameNormal*isSameDepth<0.1;
//****要在这里直接做判断返回 1 和0 才可
return isSame<0.1?1.0:0;
}
float4 frag (v2f i ): SV_Target
{
half4 depthNormalsTexture1 = tex2D(_CameraDepthNormalsTexture ,i.uv[1]);
half4 depthNormalsTexture2 = tex2D(_CameraDepthNormalsTexture ,i.uv[2]);
half4 depthNormalsTexture3 = tex2D(_CameraDepthNormalsTexture ,i.uv[3]);
half4 depthNormalsTexture4 = tex2D(_CameraDepthNormalsTexture ,i.uv[4]);
float edge =1;
//调用其差值比较后的结果 累乘到 edge 非1 即 0 疑问 都是 1 和 0 为什么调节参数还能有变化...
edge *= CheckSame(depthNormalsTexture1,depthNormalsTexture2);
edge *= CheckSame(depthNormalsTexture3,depthNormalsTexture4);
//****因为上边做了相应书写规范处理 所以这边也要调整插值顺序
//以下插值顺序与书中正好相反,因为这样才符合预期
//****fixed4 withTexture = lerp (tex2D(_MainTex,i.uv[0]),_OutlineColor,edge) ;
//****fixed4 edgeOnly = lerp (_BackGroundColor,_OutlineColor,edge);
//****fixed4 finalColor = lerp (edgeOnly,withTexture,_EdgeOnly);
fixed4 withTexture = lerp (_OutlineColor,tex2D(_MainTex,i.uv[0]),edge) ;
fixed4 edgeOnly = lerp (_OutlineColor,_BackGroundColor,edge);
fixed4 finalColor = lerp (withTexture,edgeOnly,_EdgeOnly);
return finalColor;
}
ENDCG
pass
{
ZWrite Off ZTest Always Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
FallBack Off
}