Shader 基础使用(三) ----- vertex & fragment

本文介绍了Unity中Shader的基础使用,包括顶点语义绑定如POSITION、NORMAL、TEXCOORD等,以及常用的函数库如HLSLSupport.cginc、UnityShaderVariables.cginc等。通过示例展示了如何编写实现纯色和彩色效果的顶点片段着色器,逐步讲解了漫反射的实现。适合Shader初学者入门。

基本数据类型与surface一致,就不在此文章赘述了
顶点语义绑定

float4 POSITION 顶点坐标位置
float3 NORMAL 顶点法线向量坐标
float4 TEXCOORD0 第一个UV坐标
float4 TEXCOORD1..N 第二个到第N个UV坐标
float4 TENGENT 顶点切线向量坐标
float4 COLOR 顶点颜色值

常用函数库

HLSLSupport.cginc 辅助为跨平台的着色器编译宏和定义
UnityShaderVariables.cginc 常⽤用全局变量量
UnityCG.cginc 常⽤用辅助函数
AutoLight.cginc 光、影函数
Lighting.cginc 光照模型相关
TerrainEngine.cginc 地形植被辅助

首先我们应该知道顶点片段着色器的基本框架

Shader "MyVFShader/VFShader_001" 
{
    Properties
    {
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
                //预编译指令关键词  |  函数类型  |  函数名
                #pragma vertex vert  //vertex 是顶点着色器
                #pragma fragment frag // fragment 是片段着色器
                void vert(){}
                void frag(){}
            ENDCG
        }
    }
}

接下来先来用顶点片段着色器写一个纯色的Shader

Shader "MyVFShader/VFShader_002" 
{
    Properties
    {
        _MainColor("颜色",Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
                //预编译指令关键词  |  函数类型  |  函数名
                #pragma vertex vert  //vertex 是顶点着色器
                #pragma fragment frag // fragment 是片段着色器
                //输入一个顶点坐标 名称vertexPos 语义绑定POSITION
                //输出一个像素坐标 语义绑定SV_POSITION
                float4 vert(float4 vertexPos:POSITION):SV_POSITION
                {
                    //老版本写法(Model View Project矩阵变幻,得到每个像素的坐标位置)
                    return UnityObjectToClipPos(vertexPos);
                    //新版本写法UnityObjectToClipPos(顶点坐标)
                    return UnityObjectToClipPos(vertexPos);
                }
                float4 _MainColor;
                //无输入 输出内插值颜色
                float4 frag():COLOR
                {
                    return _MainColor;
                }
            ENDCG
        }
    }
}

/*
我们来说一下步骤和思路 做一个总结

首先看顶点函数
1.参数 --> 每个顶点的坐标位置 语义绑定是POSITION 类型是float4
2.返回值 --> 每个顶点的像素位置 语义绑定是SV_POSITION 类型是float4
3.顶点函数的作用:就是将三维空间坐标投影到二维窗口
然后看片段函数
1.参数 --> 片段函数没有参数
2.返回值 --> 片段的颜色值 语义绑定COLOR 类型是float4
3.片段函数的作用:就是给片段颜色赋值,也就是设置片段颜色
*/

如果感觉纯色的太局限了 我们来写一下彩色的看看效果

Shader "MyVFShader/VFShader_003" 
{
    Properties
    {
        //_ColorOffset("颜色偏移量",Range(0,1)) = 0.5
        _ROffset("红色偏移量",Range(0,1)) = 0
        _GOffset("绿色偏移量",Range(0,1)) = 0
        _BOffset("蓝色偏移量",Range(0,1)) = 0
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
                //预编译指令关键词  |  函数类型  |  函数名
                #pragma vertex vert  //vertex 是顶点着色器
                #pragma fragment frag // fragment 是片段着色器
                //顶点输出的结构体
                struct V2F 
                {
                    //像素坐标
                    float4 position:POSITION;
                    //0级纹理坐标(可以理解为像素的颜色)
                    float4 color:TEXCOORD0;
                };

                float _ROffset;
                float _GOffset;
                float _BOffset;
                //顶点函数
                //输入一个顶点坐标 名称vertexPos 语义绑定POSITION
                V2F vert(float4 vertexPos:POSITION)
                {
                    //声明结构体
                    V2F v2f;
                    //通过顶点坐标求像素坐标
                    v2f.position = UnityObjectToClipPos(vertexPos);
                    //顶点坐标当做颜色值设置成像素颜色
                    //通过红,绿,蓝三个颜色的偏移量来修改颜色的变化
                    v2f.color = vertexPos + float4(_ROffset,_GOffset,_BOffset,0);
                    //返回
                    return v2f;
                }   
                //片段函数
                float4 frag(V2F v2f):COLOR
                {
                    return v2f.color;
                }
            ENDCG
        }
    }
}


/*
我们来说一下步骤和思路 做一个总结

顶点着⾊色器器输出结构体
1.float4 postion:SV_POSITION 空间位置 
2.float4 color:TEXCOORD0 0级纹理理坐标
首先看顶点函数
1.参数 --> 每个顶点的坐标位置 语义绑定是POSITION 类型是float4
2.返回值 --> 输出结构体
3.顶点函数的作用:将三维空间坐标投影到⼆维口,颜⾊值设置为顶点坐标+偏移量(营造彩虹效果)
然后看片段函数
1.参数 --> 顶点着⾊器输出结构体 
2.返回值 --> 片段的颜色值 语义绑定COLOR 类型是float4
3.片段函数的作用:直接将顶点输出的颜色设置到片段显示
*/

由浅至深的 接下来 我们看一下顶点片段着色器的漫反射应该怎样实现

Shader "MyVFShader/VFShader_004" 
{
    Properties
    {
        _Color("颜色",Color) = (1,0,0,1)
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
                #pragma vertex ver
                #pragma fragment frag
                //引用库
                #include "UnityCG.cginc"
                //声明外部颜色变量
                float4 _Color;
                //声明内部光照颜色变量
                float4 _LightColor0;
                //顶点函数输入结构体
                struct appData
                {
                    //顶点坐标
                    float4 vertexPos:POSITION;
                    //顶点法线
                    float3 normal:NORMAL;
                };

                struct V2F
                {
                    //像素坐标
                    float4 position:SV_POSITION;
                    //像素法线
                    float3 normal:NORMAL;
                };
                //顶点函数
                V2F ver(appData data)
                {
                    //定义输出结构体
                    V2F v2f;
                    //坐标系转换
                    v2f.position = UnityObjectToClipPos(data.vertexPos);
                    //从顶点法线 到 像素法线
                    v2f.normal = mul(float4(data.normal,0),unity_WorldToObject).xyz;
                    //返回
                    return v2f;
                }
                //片段函数
                float4 frag(V2F v2f):COLOR
                {
                    //求法线的单位向量
                    float3 v2fnormal = normalize(v2f.normal);
                    //求入射光的单位向量 _WorldSpaceLightPos0内部函数
                    float3 lnormal = normalize(_WorldSpaceLightPos0.xyz);
                    //逆向光公式:Diffuse=LightColor * MainColor * max(0,dot(N,L)) 
                    //正向光公式:Diffuse=LightColor * MainColor * -min(0,dot(N,L))
                    float3 diffuse = _LightColor0 * _Color * -min(0,dot(v2fnormal,lnormal));
                    //添加环境光
                    float4 newDiffuse = float4(diffuse,0) + UNITY_LIGHTMODEL_AMBIENT;
                    //返回颜色值
                    return newDiffuse;
                }
            ENDCG
        }
    }

    FallBack "Diffuse"
}


/*
我们来说一下步骤和思路 做一个总结

第一步
1.引入库 #include “UnityCG.cginc”
顶点着色器输入结构体
1.顶点位置 语义绑定POSITION  类型float4
2.法线 语义绑定NORMAL 类型float3
顶点着⾊器输出结构体
1.像素位置 语义绑定SV_POSITION 类型float4 
2.法线 语义绑定NORMAL 类型float3
全局变量声明
1.光照颜色 内部值 _LightColor0 类型float4
2.漫反射颜色 属性值  自己定义
首先看顶点函数
1.参数 --> 输入结构体
2.返回值 --> 输出结构体
3.步骤:
    1.矩阵变幻
    2.计算法线
        1).输入法线扩充 : float4(input.normal, 0.0) 
        2).内部值 : unity_WorldToObject 
        3).法线计算 : mul(float4(input.normal, 0.0), unity_WorldToObject).xyz
然后看片段函数
1.参数 --> 顶点着⾊器输出结构体 
2.返回值 --> 片段的颜色值 语义绑定COLOR 类型是float4
3.步骤:
    1.获取输入法线方向(float3) normalize(input.normal)
    2.获取入射光法线方向(float3)normalize(_WorldSpaceLightPos0.xyz)
    3.计算漫反射值
        1).逆向光公式:Diffuse=LightColor * MainColor * max(0,dot(N,L)) 
        2).正向光公式:Diffuse=LightColor * MainColor * -min(0,dot(N,L))
           i).LightColor 光照颜⾊色 
           ii).MainColor 漫反射颜⾊色 
           iii).N 输⼊入法线
           iiii).L 光照法线
    4.合并环境光
        1).漫反射扩充 float4(diffuse, 1.0) 
        2).添加环境光 + UNITY_LIGHTMODEL_AMBIENT
    5.返回结果 片段颜色
*/

Shader就先介绍这么多了,感谢大家的支持, 如果有人想要深入的研究,可以给我评论留言,我们一起讨论研究!!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值