前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity Shader基础

Unity Shader基础

原创
作者头像
Zero Two
发布2024-07-14 19:59:55
680
发布2024-07-14 19:59:55
举报
文章被收录于专栏:Unity Learning

我也是一个学习者,有错误请指出。 References: 《Unity Shader 入门精要》

Unity Shader概述

材质Material与Unity shader

Unity中,我们需要配合使用材质和unity shader,它们的关系和流程是:

首先创建Unity Shader,它定义了各种着色器(如顶点着色器、片元着色器)、属性和指令,将其赋给材质。可以在材质面板上调整Unity Shader的属性,最后将其赋给某个要渲染的对象(模型)来得到最终的效果。

Unity中的材质

创建好一个材质后,一般要结合一个GameObject的Mesh或者Particle System来工作。

从Unity 5.0版本开始,默认情况下创建的Material使用的是Unity内置的Standard Shader。这种默认行为一直持续到现在。Standard Shader提供了丰富的物理材质(PBR)功能,允许用户创建各种复杂和逼真的材质效果。

材质的Inspector界面中,这个选可以简单调整光照,并且这个界面本身有预览功能,可以按住右键移动查看效果。

Unity Shader

Unity Shader与传统的vs和fs有很大不同。

Unity中提供了5种Unity Shader模板:

  1. Standard Surface Shader: 包含了一个标准光照模型的表面着色器模板
  2. Unlit Shader:产生一个不包含光照(但包含雾效)的基本顶点/片元着色器
  3. Image Effect Shader:实现屏幕后处理效果的模板
  4. Computer Shader:特殊的shader,利用GPU的并行性计算与常规渲染管线无关的计算
  5. Ray Tracing Shader:用于实现光线追踪效果的模板

材质可以选择使用的shader,这样在材质的Inspector界面可以设置shader的各种属性。

在Unity Shader的Inspector界面中,可以看到和设置很多信息,在Compiled Code选项中,可以看到该Shader针对不同图形API接口编译的代码。

ShaderLab

如果直接使用某一个图形API进行渲染,要进行很多工作,一不注意就会出错(当初我就是设置错了一个渲染状态导致我调试了2小时OpenGL)

而Unity Shader为开发者提供了一个渲染抽象层,使得开发者可以更加轻松。

所有的Unity Shader都是使用ShaderLab来编写的,ShaderLab是Unity提供的编写Unity Shader的一种说明性语言,它使用了一些嵌套在花括号内的语义来描述Unity Shader文件的结构,这些结构包含了许多渲染所需的数据,例如Properties语句块中定义了着色器所需的各种属性,这些属性会出现材质面板中。

Unity Shader的结构

之前我们提到了Unity Shader是通过Shader Lab分为了多个语义块,下面将分块介绍Unity Shader。

Properties

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

代码一般为这样的形式:

代码语言:javascript
复制
Properties {
     Name ("display name", Type) = DefaultValue
     // 更多其他属性
}

Properties的属性类型:

语义块中定义的属性的作用就是为了在材质面板中显示,这样开发者可以在面板上直接调整属性的值。shader中要想使用这些变量,需要直接在shader中使用相应的Uniform变量,属性和Uniform变量的名字通常是一致的,这样系统才会正确将属性传给Uniform变量;或者通过脚本传递。

SubShader

每个Unity Shader文件可以包含多个SubShader块,至少要有一个SubShader块。当Unity加载这个Unity Shader时,Unity会扫描所有的SubShader块,然后选择第一个能够在目标平台上运行的SubShader。

这样做的原因是,不同的显卡具有不同的能力,我们希望在旧显卡上运行计算复杂度较低的着色器,在高级的显卡上运行复杂度较高的着色器。

SubShader语义块的定义如下:

代码语言:javascript
复制
SubShader{
    // 可选的
    [Tags]
    // 可选的
    [RenderSetup]
    
    Pass{
    
    }
    // 其他Pass
}

SubShader中定义了一系列的Pass以及[RenderSetup]状态和[Tags]标签。

每个Pass定义了一个完整的渲染流程,过多的Pass会导致性能的下降。标签和状态同样也可以在Pass中定义,但是SubShader的标签与Pass中使用的标签是不一样的,SubShader中的一些标签是特定的;状态两者使用的语法相同,但如果在SubShader中设置了状态,那么会用于全部的Pass

状态设置

SubShader提供了一系列的指令,这些指令用于设置显卡的各种状态。

一些常见的状态设置

就像之前提到的,SubShader中设置的状态会应用到全部的Pass,要想不同Pass使用不同的设置,需要在每个Pass中单独进行状态设置。

SubShader标签

SubShader的标签是一个键值对,键和值都是字符串。

结构如下:

代码语言:javascript
复制
Tags { "TagName1" = "Value1" "TagName2" = "Value2" }

Pass标签

代码语言:javascript
复制
Pass {
    [Name]
    [Tags]
    [RenderSetup]
    // other
}

可以在Pass中定义该Pass的名称:

代码语言:javascript
复制
Name "MyPassName"

这样,我们可以在其他Unity Shader中调用ShaderLab的UsePass命令使用Pass

代码语言:javascript
复制
UsePass "MyShader/MYPASSNAME"

Unity内部会将所有Pass的名称转换为大写字母,所以使用UsePass时要使用大写形式

Pass中的标签不同于SubShader的标签

RequireOptions现在有很多选项,例如Shadows, Directional, Point等等,使用时查阅相关文档即可。

Unity Shader中还支持一些特殊的Pass:

  1. UsePass:复用其他Shader的Pass
  2. GrabPass:该Pass的作用是抓取屏幕并将结果存储在一张纹理中,用于后续Pass处理

Others

Unity Shader以及ShaderLab还能实现很多功能,比如自定义材质面板等等,但不太常用。

Unity Shader的形式

上面讲解了这么多,但基本没有涉及到Unity Shader是如何处理传统的像是顶点着色器或者片元着色器。这些着色器代码可以写在SubShader语义块中(表面着色器),也可以写在Pass语义块中(顶点/片元着色器和固定函数着色器)

代码语言:javascript
复制
Shader "ShaderName" {
    Properties {
    }
    SubShader {
        // shader code
    }
    SubShader {
    }
}

Surface Shader

这是Unity自创的一种shader类型,它需要的代码量很少,这就意味着Unity在背后为它做了很多工作(一般这种需要软件背后做工作的,性能都不会太好)。它本质上还是一个vs或fs,Unity会对其进行转换。

它的意义在于处理了很多光照细节,不需要开发者自己编写。

代码语言:javascript
复制
Shader "Custom/Simple Surface Shader" {
    SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
        #pragma surface surf Lambert

        struct Input {
            float4 color : COLOR;
        };

        void surf(Input IN, inout SurfaceOutput o) {
            o.Albedo = IN.color.rgb;
        }
        ENDCG
    }
}

需要注意的点有:

  1. Surface Shader的代码没有定义在Pass语义块中,表面着色器不需要开发者关心Pass的问题,Unity会为我们处理好
  2. CGPROGRAMENDCG之间的代码是使用Unity封装后的CG/HLSL编写,与原生的CG/HLSL仅有细微的不同。

Vertex/Fragment Shader

同样是使用CG/HLSL语言来编写,定义在CGPROGRAMENDCG,但需要写在Pass语义块内,我们需要自己定义每个Pass使用的Shader代码。

如果想要使用GLSL编写Unity shader,需要将GLSL代码嵌套在GLSLPROGRAMENDGLSL之间。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Unity Shader概述
    • 材质Material与Unity shader
      • Unity中的材质
        • Unity Shader
        • ShaderLab
        • Unity Shader的结构
          • Properties
            • SubShader
              • 状态设置
              • SubShader标签
              • Pass标签
            • Others
            • Unity Shader的形式
              • Surface Shader
                • Vertex/Fragment Shader
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档