1、遮挡半透明效果是什么
在游戏开发中,遮挡半透明效果就是物体被挡住的部分,也能呈现出一种半透明效果而被看到(具体效果可以自定义)比如 当角色在建筑物之间穿行时,被遮挡部分能够呈现出半透明效果而被我们看到。遮挡半透明效果包含了两种显示效果,即挡住和没被挡住的部分,没被遮挡的部分正常显示,被遮挡的部分自定义显示(半透明、X光等等)
2、遮挡半透明效果的基本原理
一句话描述它的基本原理:两个Pass渲染对象,一个Pass用于渲染被遮挡部分,一个Pass用于渲染未遮挡部分。被遮挡部分通过修改深度测试规则和关闭深度写入达到目的
关键点:
- 如何渲染遮挡部分
- 如何渲染未遮挡部分
首先进行一个关于深度测试和深度写入的知识回顾,我们可以设置Pass的深度测试规则,只有通过了深度测试,该Pass才会执行进行渲染。
不设置的话,默认为LEqual 小于等于,通过了深度测试后,我们可以使用 Zwrite On/Off 来决定是否将通过深度测试的值写入缓冲区
- 如何渲染遮挡部分
在第一个Pass中,我们按照想要的遮挡效果去实现Shader即可(比如半透明或X射线效果)
最关键的点,是需要修改该Pass的深度测试规则,并且关闭深度写入!
修改深度测试的目的:
只有自己的深度值大于深度缓冲中的值才渲染,相当于只有前方有遮挡时才渲染
关闭深度写入的目的:
如果前方有遮挡,又写入较大的深度值,执行第二个Pass时会通过深度写入(因为第二个Pass 默认是 LEqual),导致第二个Pass的内容通过深度测试被全部渲染,呈现出未被遮挡的错误效果!
- 如何渲染未遮挡部分
在第二个Pass中我们只需要正常按需求(是否受光照影响等)渲染模型即可,不需要做什么特别处理
3、自定义半透明效果
普通的半透明效果非常容易实现,只需要设置混合因子即可。而要实现类似X射线的效果,也就是边缘不透明,中间透明的效果,可以利用尼尔反射的公式来得到:
其中:
- R(θ) 表示入射角为θ时时的反射率
- R0 是垂直入射某介质时的反射率
- V 是视角方向单位向量(入射角)
- N 是顶点法线单位向量
将得到的 入射角为θ的反射率 作为自定义颜色的A值,便可以得到类似的结果
4、实现
基础实现
Shader "ShaderProj/16/OcclusionTransparent"
{Properties{_MainTex ("Texture", 2D) = "white" {}_Alpha ("Alpha", Range(0, 1)) = 0.5}SubShader{Tags { "RenderType"="Opaque" }Pass{ZTest GreaterZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;fixed _Alpha;v2f vert (appdata_base v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);return fixed4(col.rgb, _Alpha);}ENDCG}Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;fixed _Alpha;v2f vert (appdata_base v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);return col;}ENDCG}}
}
X 射线效果实现
Shader "ShaderProj/16/OcclusionTransparent_X"
{Properties{_MainTex ("Texture", 2D) = "white" {}// 菲涅尔反射颜色_FresnelScale ("FresnelScale", Range(0,2)) = 1_FresnelN ("FresnelN", Range(0, 5)) = 5_Color ("Color", Color) = (1, 1, 1, 1)}SubShader{Tags { "RenderType"="Opaque" }Pass{ZTest GreaterZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float4 vertex : SV_POSITION;float3 worldViewDir : TEXCOORD0;float3 worldNormal : TEXCOORD1;};fixed _FresnelN;fixed _FresnelScale;fixed4 _Color;v2f vert (appdata_base v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.worldViewDir = normalize(WorldSpaceViewDir(v.vertex));o.worldNormal = UnityObjectToWorldNormal(v.normal);return o;}fixed4 frag (v2f i) : SV_Target{fixed alpha = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(normalize(i.worldViewDir), normalize(i.worldNormal)), _FresnelN);return fixed4(_Color.rgb, alpha);}ENDCG}Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;fixed _Alpha;v2f vert (appdata_base v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);return col;}ENDCG}}
}