• 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"
    }
    UnityEditorDataCGIncludesUnityShaderUtilities.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"
    }
  • 相关阅读:
    左滑删除 --- 自定义组件(优化)
    扩展方法
    关于Windows服务中的一点小记录
    MySQL数据库方面
    反射初探
    FireDAC读取数据Delphi
    Delphi学习之 FireDAC
    向ComboBox列表框中添加Enum的全部数据
    怎样在VC中生成一个DLL
    AutoCAD 开发备注
  • 原文地址:https://www.cnblogs.com/vuciao/p/10363723.html
Copyright © 2020-2023  润新知