Unity Shader 入门(零基础到敢上手敲Shader)

目录

 创建Shader

一.Standard Surface Shader

二.Unlit Shader

三.Image Effect Shader

四.Compute Shader

五.Ray Tracing Shader

着色器语言

Shader默认代码格式和一些常用API讲解


 创建Shader

一.Standard Surface Shader

标准表面着色器,它是一种基于物理的着色系统,可以理解为 它是通过对物理现象的简单模拟,可以实现生活中各种物品的效果,比如石头、木材、玻璃、塑料和金属等等。

二.Unlit Shader

它是最简单的着色器,与 Standard Surface Shader 相比,它去除了冗长的光照公式以及阴影解算,因此得名 Unlit,翻译过来就是无光照,也正因如此,它只由最基础的 Vertex Shader 和 Fragment Shader 组成,最为基础易懂。

三.Image Effect Shader

它其实也是也是顶点片元着色器,不过它主要针对实现各种屏幕后处理效果,那后处理是什么呢?一般像是泛光、调色、景深、模糊等基于最终整个屏幕画面而进行再次处理的就是后处理,这里做个简单的了解即可。

四.Compute Shader

计算着色器,它是在GPU中运行的一段程序,独立于常规渲染管线之外的,它可以直接将GPU作为并行处理器加以利用,从而使GPU不仅具有3D渲染能力,还具有其他的运算能力。一般会在需要大量并行计算的时候使用。

五.Ray Tracing Shader

光线追踪着色器,光线追踪是指从摄像机出发的若干条光线,每条光线会和场景里的物体求交,根据交点位置获取表面的材质、纹理等信息,并结合光源信息计算光照。相对于传统的光栅化渲染,光线追踪可以轻松模拟各种光学效果,如反射、折射、散射、色散等。但由于在进行求交计算时需要知道整个场景的信息,它的计算成本也是非常高的。

着色器语言

Unity为我们封装的着色器语言,而目前主流的着色器语言有3种,基于OpenGL的GLSL / 基于DX的HLSL / NVIDIA公司的CG。

GLSL与HLSL分别是基于OpenGL和Direct3D的接口,两者不能混用。而CG则是为了使图形硬件的编程变得和 C语言编程一样方便自由,它本身基于C语言。如果你之前使用过C系语言其中的任意一个,那CG的语法也是比较容易掌握的。但其实由于Microsoft和NVIDIA的相互协作,他们在标准硬件光照语言的语法和语义上达成了一致,所以HLSL和Cg其实可以看为是同一种语言。

而ShaderLab则是Unity在HLSL和CG的基础之上封装的只属于Unity的着色器语言,它的灵活性更高,而且不再需要将 Shader 的配置 硬写在引擎代码中,本质是在底层着色语言的基础上,额外提供了声明信息,以数据驱动的方式使我们在渲染管线内自由发挥。

GLSL(OpenGL):跨平台、没有提供着色器编译器、依靠显卡驱动完成编译工作、不同显卡不同驱动编译效果不同。
HLSL(DirectX):微软提供着色器编译器、不同硬件效果相同但是只限windows、xbox等。
CG:真正意义跨平台、微软NVIDIA合作,根据不同平台编译成相应的中间语言。

Shader默认代码格式

拿 Unlit Shader举例子

// Shader 的路径名称  默认为文件名,也可以与文件名不同
Shader "Unlit/TestShader"
{    
    // 属性 
    // Material Inspector显示的所有参数都在需要在这里进行声明
    Properties
    {
        // 通常所有属性名都以下划线字符开头 _MainTex
        _MainTex ("Texture", 2D) = "white" {}
    }
    // 子着色器 
    // 一个Shader至少有一个或者多个子着色器SubShader,这些子着色器互不干扰,且只有一个会运行
    // 在加载shader时Unity会遍历所有SubShader列表,并最终选择用户机器支持的第一个
    SubShader
    {
        // 可以通过Tags来向子着色器分配标签
        // 只可以写在SubShader语块内,不可写在Pass内
        // 以键值对的形式存在,可以出现多个键值对
        Tags { "RenderType"="Opaque" }
        // RenderPipeline: 声明子着色器是否与通用渲染管线 (URP) 或高清渲染管线 (HDRP) 兼容
        // 仅与 URP 兼容
        // Tags { "RenderPipeline"="UniversalRenderPipeline" }
        // 仅与 HDRP 兼容
        // Tags { "RenderPipeline"="HighDefinitionRenderPipeline" }
        // RenderPipeline不声明或任何其他值表示与 URP 和 HDRP 不兼容
        LOD 100
        // 每个子着色器由多个通道组成,许多简单的着色器只使用一个通道,但想要一些更复杂的效果,着色器可能需要更多通道
        // 一个Pass就是一次绘制,可以看成是一个Draw Call而Pass的意义在于多次渲染,
        // 如果你有一个Pass,那么着色器只会被调用一次,如果你有多个Pass的话,
        // 那么就相当于执行多次SubShader了,这就叫双通道或者多通道。

        // Draw Call:其实就是CPU调用图像编程接口的渲染命令,CPU每次调用DrawCall,都需要向GPU发送许多数据啊、渲染状态等等,
        // 一旦CPU执行完应用阶段,GPU就会开始执行这次的渲染流程。而GPU渲染的速度比CPU提交命令的速度要快的多,
        // 所以如果DrawCall数量过多的情况下,CPU需要进行大量的计算,进而就会导致CPU过载,影响游戏的运行效率。
        Pass
        {
            CGPROGRAM
            // 声明顶点着色器
            #pragma vertex vert
             // 声明像素着色器
            #pragma fragment frag
             // 使雾生效
            #pragma multi_compile_fog
             // 引用CG的核心代码库
            #include "UnityCG.cginc"

             // 应用程序阶段结构体
            struct appdata
            {
                // 模型空间的顶点坐标
                float4 vertex : POSITION;
                // 模型的第一套UV坐标
                float2 uv : TEXCOORD0;
            };
            //顶点和纹理
            struct v2f
            {
                // UV
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            // 定义顶点着色器函数 函数名要与声明顶点着色器名称相同
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            // SV_Target可以视为COLOR ,虽说他也是作为输出值输出给系统的
            // 但它其实是告诉系统把输出的颜色值存储到RenderTarget中
            // 所以这里我们用SV_Target
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

Shader一些常用API讲解

// Shader 的路径名称  默认为文件名,也可以与文件名不同
Shader "Unlit/TestShader"
{
    // 属性 
    // Material Inspector显示的所有参数都在需要在这里进行声明
    Properties
    {
        // 通常所有属性名都以下划线字符开头 _MainTex
        _MainTex("Texture", 2D) = "white" { }

    // 比较常见的属性类型
    // ————————————————————————————————————————————————
    _Integer("整数(新版)", Integer) = 1
    _Int("整数(旧版)", Int) = 1
    _Float("浮点数", Float) = 0.5
    _FloatRange("浮点数滑动条", Range(0.0, 1.0)) = 0.5
        // Unity包含以下内置纹理, 可以直接填充
        // “white”(RGBA:1,1,1,1)
        // “black”(RGBA:0,0,0,1)
        // “gray”(RGBA:0.5,0.5,0.5,1)
        // “bump”(RGBA:0.5,0.5,1,0.5)
        // “red”(RGBA:1,0,0,1)
        _Texture2D("2D纹理贴图", 2D) = "red" { }
    // 字符串留空或输入无效值,则它默认为 “gray”
    _DefaultTexture2D("2D纹理贴图", 2D) = "" { }
    // 默认值为 “gray”(RGBA:0.5,0.5,0.5,1)
    _Texture3D("3D纹理贴图", 3D) = "" { }
    _Cubemap("立方体贴图", Cube) = "" { }
    // Inspector会显示四个单独的浮点数字段
    _Vector("Example vector", Vector) = (0.25, 0.5, 0.5, 1)
        // Inspector会显示拾色器拾取色彩RGBA值
        _Color("色彩", Color) = (0.25, 0.5, 0.5, 1)
        // ————————————————————————————————————————————————

        // 除此之外 属性声明还可以具有一个可选特性 用来告知Unity如何处理它们
        // HDR可以使色彩亮度的值超过1
        [HDR]_HDRColor("HDR色彩", Color) = (1, 1, 1, 1)
        // Inspector隐藏此属性
        [HideInInspector]_Hide("看不见我~", Color) = (1, 1, 1, 1)
        // Inspector隐藏此纹理属性的Scale Offset字段
        [NoScaleOffset]_HideScaleOffset("隐藏ScaleOffset", 2D) = "" { }
    // 指示纹理属性为法线贴图,如果分配了不兼容的纹理,编辑器则会显示警告。
    [Normal] _Normal("法线贴图", 2D) = "" { }
    }

        // 子着色器 
        // 一个Shader至少有一个或者多个子着色器SubShader,这些子着色器互不干扰,且只有一个会运行
        // 在加载shader时Unity会遍历所有SubShader列表,并最终选择用户机器支持的第一个
        SubShader
    {
        // 可以通过Tags来向子着色器分配标签
        // 只可以写在SubShader语块内,不可写在Pass内
        /* 以键值对的形式存在,可以出现多个键值对
        Tags {
            "TagName1" = "Value1"
            "TagName2" = "Value2"
            "TagName3" = "Value3"
            ...
            }
        */

        // RenderPipeline: 声明子着色器是否与通用渲染管线 (URP) 或高清渲染管线 (HDRP) 兼容
        // 仅与 URP 兼容
        // Tags { "RenderPipeline"="UniversalRenderPipeline" }
        // 仅与 HDRP 兼容
        // Tags { "RenderPipeline"="HighDefinitionRenderPipeline" }
        // RenderPipeline不声明或任何其他值表示与 URP 和 HDRP 不兼容
        // ————————————————————————————————————————————————

        // Queue: 声明渲染队列
        // Tags { "Queue"="Background" } // 最早被调用的渲染,用来渲染天空盒或者背景
        // Tags { "Queue"="Geometry" }   // 这是默认值,用来渲染非透明物体(普通情况下,场景中的绝大多数物体应该是非透明的)
        // Tags { "Queue"="AlphaTest" }  // 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑
        // Tags { "Queue"="Transparent" }// 以从后往前的顺序渲染透明物体
        // Tags { "Queue"="Overlay" }    // 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效)
        // ————————————————————————————————————————————————

        // RenderType: 用来区别这个Shader要渲染的对象是属于什么类别的。
        // 设置渲染类型 用一种称为着色器替换的技术在运行时交换子着色器,用来区别这个Shader要渲染的对象是属于什么类别的
        // 这里表示非透明物体渲染
        Tags { "RenderType" = "Opaque" }
        // 更多详细内容可参考官网文档 https://docs.unity.cn/cn/2021.3/Manual/SL-SubShaderTags.html

        // LOD (Level of Detail)
        LOD 100

        // 每个子着色器由多个通道组成,许多简单的着色器只使用一个通道,但想要一些更复杂的效果,着色器可能需要更多通道
        // 一个Pass就是一次绘制,可以看成是一个Draw Call而Pass的意义在于多次渲染,
        // 如果你有一个Pass,那么着色器只会被调用一次,如果你有多个Pass的话,
        // 那么就相当于执行多次SubShader了,这就叫双通道或者多通道。

        // Draw Call:其实就是CPU调用图像编程接口的渲染命令,CPU每次调用DrawCall,都需要向GPU发送许多数据啊、渲染状态等等,
        // 一旦CPU执行完应用阶段,GPU就会开始执行这次的渲染流程。而GPU渲染的速度比CPU提交命令的速度要快的多,
        // 所以如果DrawCall数量过多的情况下,CPU需要进行大量的计算,进而就会导致CPU过载,影响游戏的运行效率。
        Pass
        {
            CGPROGRAM
            // 声明顶点着色器
            #pragma vertex vert
            // 声明像素着色器
            #pragma fragment frag
            // 使雾生效
            #pragma multi_compile_fog

            // 引用CG的核心代码库
            # include "UnityCG.cginc"

            // 应用程序阶段结构体
            struct appdata
            {
        // 参考:https://docs.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics
        // POSITION 着色器语言的语义,用来限定着色器的输入输出值的类型
        // 模型空间的顶点坐标
        float4 vertex : POSITION;
        // 模型的第一套UV坐标
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        // UV
       float2 uv : TEXCOORD0;
       UNITY_FOG_COORDS(1)
           // SV_POSITION 当这个值需要作为输出值输出给系统用的时候 前面需要加SV_前缀
           // 当然因为有向下兼容的机制 不加也没啥太大问题
           float4 vertex : SV_POSITION;
       };

    // 在Properties中声明的参数要在这里相对应的定义后才可以使用
    sampler2D _MainTex;
    float4 _MainTex_ST;

    // 定义顶点着色器函数 函数名要与声明顶点着色器名称相同
    v2f vert(appdata v)
    {
        v2f o;
        // 将顶点坐标从模型空间变换到裁剪空间
        o.vertex = UnityObjectToClipPos(v.vertex);
        // Transforms 2D UV by scale/bias property
        // #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
        // 等价于v.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;
        // 简单来说,TRANSFORM_TEX主要作用是拿顶点的uv去和材质球的tiling和offset作运算,
        // 确保材质球里的缩放和偏移设置是正确的
        o.uv = TRANSFORM_TEX(v.uv, _MainTex);
        UNITY_TRANSFER_FOG(o, o.vertex);
        return o;
    }

        // SV_Target可以视为COLOR ,虽说他也是作为输出值输出给系统的
        // 但它其实是告诉系统把输出的颜色值存储到RenderTarget中
        // 所以这里我们用SV_Target
        fixed4 frag(v2f i) : SV_Target
        {
            // 采样2D纹理贴图
            fixed4 col = tex2D(_MainTex, i.uv);
            // 应用雾
            UNITY_APPLY_FOG(i.fogCoord, col);
            // 返回经过处理后的最终色彩
            return col;
        }
        ENDCG
        }
    }
}

 本内容部分来自Unity官方文档和Unity官方教学视频

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity Shader是一种用于渲染图形的程序,它可以控制对象的表面颜色、纹理、透明度、反射等属性,从而实现特殊的视觉效果。对于游戏开发者来说,掌握Shader编写技巧是非常重要的。 以下是关于Unity Shader入门精要: 1. ShaderLab语言 ShaderLab是Unity中用于编写Shader的语言,它是一种基于标记的语言,类似于HTML。ShaderLab可以用于定义Shader的属性、子着色器、渲染状态等信息。 2. CG语言 CG语言是Unity中用于编写Shader的主要语言,它是一种类似于C语言的语言,可以进行数学运算、向量计算、流程控制等操作。CG语言可以在ShaderLab中嵌入,用于实现Shader的具体逻辑。 3. Unity的渲染管线 Unity的渲染管线包括顶点着色器、片元着色器、几何着色器等组件,每个组件都有不同的作用。顶点着色器用于对对象的顶点进行变换,片元着色器用于计算每个像素的颜色,几何着色器用于处理几何图形的变形和细节等。 4. 模板和纹理 在Shader中,我们可以使用纹理来给对象添加图案或者贴图,也可以使用模板来控制对象的透明度、反射等属性。纹理可以通过内置函数tex2D()来获取,模板可以通过内置函数clip()来实现裁剪。 5. Shader的实现 Shader的实现需要注意以下几点: - 在ShaderLab中定义Shader的属性、子着色器、渲染状态等信息。 - 在CG语言中实现Shader的具体逻辑,包括顶点着色器、片元着色器等内容。 - 使用纹理和模板来实现特定的视觉效果。 - 在对象上应用Shader,通过调整Shader的属性来达到不同的效果。 以上是关于Unity Shader入门精要,希望对你有所帮助。如果你想更深入地了解Shader的编写技巧,可以参考官方文档或者相关教程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值