Unity3D学习笔记(三十五):Shader着色器(2)- 顶点片元着色器

Alpha测试
AlphaTest Great:大于
AlphaTest Less:小于
AlphaTest Equal:等于
AlphaTest GEqual:大于等于
AlphaTest LEqual:小于等于
AlphaTest Never:全不渲染
AlphaTest Always:全部渲染
如果使用后两项的命名的情况下,比较后的数字项没有意义
 
AlphaTest 比较项 数字
AlphaTest Great 0.5 //表示只渲染alpha值大于0.5的部分
AlphaTest Less 0.5 //表示只渲染alpha值小于0.5的部分
 
混合命令
Blend SrcFactor DstFactor
SrcFactor DstFactor 可以的取值
One表示1
Zero表示0
SrcColor当前的颜色
DstColor已经存在的颜色
SrcAlpha当前的透明度
DstAlpha已经存在的颜色的透明度
OneMinusSrcColor当前的颜色取反向 1-SrcColor
OneMinusSrcAlpha当前的Alpha值取反向 1-SrcAlpha
OneMinusDstColor已经存在的颜色取反向 1-DstColor
OneMinusDstAlpha已经存在的颜色的透明度取反向 1-DstAlpha
 
最终颜色 = 新颜色 * SrcFactor + 旧颜色 * DstFactor
 
新颜色:即将写入到颜色缓冲区的颜色
旧颜色:已经在颜色缓冲区的颜色
 
颜色运算法则(不同于向量运算法则)
(r,g,b) * a = (r*a,g*a,b*a)
(r,g,b) * (x,y,z) = (r*x,g*y,b*z)
(r,g,b) + (x,y,z) = (r+x,g+y,b+z)
A - (r,g,b) = (a-x,a-y,a-z)
 
例如
Blend Zero One //仅仅显示背景的颜色,自身的效果不会显示
Blend One Zero //显示贴图的RGB颜色,即使有透明通道的部分也显示原色,不会透过去
Blend One One //贴图色与背景色叠加,没有透明通道处理,结果可能更趋近于(1,1,1)
Blend SrcAlpha Zero //没有透明通道部分显示的是贴图的原色,有透明通道0的部分,显示黑色,0.5部分更趋近于黑色
Blend SrcAlpha OneMinusSrcAlpha //最终颜色 = 新颜色 * 当前透明度 + 旧颜色 * (1 - 当前透明度),最常用的透明混合方式
Shader "Lesson/AlphaTest" {
    Properties {
        _Tex("纹理", 2D) = "white"{}
        _Alpha("透明度", Range(0,1)) = 0
        
    }
    SubShader {
        Pass
        {
            //表示只渲染alpha值大于0.5的部分
            AlphaTest Greater 0.5
            AlphaTest Greater [_Alpha]
            
            //Blend SrcAlpha OneMinusSrcAlpha
            Blend SrcAlpha zero

            SetTexture[_Tex]
            {
                Combine texture
            }
        }
    }
    FallBack "Diffuse"
}
 
Cg语言,详见PPT
 
顶点/片元着色器
核心:
顶点函数:
片元函数:
 
顶点函数在几何阶段,能从应用程序获取顶点信息。这些信息就是通过顶点函数的参数传递进来的。顶点函数的返回值就是传递到片元函数里的,片元函数也是通过参数去接收的
Float4 vertex:顶点坐标(模型空间下)
Float4 normal:顶点的法线向量
Float4 tangent:顶点的切线向量
Float4 texcoord:第一UV颜色
Float4 texcoord1:第二UV颜色
Float4 color:顶点颜色
 
语义:语句的含义
顶点函数的形参后跟的语义:表示该形参的是接收应用程序传递来的是什么。
对于顶点函数的方法后跟的语义:修饰的返回值,代表该返回值表示的是什么。
对于片元函数的方法后跟的语义:修饰的是片元函数的返回值,代表的是告诉应该GPU是什么
 
从应用程序阶段到顶点函数阶段
1.POSITION:表示应用程序把顶点坐标传递过来并且存储在修饰的参数
2.NORMAL:表示法线,通常是float3
3TANGENT:表示切线
4.TEXCOORD0-N:从第1套UV到第7套UV
5.COLOR:顶点颜色
 
从顶点函数到片元函数能表示的语义
1.SV_POSITION:代表转换之后的齐次空间坐标
2.COLOR0:代表一组颜色
2.COLOR1:代表一组颜色
4.TEXCOORD0-N:从第1套UV到第7套UV
 
从片元函数输出的语义
SV_Target:输出的值会渲染到屏幕上
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Lesson/VFColor" {
    Properties {
        _Color("颜色", Color) = (1,0,0,1)
    }
    SubShader {
       
        //1.顶点片元程序也要写在Pass块里
        Pass
        {
            //2.把Cg语言的开始和结束写出来
            //表示Cg语言程序的开始
            CGPROGRAM
            //3.定义顶点函数和片元函数的名字
            //#pragma 不变 vertex 关键字,后跟的是顶点函数的名字,vert顶点函数的名字
            #pragma vertex vert //定义函数名为vert的函数为顶点函数
            //#pragma 不变 fragment 关键字
            #pragma fragment frag //定义函数名为frag的函数为片元函数
            fixed4 _Color;//如果要在Cg语言中去使用属性面板定义的一些变量,需要在Cg语言中进行重定义
            //4.实现顶点函数
            //POSITION修饰的是顶点函数参数vet,证明vet是顶点坐标
            //SV_POSITION修饰的是vet函数的返回值,证明返回值是转换之后的坐标
            float4 vert(float4 vet : POSITION, float3 normal : NORMAL) : SV_POSITION
            {
                //顶点函数的核心作用必须做的是空间坐标转换
                //mul是Cg语言的提供的API,计算向量与矩阵相乘
                float4 position = UnityObjectToClipPos(vet); //
                return position;
            }
            //5.实现片元函数
            fixed4 frag() : SV_Target
            {
                //最重要的必须的做到就是返回一个颜色
                return _Color;
            }
            //表示Cg语言程序的结束
            ENDCG
        }
    }
    FallBack "Diffuse"
}
Unity\Editor\Data\CGIncludes\UnityShaderUtilities.cginc里的UnityObjectToClipPos()函数
UnityCG.cginc常用的API
#ifndef UNITY_SHADER_UTILITIES_INCLUDED
#define UNITY_SHADER_UTILITIES_INCLUDED
// This file is always included in all unity shaders.
#include "UnityShaderVariables.cginc"
// Tranforms position from object to homogenous space
inline float4 UnityObjectToClipPos(in float3 pos)
{
    // More efficient than computing M*VP matrix product
    return mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(pos, 1.0)));
}
inline float4 UnityObjectToClipPos(float4 pos) // overload for float4; avoids "implicit truncation" warning for existing shaders
{
    return UnityObjectToClipPos(pos.xyz);
}
#endif
 
UNITY_MATRIX_MVP的MVP是几何阶段的三次转变
M模型到世界
V世界到观察
P观察到剪裁
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Lesson/VFNormal" {
    Properties {
    }
    SubShader {       
        Pass
        {
            CGPROGRAM
           
            #pragma vertex vert
            #pragma fragment frag
            //定义一个结构体,作为顶点函数的参数
            struct m2v
            {
                float4 vex : POSITION;//告诉应用程序把模型空间下的顶点坐标放在这
                float3 normal : NORMAL;//告诉应用程序把模型空间下的法线放在这
                float3 tangent : TANGENT;//告诉应用程序把模型空间下的切线放在这
            };
            //定义一个结构体,作为顶点函数的返回值和片元函数的参数
            struct v2f
            {
                float4 position : SV_POSITION;//转换之后的顶点坐标
                float3 normal : COLOR0;//法线
                float3 tangent : COLOR1;//切线
            };
            //结构体作为参数和返回值
            v2f vert(m2v v)
            {
                v2f f;
                f.position = UnityObjectToClipPos(v.vex); //必须变换顶点坐标
                f.normal = v.normal;//法线赋值
                f.normal = mul(UNITY_MATRIX_M, v.normal);
                //f.tangent = v.tangent;//切线赋值
                return f;
            }
            fixed4 frag(v2f f) : SV_Target
            {
                return fixed4(f.normal.x, f.normal.y, f.normal.z, 1);//把法线作为颜色输出
                //return fixed4(f.tangent.x, f.tangent.y, f.tangent.z, 1);//把切线作为颜色输出
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

UV坐标,可以通过顶点的UV坐标去获取纹理对应的颜色。对于图片的纹理来说UV的(0,0)点在左下角,UV的(1,1)点在右上角

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Lesson/VFTexture" {
    Properties{
            //定义一个图片
            _MainTex("纹理", 2D) = "white"{}
        }
    SubShader{
        //透明的纹理处理要把渲染队列调高
        Tags{ "Queue" = "Transparent" }
        Pass
        {
            //Cull off
            //处理带有透明通道贴图的混合
            Blend SrcAlpha OneMinusSrcAlpha
       
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //重定义纹理
            sampler2D _MainTex;
       
            //定义结构体,作为顶点函数的参数
            struct m2v
            {
                float4 vex : POSITION;
                float2 uv : TEXCOORD0;//告诉应用程序要UV信息
            };
           
            //定义一个结构体,作为顶点函数的返回值和片元函数的参数
            struct v2f
            {
                float4 position : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
                   
            v2f vert(m2v v)
            {
                v2f f;
                //转换顶点坐标
                f.position = UnityObjectToClipPos(v.vex);
                f.uv = v.uv;
                return f;
            }
               
            fixed4 frag(v2f f) : SV_Target
            {
                //通过顶点的uv坐标去访问纹理对应的颜色
                fixed4 color = tex2D(_MainTex, f.uv);
            //return fixed4(f.uv.x,f.uv.y, 0, 1);
            return color;
            }
        ENDCG
        }
    }
    FallBack "Diffuse"
}
属性面板的变量,如果想在Cg程序中去使用,必须在Cg程序中重新定义:
Color - fixed4或float4
Vector - float4
Float - float
Range - float
2D - sampler2D
Rect - samplerRect
Cube - samplerCube
 
裁剪可以做场景切换的幕布效果
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Lesson/VFDiscard" {
    Properties{
        _MainTex("纹理", 2D) = "white"{}
        _Radius("半径", Range(0, 0.75)) = 0
    }
    SubShader{
        Pass
        {
            CGPROGRAM
           
            #pragma vertex vert
            #pragma fragment frag
           
            sampler2D _MainTex;
            float _Radius;
           
            struct m2v
            {
                float4 vex : POSITION;
                float2 uv : TEXCOORD0;
            };
           
            struct v2f
            {
                float4 position : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
           
            v2f vert(m2v v)
            {
                v2f f;
                f.position = UnityObjectToClipPos(v.vex);
                f.uv = v.uv;
                return f;
            }
           
            fixed4 frag(v2f f) : SV_Target
            {
                //discard;//裁剪命令
                fixed4 color = tex2D(_MainTex, f.uv);
           
                //0.2圆的半径
                //圆心是0.5 0.5
                float2 current = f.uv;
                float2 center = float2(0.5, 0.5);
               
                float dis = pow((current.x - center.x), 2) + pow((current.y - center.y), 2);
           
                if (dis < pow(_Radius, 2))
                {
                    //在圆内
                    discard;
                }
               
                return color;
            }
        ENDCG
        }
    }
        FallBack "Diffuse"
}
 
Emission,类似RawImage的UV Rect
----Tiling:图片的左右偏移
----Offset:图片的大小比例
 
练习 - 实现西瓜的效果
Shader "Lesson/VFWatermelon" {
    Properties {
        _LightColor("浅色条纹", Color) = (1,1,1,1)
        _DarkColor("深色条纹", Color) = (1,1,1,1)
        _Number("深色条纹数量", int) = 3
        _Width("深色条纹宽度", Range(0.01, 0.2)) = 0.02
    }
    SubShader{
        Pass
        {
            CGPROGRAM
                  
            fixed4 _LightColor;
            fixed4 _DarkColor;
            int _Number;
            float _Width;
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
           
            struct m2v
            {
                float4 vex : POSITION;
                float3 uv : TEXCOORD0;
            };
           
            struct v2f
            {
                float4 position : SV_POSITION;
                float3 uv : TEXCOORD0;
            };
           
            v2f vert(m2v v)
            {
                v2f f;
                f.position = UnityObjectToClipPos(v.vex);
                f.uv = v.uv;
                return f;
            }
           
            fixed4 frag(v2f f) : SV_Target
            {
                //实现1
                //浅色条纹的宽度
                float width = 1.0 / _Number - _Width;
                for (int i = 0; i < _Number; i++)
                {
                    if (f.uv.x > i * (width + _Width) && f.uv.x < width + i * (width + _Width))
                    {
                        return _DarkColor;
                    }
                }
                return _LightColor;
                /*
                //实现2
                //每对条纹的宽度(1深1浅)
                float wid = 1.0 / _Number;
                float x = fmod(f.uv.x, wid); //对wid取模(余)
                if (x < _Width)
                {
                    return _DarkColor;
                }
                return _LightColor;
                */
            }
       
            ENDCG
        }
    }
    FallBack "Diffuse"
}

猜你喜欢

转载自www.cnblogs.com/ciaowoo/p/10363723.html