简单的顶点/片元着色器

导读

(1)材质Material与着色器Shader之间的关系:

  • 每种材质在创建时都必须指明其具体渲染管线下的具体着色器类型
  • Shader的效果需要通过使用该着色器的Material来体现,而Material的效果则通过使用该材质的模型体现。
  • 无材质就无法渲染模型。

(2)Unity Shader与传统Shader的区别:

  • 传统Shader编写时只能编写特定类型的着色器,例如顶点着色器,片元着色器。
  • Unity Shader文件中可以包含多种类型的着色器,即包含多种类型的着色器代码,使开发人员能够同时控制GPU渲染流水线中的多个子阶段

(3)Unity Shader的概述:
在Unity中通过ShaderLab语言所编写的Unity Shader文件并不是真正的Shader,Unity引擎会自动将其编译成真正的Shader代码文件而开发人员无需关心,只需要关心使用ShaderLab语言编写Unity Shader即可!

简单的顶点/片元着色器

Unity Shader的基本结构:

包括:

  • Shader路径名
  • Properties语义块:
    ------用于声明使用该Shader的材质在材质控制面板所需显示的属性列表!
  • SubShader语义块:
    ------为了兼容不同显卡的处理能力,为显卡提供多种解决(执行)方案从而进行多选一执行!
  • Fallback指令:
    在这里插入图片描述

简单示例1及解析

Shader "Unlit/001"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
        SubShader
    {
        Tags { "RenderType" = "Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            //定义顶点着色器和片元着色器的函数名称为vert和frag
            #pragma vertex vert
            #pragma fragment frag
            //POSITION 和SV_POSITION是CG中的语义,表明v参数(四维向量)是顶点位置信息,vert函数的输出是裁剪空间里的顶点信息
            //参数v的输入并没有手动输入,在unity中反而有数据来源!由Unity自动完成!
           float4 vert(float4 v:POSITION) :SV_POSITION
           {
                return UnityObjectToClipPos(v);
           }
            //SV_TARGET表示告诉渲染器,把用户的输出颜色存储到一个渲染目标(render target) 中,这里将输出到默认的帧缓存中!
           fixed4 frag() : SV_TARGET
           {
               return fixed4(0,0,0,1);
           }
            ENDCG
        }
    }
}

CG代码块中的两条编译指令:

声明有关顶点着色器的函数vert与有关片元着色器的函数frag

#pragma vertex vert //顶点着色器函数
#pragma fragment frag //片元着色器函数
有关顶点着色器:
  • 一个最基本的顶点着色器必须完成的任务:将顶点由原始的模型空间转换到齐次裁剪空间。其经过模型变换,观察变换,投影过程,从而历经模型空间----世界空间----观察空间----齐次裁剪空间。

通过UnityObjectToClipPos()函数实现将顶点由模型空间转换到齐次裁剪空间。

//顶点着色器函数是逐顶点执行
//POSITION语义表示将模型顶点位置信息作为输入
//SV_POSITION语义表示将齐次裁剪空间下的顶点位置信息作为输出
float4 vert(float4 v:POSITION) :SV_POSITION
    {
     return UnityObjectToClipPos(v);
     //return mul(UNITY_MATRIX_MVP,v);旧版本
    }
  • 顶点着色器的处理单位是顶点,每输入一个顶点都将单独调用一次顶点着色器。顶点着色器本身不可创建和销毁顶点,也无法得到顶点与顶点之间的关系
有关片元着色器:
  • 计算每个片元的颜色信息
//SV_TARGET语义表示告诉渲染器,把输出的颜色值存储到渲染目标(render target) 中,这里将输出到默认的帧缓存中!
fixed4 frag() : SV_TARGET
     {
      return fixed4(0,0,0,1);
     }

简单示例2及解析:

使用结构体实现多值输入输出

Shader "Unlit/002"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color("Color",Color) = (1,1,1,1)
    }
        SubShader
        {
            Tags { "RenderType" = "Opaque" }
            LOD 100

            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                
//对于Properties语义块中定义的属性只有在SubShader的CG代码块中再次重复声明该变量才有效,才能将其值传递到CG代码块中!
                fixed4 _Color;
                
            //在Unity Shader中没有类,只能使用结构体!
            //顶点着色器的输入结构体
            //a2v的含义application to vert shader
            struct a2v
            {
                float4 vertex:POSITION;//用模型顶点填充vertex变量
                float3 normal:NORMAL;//用模型的法线填充normal变量
                //用模型的第一套uv填充
                float4 texcoord:TEXCOORD0;texcoord
            };
            
            //顶点着色器的输出结构体
            //v2f表示vert to fragment shader
            //顶点着色器的输出结构中, 必须包含一个绑定SV_POSITION语义的变量。否则,渲染器将无法得到裁剪空间中的顶点坐标,也就无法把顶点渲染到屏幕上。
            struct v2f 
            {
                float4 pos:SV_POSITION;
                fixed3 color : COLOR0;
            };
            v2f vert(a2v v) 
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                //将-1~1范围转变到0~1的范围
                o.color = v.normal * 0.5 + fixed3(0.5,0.5,0.5);
                return o;
            }

            fixed4 frag(v2f i) : SV_TARGET
            {
                fixed3 color = i.color;
//对于颜色这种三/四维向量,想访问其分量则直接.x/y/z=fixed1类型进行访问!以及.xyzw=fixed4类型或者.rgba或者.xy=fixed2类型等访问部分数据。
                color *= _Color.rgb;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}
特别注意:
顶点着色器与片元着色器的调用

顶点着色器是逐顶点调用的, 而片元着色器是逐片元调用的。 片元着色器中的输入实际上是把顶点着色器的输出进行插值后得到的结果。

Shader Lab中属性的类型和CG中变揽的类型之间的匹配关系:

在这里插入图片描述

CG语言的语义

Cg 语言中,通过引入语义绑定机制,将输入/输出数据和寄存器做一个映射关系(在 OpenGL Cg profiles 中是这样的,但在 DirectX-based Cg profiles 中则并没有这种映射关系)。

根据输入语义,图形处理器从某个寄存器取数据:

  • 输入含义通过语义获取相应的数据,用作输入!
  • 通过POSITION顶点位置, TANGENT顶点切线, NORMAL顶点法线,COLOR顶点颜色,TEXCOORDn纹理坐标等语义获取模型的顶点数据,而这些顶点数据是由使用包含该Shader的材质的模型的Mesh Render组件提供!

根据输出语义,再将处理好的数据,放到指定的寄存器:

  • 输出含义指明数据的去处,用作输出!
  • SV_POSITION语义表示将齐次裁剪空间下的顶点位置信息作为顶点着色器的输出,输入给渲染流水线的下一个子阶段。
    SV_TARGET语义表示告诉渲染器,把输出的颜色值存储到渲染目标(render target) 中。

故语义是具有输入语义和输出语义的区别。虽然在旧版本中一些参数经常会使用相同的绑定语义词,例如:顶点 Shader 的输入参数,使用POSITION语义 指应用程序传入的顶点位置信息,而输出参数使用 POSITION 语义就表示要反馈给硬件光栅器的裁剪空间位置。虽然两个语义都命名为 POSITION ,但却对应着图形流水线上不同的寄存器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值