透明效果

透明效果一般有两种实现方法:

  • 第一种,使用透明度测试(Alpha Test)
  • 第二种,使用透明度混合(Alpha Blending)

透明度测试透明度混合机制

透明度测试(Alpha Test):只要一个片元的透明度不满足条件(小于某阀值),那么它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就按照普通的不透明物体处理,即进行深度测试、深度写入。透明度测试不需要关闭深度写入。

透明度混合(Alpha Blending):使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色值。但是,这需要关闭深度写入。虽然关闭了深度写入,但是没有关闭了深度缓冲,此时深度缓冲还是可读的。

不同的渲染顺序带来的结果:(A半透明,B不透明)

第一种:先渲染B,再渲染A.

结果:能得到正确的渲染效果。

第二种:先渲染A,再渲染B.

结果:不能得到正确的渲染效果,因为在渲染A时已经关闭了深度写入,所以A不会修改深度缓冲,等到渲染B时,B直接覆盖了A的颜色。

渲染常用顺序:

  1. 先渲染所有不透明物体,开启深度测试和深度写入。
  2. 半透明物体按离摄像机距离远近排序,从后往前渲染,开启深度测试,关闭深度写入。

部分相互重叠的物体不适用,解决方法是分割网格。

unity shader的渲染顺序

Unity为了解决渲染顺序问题提供了渲染队列(render queue)解决方案。

实现透明度测试时需要添加代码:

SubShader{
Tags {"Queue" = "AlphaTest"}
Pass{
...
}
}

实现透明度混合需要添加代码:

SubShader{
Tags {"Queue" = "Transform"}
Pass{
ZWrite Off
...
}
}

透明度测试

关键函数

clip函数是CG中的一个函数:

void clip(float4 x);
void clip(float3 x);
void clip(float2 x);
void clip(float1 x);
void clip(float x);

全部代码

Shader "Unity Shaders Book/Chapter 8/Alpha Test" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
}
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"} Pass {
Tags { "LightMode"="ForwardBase" } CGPROGRAM #pragma vertex vert
#pragma fragment frag #include "Lighting.cginc" fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Cutoff; struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(_Object2World, v.vertex).xyz; o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o;
} fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor = tex2D(_MainTex, i.uv); // Alpha test
clip (texColor.a - _Cutoff);
// Equal to
// if ((texColor.a - _Cutoff) < 0.0) {
// discard;
// } fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir)); return fixed4(ambient + diffuse, 1.0);
} ENDCG
}
}
FallBack "Transparent/Cutout/VertexLit"
}

效果

透明度混合

透明度混合的本质就是用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新颜色。

混合公式如下:

unity提供的混合命令:

透明度混合完整代码

Shader "Unity Shaders Book/Chapter 8/Alpha Blend" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_AlphaScale ("Alpha Scale", Range(0, 1)) = 1
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} Pass {
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert
#pragma fragment frag #include "Lighting.cginc" fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale; struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(_Object2World, v.vertex).xyz; o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o;
} fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor = tex2D(_MainTex, i.uv); fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir)); return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
} ENDCG
}
}
FallBack "Transparent/VertexLit"
}

效果

开启深度写入的半透明效果

前面提到由于关闭深度写入而造成的错误排序的情况。可以使用两个Pass的办法来解决

第一个Pass: 开启深度写入,但不输出颜色,它的目的仅仅是为了把该模型的深度值写入深度缓冲中

第二个Pass: 进行正常的透明度混合,由于上个Pass已经的到了像素的正确深度信息,所以可以得到正确的渲染结果。

这种办法的缺点是对性能有一定影响

ShaderLab的混合命令

ShaderLab中的混合因子

参数 描述
One The value of one - use this to let either the source or the destination color come through fully.
Zero The value zero - use this to remove either the source or the destination values.
SrcColor The value of this stage is multiplied by the source color value.
SrcAlpha The value of this stage is multiplied by the source alpha value.
DstColor The value of this stage is multiplied by frame buffer source color value.
DstAlpha The value of this stage is multiplied by frame buffer source alpha value.
OneMinusSrcColor The value of this stage is multiplied by (1 - source color).
OneMinusSrcAlpha The value of this stage is multiplied by (1 - source alpha).
OneMinusDstColor The value of this stage is multiplied by (1 - destination color).
OneMinusDstAlpha The value of this stage is multiplied by (1 - destination alpha).

ShaderLab中的混合操作

操作 描述
Add Add source and destination together.
Sub Subtract destination from source.
RevSub Subtract source from destination.
Min Use the smaller of source and destination.
Max Use the larger of source and destination.
LogicalClear Logical operation: Clear (0) DX11.1 only.
LogicalSet Logical operation: Set (1) DX11.1 only.
LogicalCopy Logical operation: Copy (s) DX11.1 only.
LogicalCopyInverted Logical operation: Copy inverted (!s) DX11.1 only.
LogicalNoop Logical operation: Noop (d) DX11.1 only.
LogicalInvert Logical operation: Invert (!d) DX11.1 only.
LogicalAnd Logical operation: And (s & d) DX11.1 only.
LogicalNand Logical operation: Nand !(s & d) DX11.1 only.
LogicalOr Logical operation: Or (s | d) DX11.1 only.
LogicalNor Logical operation: Nor !(s | d) DX11.1 only.
LogicalXor Logical operation: Xor (s ^ d) DX11.1 only.
LogicalEquiv Logical operation: Equivalence !(s ^ d) DX11.1 only.
LogicalAndReverse Logical operation: Reverse And (s & !d) DX11.1 only.
LogicalAndInverted Logical operation: Inverted And (!s & d) DX11.1 only.
LogicalOrReverse Logical operation: Reverse Or (s | !d) DX11.1 only.
LogicalOrInverted Logical operation: Inverted Or (!s | d) DX11.1 only.

双面渲染的透明效果

上面的透明度测试和透明度混合都无法将物体的背面显示出来,这是因为渲染引擎剔除了物体的背面,所以需要在渲染透明物体使用Cull指令控制需要剔除的渲染图元。

  • Cull Back | Front | Off

分别是:剔除背面的图元 | 剔除前面的图元 | 关闭功能

完整代码

Shader "Unity Shaders Book/Chapter 8/Alpha Blend With Both Side" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_AlphaScale ("Alpha Scale", Range(0, 1)) = 1
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} Pass {
Tags { "LightMode"="ForwardBase" } // First pass renders only back faces
Cull Front ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert
#pragma fragment frag #include "Lighting.cginc" fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale; struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(_Object2World, v.vertex).xyz; o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o;
} fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor = tex2D(_MainTex, i.uv); fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir)); return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
} ENDCG
} Pass {
Tags { "LightMode"="ForwardBase" } // Second pass renders only front faces
Cull Back ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert
#pragma fragment frag #include "Lighting.cginc" fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale; struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}; struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
}; v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(_Object2World, v.vertex).xyz; o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o;
} fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor = tex2D(_MainTex, i.uv); fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir)); return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
} ENDCG
}
}
FallBack "Transparent/VertexLit"
}

效果

Unity Shader 之 透明效果的更多相关文章

  1. unity shader 纹理&透明效果

    1.纹理映射基础 (1)纹理映射通过(u,v)坐标实现.注意:这句话时博主当时面试一家外企被问到的问题. (2)添加纹理属性:——MainTex("Main Tex",2D)=&q ...

  2. Unity Shader实现描边效果

    http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用S ...

  3. Unity Shader 屏幕后效果——颜色校正

    屏幕后效果指的是,当前整个场景图已经渲染完成输出到屏幕后,再对输出的屏幕图像进行的操作. 在Unity中,一般过程通常是: 1.建立用于处理效果的shader和临时材质,给shader脚本传递需要控制 ...

  4. Unity Shader 屏幕后效果——全局雾

    Unity内置的雾效需要在每个shader中分别编写,造成了极大的不便.这里利用屏幕后处理产生可单独控制且自由度更高的雾效. 屏幕后雾效的本质在于,通过深度纹理重构出每个像素在世界空间中的位置,根据得 ...

  5. Unity Shader 屏幕后效果——景深

    景深效果的原理是,在摄像机的近裁剪平面和远裁剪平面之间可以设置一个焦距,在这个距离所在的平面上的物体最为清晰,而这个距离之前或之后的物体成像是一种模糊状态(根据距离逐渐模糊,最终达到最为模糊的状态). ...

  6. Unity Shader 屏幕后效果——Bloom外发光

    Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成. 一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客: https:/ ...

  7. Unity Shader 屏幕后效果——高斯模糊

    高斯模糊是图像模糊处理中非常经典和常见的一种算法,也是Bloom屏幕效果的基础. 实现高斯模糊同样用到了卷积的概念,关于卷积的概念和原理详见我的另一篇博客: https://www.cnblogs.c ...

  8. Unity Shader 屏幕后效果——边缘检测

    关于屏幕后效果的控制类详细见之前写的另一篇博客: https://www.cnblogs.com/koshio0219/p/11131619.html 这篇主要是基于之前的控制类,实现另一种常见的屏幕 ...

  9. Unity Shader 屏幕后效果——摄像机运动模糊(速度映射图实现)

    速度映射图主要是为了得到每个像素相对于前一帧的运动矢量,其中一种方法是使用摄像机的深度纹理来推导. 推导过程如下: 先由深度纹理逆推出NDC(归一化的设备坐标)下的顶点坐标,利用VP矩阵(视角*投影矩 ...

随机推荐

  1. CSS基础复习

    重新撸一遍CSS的基础,因为以前面试的时候被问到,突然发现某些概念搞不清楚,瞬间懵逼了,其实我都知道的,就是因为不会炒概念,导致面试官觉得我很low,你特么连这个都不知道还敢来面试,回家种田去好嘛! ...

  2. fetch and js异步介绍

    http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html   Javascript异步编程的4种方法 ht ...

  3. UVA - 10494 If We Were a Child Again

    用java写的大数基本操作,java要求的格式比较严谨. import java.util.*; import java.math.*; public class Main { public stat ...

  4. 【译】DTD - Entities

    原文:DTD - Entities 实体用于定义XML文档中特殊字符的快捷方式. 实体主要有四种类型: 内置实体(Built-in entities) 字符实体(Character entities) ...

  5. VueJS $refs 在 ElementUI 中遇到的问题

    表单验证的时候  $refs 拿不到 暂且是用 $nextTick 解决,具体原因有待研究 假入在 created 中注册时间来验证 validate,那就放在mounted中 或者...注册了 ev ...

  6. Linux下用到数据库sqlite3

    最近在Linux下用到数据库sqlite3,于是开始了该方面的学习. 0. 引言 我们这篇文章主要讲述了如何在C/C++语言中调用 sqlite 的函数接口来实现对数据库的管理, 包括创建数据库.创建 ...

  7. VirtualBox与Genymotion命令行启动

    一.VirtualBox命令行启动 1.添加环境变量: %programfiles%\Oracle\VirtualBox 2.用VBoxManage查看已存在vmname|uuid命令: VBoxMa ...

  8. Firefox缓存文件夹位置设置及清除缓存方法

    地址栏敲入: about:config, 新建一个"browser.cache.disk.parent_directory", 并设置为你要的缓存文件夹, 例如:  "F ...

  9. Transport failed: java.io.EOFException

    ActiveMQ服务端有时会报Transport failed: java.io.EOFException这样的错误,这是由客户端丢失连接并反复尝试连接导致的,不是什么大问题,有时网络波动就会产生这种 ...

  10. str.format() 格式化字符串函数

    语法 它通过{}和:来代替%. “映射”示例 通过位置 In [1]: '{0},{1}'.format('kzc',18) Out[1]: 'kzc,18' In [2]: '{},{}'.form ...