Unity Shader学习笔记——基本结构

Unity提供了5种Unity Shader的模板供我们选择:

        Standard Surface Shader:会产生一个包含了标准光照模型的表面着色器模板。

        Unlit Shader:会产生一个不包含光照(但包含雾效)的基本的顶点/片元着色器。

        Image Effect Shader:为我们实现各种屏幕后处理效果提供了一个基本模板。

        Compute Shader:会产生一种特殊的Shader文件,这类Shader旨在利用GPU的并行性来进行一些与常规渲染流水线无关的计算。

        Ray Tracing Shader:会创建一个光线追踪着色器。


        一个Unity Shader的基础结构如下所示:

Shader "ShaderName"
{
    Properties
    {
        //所需的各种属性
    }
    SubShader
    {   
        //显卡A使用的子着色器
        //真正意义上的Shader代码会出现在这里
        //表面着色器(Surface Shader)或者
        //顶点/片元着色器(Vertex/Fragment Shader)或者
        //固定函数着色器(Fixed Function Shader)
    }
    SubShader
    {   
        //显卡B使用的子着色器
        //和上一个SubShader类似 
    }
    Fallback "VertexLit"
}

        通过代码第一行的shadername可以在Unity窗口中找到对应的shader材质,如:

Shader "Unlit/FirstShader"


         Properties语义块中包含了一系列属性,这些属性将会出现在材质面板中:

    Properties
    {
        Name("display name", PropertyType) = DefaultValue
        Name("display name", PropertyType) = DefaultValue
    }

         Name是每个属性的名字,在Unity中这些属性的名字通常由一个下划线开始。

        displayname是显示的名称,就是出现在材质面板上的名字。

        PropertyType就是属性类型。除此之外,我们还需要为每个属性制定一个默认值,即DefaultValue。

         下面代码给出了一个展示所有属性类型的例子:

    Properties
    {
        //Name("display name", PropertyType) = DefaultValue
        _Int("Int", Int) = 1
        _Float("Float",Float) = 1.5
        _Range("Range",Range(0.0, 5.0)) = 3.0

        _Color("Color",Color) = (1, 1, 1, 1)
        _Vector("Vector",Vector) = (2, 3, 6, 1)

        _2D("2D",2D) = ""{}
        _Cube ("Cube",Cube) = "white" {}
        _3D("3D",3D) = "black"{}
    }

        然后我们就可以在材质面板中看到对应的显示:


         SubShader语义块:每一个Unity Shader文件可以包含多个SubShader,但最少要有一个。当Unity需要加载这个Unity Shader的时候,会扫描所有的SubShader然后选择第一个能够在目标平台上运行的,如果都不支持的话,就会使用Fallback语义指定的Unity Shader。

        这种语义的主要功能就是在不同显卡上显示不同的画面,在旧的显卡上使用计算复杂度较低的着色器,而再高级显卡上使用计算复杂度较高的着色器,以便提供更出色的画面。

SubShader
    {
        //可选的
        [Tags]
        
        //可选的
        [RenderSetup]

        Pass
        {
            //Other Passes
        }
}

        SubShader中定义了一系列Pass以及可选的状态(RenderSetup)和标签(Tags)设置。每个Pass定义了一次完整的渲染流程,但是如果Pass数目过多会造成渲染性能的下降。

        状态设置:设置之后会应用到所有的Pass,如果想要单独渲染的话可以在Pass语义块中单独进行上面的设置。

         标签:标签是一个键值对,它的键和值都是字符串类型。这些键值对是SubShader和渲染引擎之间沟通的桥梁,它告诉Unity渲染引擎该怎么样以及何时渲染这个对象。标签只可以在SubShader中实现,而不可以在Pass块中声明。

 Tags    { "TagName1" = "Value1" "TagName2" = "Value2"}


        Pass语义块:

Pass
{
    [Name]
    //此处的Tags和上面SubShader的Tags是不一样的
    [Tags]
    [RenderSetup]
    //Other code
}

        我们可以定义该Pass的名称,然后通过这个名称在其他Unity Shader中调用Pass。

//声明Pass名称
Name "MyPassName"

//在其他Unity Shader中调用
UsePass "FirstShader/MYPASSNAME"


        Fallback指令:它用于告诉Unity如果上述所有的SubShader在这块显卡上都无法运行,那就使用这个最低级的Shader吧。它还会影响阴影的投射,Fallback使用的内置Shader中包含了这样一个通用的Pass。

//调用最低级的Unity Shader的名字
Fallback "name"
//或者关闭Fallback,即使跑不了所有的SubShader也不管他
Fallback Off

Pass
{
    //嵌套CG/HLSL语言
	CGPROGRAM
    //指定顶点阶段函数为vert
	#pragma vertex vert
    //指定片元阶段函数为frag
	#pragma fragment frag
 
    //引入Unity中的函数库
	#include "UnityCG.cginc"
 
    //顶点阶段输入的信息,这里指定了输入的有顶点的位置信息
	struct appdata
	{
        //可以把 float4 理解为一个长度等于4的 float 数组,用 xyzw 或者 rgba 来取它的每一个元素值
        //POSITION 是这个字段的语义,它的意思是指明这个字段传入的是顶点位置信息。
		float4 vertex : POSITION;
	};
 
    //是片元阶段输入的信息,也是顶点阶段输出的信息
	struct v2f
	{
        //SV_POSITION 指定了顶点的位置是经过顶点坐标空间变换过的,直接进行光栅化处理。
		float4 vertex : SV_POSITION;
	};
 
    //这个声明通常和Properties语句块里的属性相对应
	float4 _TintColor;
 
    //vert函数输入的是appdata结构体,输出的是v2f结构体,这里个函数里只做了一件事,就是转换顶点空间并返回。
	v2f vert(appdata v)
	{
		v2f o;
		o.vertex = UnityObjectToClipPos(v.vertex);
		return o;
	}
 
    //frag函数输入的是v2f结构体,输出的是一个颜色值,这个颜色值是我们在Properties里声明的。
	float4 frag(v2f i) : SV_Target
	{
		return _TintColor;
	}
	ENDCG
}

猜你喜欢

转载自blog.csdn.net/weixin_45081191/article/details/129164954