Unity Shader 学习 001-Shader基础

学习目标:

001-shader基础

学习时间:

2022.5.27

学习产出:

1.什么是Shader?

shader通俗理解来说就是shader代码,在Unity里面我们通过shader代码来控制渲染的效果
Unity里面的shader代码叫做shaderlab
当我们在Unity中创建一个Shader时(Surface Shader / Vertex&Fragment Shader),会生成一个 .shader 的文件,打开这个文件时可以看到其内容由一堆代码组成,这堆代码就是控制着我们的渲染效果

2.如何创建Shader代码

在这里插入图片描述

3.Shader代码参数

我们的shader是赋值给Material的
我们在shader里面设置的参数,都会在Material的面板里面进行显示
我们设置参数的意义,就在于与外界交互,比如说下面的shader
我可以随意修改其参数面板来达到不同的渲染效果
这个修改的过程可以是手动改,也可以是通过代码来控制

在这里插入图片描述
对应属性块代码一一对应,发现这些参数的设置还是很有规律的
比如Int类型在参数面板就是一个int输入框
Range类型在参数面板是一个slider
Vector类型在参数面板是一个Vector4

   //属性块
    Properties
    {
    
    
        _Int("Int",int) = 2
        _Float("Float",float)=1.5
        _Range("Range",range(0.0,2.0))=1.5
        _Color("Color",Color)=(1,1,1,1)
        _Vector("Vector",Vector)=(1,4,3,8)
        _MainTex ("Texture", 2D) = "red" {
    
    }  //2d图片 贴图
        //CubeMap就是天空盒 我们在这里用一个CubeMap肯定比用六张2d贴图更节省操作,空间
        _Cube("Cube",Cube) = "white"{
    
    }        
        _3D("3D",3D) = "black"{
    
    }     //3D是和CubeMap类似的  不常用
    }

在这里插入图片描述

4.Shader标签

在这里插入图片描述
我们的Shader标签,就是在子着色器SubShader里面的
这也就意味着,这些标签只对这这一个子着色器产生影响,对这个子着色器内部的所有通道产生影响
同样的,我们可以将Shader标签放在一个通道里面,表示只对这一个通道产生影响

但是内外都定义了同一个Tags 走的还是外面的Tags

//标签   可选  key=value
        Tags 
        {
    
     
            "Queue"="Transparent"   //渲染顺序
            "RenderType"="Opaque"   //渲染类型 着色器替换功能  
            //比如说C#代码在渲染完成之后可以根据渲染类型 更换shader
            //比如将全部渲染类型为透明的 换为 渲染类型不透明的Shader
            "DisableBatching"="True"   //是否进行合批
            "ForceNoShadowCasting"="True"   //是否投射阴影
            //projector是unity里面做阴影的一个东西
            "IgnoreProjector"="True"     //受不受Projector的影响 通常用于透明物体 
            //比如透明物体肯定不想受阴影影响
            "CanUseSpriteAltas"="False" //是否是用于图片的Shader,通常用于UI
            "PreviewType"="Plane"      //用于shader面板预览的属性  不设定的话就是一个3d的球形状
        }
        //下面所有Pass都使用这个Tags  但是我们也可以在Pass通道里面进行  
        //但是内外都定义了同一个Tags  走的还是外面的Tags

5.Render渲染设置 剪裁 深度检测 深度写入 混合 LOD

这些都是关于Shader渲染过程的一些参数设置

        //Render渲染设置  可选

        //裁剪 旋转切除掉的面
        //off是裁剪关闭让正反两面都渲染 Back是切掉背面渲染前面  front是切掉前面切掉背面
        // Cull off/back/front    

        //深度测试 Z轴 应为屏幕是二维坐标 深度这个概念是在Z轴上的
        //比如LEqual 就是less or equal(小于等于)就代表通过深度测试
        // ZTest Always/Less Greater/LEqual/GEqual/Equal/NotEqual

        //深度写入
        // Zwrite off/on

        //混合 融合 Src源 Dst目标
        //Blend SrcFactor DstFactor  

        //LOD 不同情况下使用不同的LOD,达到图像性能提升 LOD越大 需要性能越强
        //一般手机端可以设置为50   PC设置为100
        LOD 100
        //下面所有Pass都使用这个渲染设置  但是我们也可以在Pass通道里面进行  
        //但是内外都定义了同一个渲染设置  走的还是外面的渲染设置

6.Pass通道 顶点 片元 着色器

我们现在对这段Pass内部的代码进行分析

Pass
        {
    
    
            Tags
            {
    
    
                  "LightMode"="ForwardBase" 
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
    
    
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }

1.建议不要多个Pass通道 多一个Pass就是多一个DrawCall 但是一个SubShader必须有一个Pass

当我们在另外的Shader文件里面需要使用当前的shader文件的Pass
直接通过 Use 路径加Name就可以实现 Tips:Use Pass通道的时候 要对名字用全大写
Name “Default” //Pass通道名称
Tags{} 可以在每个Pass通道里面进行定义

2.我们可以设置单独的Pass通道内的Tag

			Tags
            {
    
    
                  //光照模型(渲染方式) ForwardBase前向渲染
                  //定义该Pass通道在Unity渲染流水中的角色
                  "LightMode"="ForwardBase" 
                  //"RequireOptions"="SoftVegetation SoftVegetation2" //满足某些条件时才渲染该Pass通道    条件1  条件2 条件3 
            }

3.Pass内部的代码从 CGPROGRAM 开始 ENDCG 结束

在CGPROGRAM 下面
也就是刚开始的时候我们得指定vertex(顶点着色器)的函数名 和 fragment(片元着色器)的函数名
这里,我指定顶点着色器的函数名为vert,我们在下面写vert这个函数的时候,编辑器就会将其作为顶点着色器函数
同样,frag在这里指定为片元着色器

			#pragma vertex vert
            #pragma fragment frag

4.在这里,我们可以引用对应编辑器版本的Shader库,这些都是写好的内容,我们可以直接引用,避免反复造轮子

#include "UnityCG.cginc"

这里就引用了"UnityCG.cginc"这里面的东西

5.我们现在对shader里面的结构体进行分析

			struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

比如说,这里我们将原语POSITION,模型坐标赋值给参数vertex
将原语TEXCOORD0(第一个贴图)赋值给uv

6.Pass内部的变量
我们定义在Pass内部的变量

			sampler2D _MainTex;
            float4 _MainTex_ST;

7.顶点着色器
我们在前面定义了vert为顶点着色器的函数名
在这里我们将appdate这个结构体的变量作为参数传入
将v2f这个结构体的变量作为返回
在内部,我们实例化一个v2f结构体,对其的vertex值进行修改
也就是对原语POSITION进行修改

 			v2f vert (appdata v)
            {
    
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

这里返回的v2f就是计算完成后的顶点信息

8.片元着色器
在这里,我们将v2f作为参数,返回一个fixed4颜色值
这个颜色值就是通过片元着色器计算出来的当前像素的颜色值
这里我们根据tex2D()对我们之前定义的变量_MainTex根据uv进行采样
由于,我们前面定义参数的时候,默认它是一张红色的贴图,
在这里插入图片描述

所以整个模型,都会是红色
因为每个像素点取样得到的颜色,都为红色

如果我们修改了_MainTex,那么采样结果肯定也会被修改

			fixed4 frag (v2f i) : SV_Target
            {
    
    
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }

在这里插入图片描述

7.UnityShader库

这是Unity自带的Shader库,每一个版本都不一样,我们可以在官网进行下载我们当前编辑器版本的Shader库
在这里插入图片描述
我们下载下来之后,就可以看到有很多写到的库函数,我们只需要引用就可以了

比如说之前代码里面引用的库
在这里插入图片描述
内部实际上定义了很多语句
可以类似理解为C#的命名空间,我们只有引入命名空间,才能使用里面的语句函数等
也可类似理解为C语言的头文件

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_48781656/article/details/122865253