8.透明效果

透明度:透明度为1,物体完全不透明;为0,完全透明不显示。实现透明两种方式,透明度测试,透明度混合

深度缓冲(z-buffer):根据深度缓冲里的值来判断该片元距离摄像机的距离,判断某片元的深度值与深度缓存中的值进行比较,该值距离摄像机更远,则不进行渲染;否则,该片元的值覆盖掉颜色缓冲中的像素值,并把深度值进行更新。
深度测试:进行深度值的比较。

Z缓冲器 --保存各像素处物体深度值
深度写入:深度值的更新。
帧缓冲器 – 保存各像素颜色值。当物体渲染时,通过帧缓冲器,写入的是颜色缓冲

1.当ZWrite为On时,ZTest通过时,该像素的深度才能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值也会写入颜色缓存。

2.当ZWrite为On时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。

3.当ZWrite为Off时,ZTest通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值会写入颜色缓存。

4.当ZWrite为Off时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。

透明度测试:先将Z缓冲器中每个单元的初始值置为最小值。当要改变某个像素的颜色值时,首先检查当前多边形的深度值是否大于该像素原来的深度值(保存在该像素所对应的Z缓冲器的单元中),如果大于,说明当前多边形更靠近观察点,用它的颜色替换像素原来的颜色;否则说明在当前像素处,当前多边形被前面所绘制的多边形遮挡了,是不可见的,像素的颜色值不改变。

透明度测试:通过片元的透明度与阈值进行比较,确定某片元是否渲染
透明度混合:达到半透明效果(关闭深度写入,不关闭深度测试)使用当前片元的透明度作为混合因子,与存储在颜色缓存中的颜色值进行混合,得到新颜色。

渲染顺序很重要(在关闭深度写入之后)

一般的渲染顺序是:
(1)先渲染所有不透明物体,并且开起深度测试和深度写入
(2)把半透明物体按照摄像机距离进行排序,从后往前进行渲染。开启深度测试,关闭深度写入。

一.透明度测试:
// Upgrade NOTE: replaced ‘mul(UNITY_MATRIX_MVP,)’ with 'UnityObjectToClipPos()’

Shader "Custom/Shadser8.1" {
Properties {
_Color ("Main Tint", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Cutoff("Alpha Cutoff",Range(0,1))=0.5
}
SubShader {
/*
"Queue"="AlphaTest":Unity中透明度测试使用的渲染队列是名为AlphaTest的队列
"IgnoreProjectors"="True":意味着这个Shader不会受到投影器的影响
RenderType标签可以让Unity把这个Shader归入到提前定义的组(这里就是TransparentCutout组)
通常使用了透明度测试的shader都应该在SubShader中设置这3个标签
*/
Tags{"Queue"="AlphaTest""IgnoreProjectors"="True""RenderType"="TransparentCutout"}
Pass
{
Tags{"LightMode"="ForwardBase"}
//Cull Off//控制双面渲染开关
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=UnityObjectToClipPos(v.vertex);//裁剪空间
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);//等价于o.uv=v.texcoord.xy* _MainTex_ST.xy(Tilling)+_MainTex_ST.zw(OffSet);
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);
clip(texColor.a-_Cutoff);//当texColor.a小于材质参数_Cutoff时u,该片元就会产生完全透明的效果,相当于一个判定,随着_Cutoff增大,texColor.a-_Cutoff会逐渐减小,当小于0时,则全透明
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"
}

效果较为极端,要么渲染,要么完全透明。
二.透明度混合
//透明度混合原理:用_AlphaScale影响当前图形的a值,实现透明度的改变。

    Shader "Custom/shader8.2" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _AlphaScale("Alpha Scale",Range(0,1))=1
        }
    //任何使用了透明度混合(关闭了深度写入的Shader)的物体都应该使用Transparent队列
    //blend命令两个作用:1.打开混合模式 2.设置混合因子
    
 SubShader {
    Tags{"Queue"="Transparent" "IgnoreProjectors"="True""RenderType"="Transparent"}
    Pass
    {
    Tags{"LightMode"="ForwardBase"}
    ZWrite Off
             Blend   SrcAlpha OneMinusSrcAlpha
    
    //Cull Off//控制双面渲染开关
    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=UnityObjectToClipPos(v.vertex);
    o.worldNormal=UnityObjectToWorldNormal(v.normal);
    o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
    o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);//等价于o.uv=v.texcoord.xy* _MainTex_ST.xy(Tilling)+_MainTex_ST.zw(OffSet);
    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));
            //用_AlphaScale影响当前图形的a值,实现透明度混合
    return fixed4(ambient+diffuse,texColor.a * _AlphaScale);
    }
    ENDCG
    }
    }
    FallBack "Transparent/VertexLit"
    }

如上所示,关闭了深度写入,但是在自身发生遮挡的时候,无法确定渲染顺序,往往造成错误的效果。因此需要想办法,重新开启深度写入。
三.可以同时开启深度写入和透明度混合,但需要放在两个pass中
第一个pass,得到了逐像素的的正确的深度信息(开深度写入,不写入颜色 ColorMask 0)
第二个pass,正常的透明度混合
就可以有效的避免,比如自身遮挡带来的透明现象错误

Shader "Custom/shader8.3" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _AlphaScale("Alpha Scale",Range(0,1))=1
    }
    SubShader {
    Tags{"Queue"="Transparent" "IgnoreProjectors"="True""RenderType"="Transparent"}
pass{
            ZWrite On
            ColorMask 0
        }

Pass
{
Tags{"LightMode"="ForwardBase"}
ZWrite Off
         Blend   SrcAlpha OneMinusSrcAlpha

//Cull Off//控制双面渲染开关
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=UnityObjectToClipPos(v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);//等价于o.uv=v.texcoord.xy* _MainTex_ST.xy(Tilling)+_MainTex_ST.zw(OffSet);
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));
        //用_AlphaScale影响当前图形的a值,实现透明度混合
return fixed4(ambient+diffuse,texColor.a * _AlphaScale);
}
ENDCG
}
}
FallBack "Transparent/VertexLit"
}

效果如图所示:
在这里插入图片描述

四.ShaderLab的混合命令
混合如何实现?
片元着色器产生一个颜色时,可以与颜色缓存中的颜色进行混合。
源颜色:片元着色器产生的颜色(s)
目标颜色:从颜色缓存器中读取的颜色(D)
混合后输出的颜色:(O)
上述三者都包含了RGBA四个值。
要使用混合时,除了设置混合状态外,还要开启混合。
混合等式:有S,有D,算O,需要一个等式来进行计算,该等式称为混合等式。
混合时,我们需要两个混合等式:一个混合RGB通道,一个混合A通道。
在设置混合状态时,设置的就是混合等式的操作和因子,此时操作默认是加操作,因子有四个,两个等式,每个等式,每个等式两个因子

五.双面渲染
1.深度测试的双面渲染:
在之前的渲染中,只渲染了面对摄像机的部分,背面没有渲染,使用 Cull off命令,关闭剔除背面的功能。实现深度测试的双面渲染。此外,还可以Cull Back/ Front /Off 剔除 背面/正面/关闭

2.透明度混合的双面渲染
在开启深度写入的情况下,需要保证正确的渲染顺序,两个pass,第一个只渲染背面,cull front,然后进行正常的透明度混合操作。第二个,只渲染正面,cull back,然后进行正常的透明度混合操作。

Shader "Unity Shaders 8.4" {
    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 = UnityObjectToClipPos(v.vertex);
                
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                
                o.worldPos = mul(unity_ObjectToWorld, 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 = UnityObjectToClipPos(v.vertex);
                
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                
                o.worldPos = mul(unity_ObjectToWorld, 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"
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值