给着色器添加属性

着色器的属性对于着色器管线来说时非常重要,因为艺术家或者用户想要添加纹理或者调整着色器的值都是通过著色器的属性来修改的。着色器的属性在材质的 检查器面板(Inspector) 中会提供GUI,提供图形界面让玩家去调整一个着色器,不用打开额外的编辑器。用Visual Studio Code打开你的着色器代码,从第2行到第7行的代码块就是着色器的 属性(Properties) 。当前的这个着色器,他会有一个叫 _MainTex 的属性。如果你查看使用了这个着色器的材质,你能注意到着色器的 检查器面板(Inspector) 中有一个 纹理(texture) 的GUI元素。着色器中的这行代码为我们创建了这个GUI元素。还有就是,Unity工作人员通过编码方式和努力的迭代,让你改变属性的这个过程非常快速高效。


  • 始前准备

    让我们来了解一下这个过程在 标准漫反射(StandardDiffuse) 着色器中是如何工作的,为此我们要创建自己的属性并且学习更多相关的着色器语法。比如我们会修改之前创建的着色器。在这个修改的着色器中,不适用纹理,而是仅仅使用能从**检查器面板(Inspector)**直接修改的颜色和其他的属性。开始之前,我们先复制一个 标准漫反射(StandardDiffuse) 着色器。你可以在 项目(Project) 面板中选中它,然后按 Ctrl + D 。这样就会复制一份新的 StandardDiffuse 1 的着色器。【书上的写法有问题,在Inspector面板根本不能选中复制,应该在项目面板中选中在复制】


    注意
    你最好给你复制的这个着色器在第一行代码处给它一个恰当的名字。比如,Shader “CookbookShaders/StandardDiffuse” 可以告诉Unity这个着色器叫 StandardDiffuse 并且把它分组到 CookbookShaders 这个着色器组。如果你是通过 Ctrl + D 复制的着色器,你新复制的这个着色器跟被复制的着色器就会用相同的名字和分组。为了避免混淆,一定要记得复制着色器代码之后,在第一行那里修改着色器的名字,给一个不会重复的名字。


  • 操作步骤

    StandardDiffuse2 这个着色器准备好后,我们就可以开始修改它的属性了:

    1. 在着色器的 属性(Properties ) 块中,删除着色器中下面的属性代码,整行删除:
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    
    1. 当我们移除这个必要的属性后,着色器不会被编译直到所有跟 _MainTex 的代码都被移除。然我们删除另外有引用的代码:
    sampler2D _MainTex;
    
    1. 原始的着色器使用 _MainTex 给游戏模型上色。为了改变这个,我们替换掉 surf() 方法的第一行代码,通过如下代码:
    fixed4 c = _Color;
    
    1. 当你修改完成之后,返回Unity,然后着色器会被重新编译, 之后我们的材质 检查器 面板中就没有纹理选择这一选项了。 为了完成这个着色器的调整,让我们添加一个额外的属性给着色器,看看会有什么效果。输入下面的代码:
    _AmbientColor ("Ambient Color", Color) = (1,1,1,1)
    
    1. 我们在材质的 检查器 面板中添加了另一个颜色选项。现在,让我们来额外添加另一种类型的属性来找找属性语法的感觉。添加下面的代码到 属性 代码块中:
    _MySliderValue ("This is a Slider", Range(0,10)) = 2.5
    
    1. 我们创建了其他两种不同类型的GUI元素,它们可以让我们与着色器进行可视化的交互。我们这次创建了一个叫做 This is a Slider 的滑动条,就如下图所示:
      diagram

    着色器的属性让你可以通过可视化的方式调整着色器,而不用在着色器自己的代码中调整。 下一个知识点将会为你介绍如何利用这些属性创建一些更有趣的着色器。


    注意
    尽管属性属于着色器,但是着色器上属性的值却是保存在材质上的。不同的材质可以很安全的共用相同的着色器。从另一方面说,修改材质上的属性的值,将会影响到所有使用了该材质的游戏对象的外观。


  • 原理介绍

    每一个Unity的着色器都有它想要的内建的代码结构。属性 代码块就是Unity所期望的功能之一。属性 代码块的目的是让着色器编程人员能快速的创建GUI交互元素,并且将GUI元素与着色器代码相关联起来。那些你在着色器 属性 面板中申明的属性,能让你在着色器代码中使用,从而修改着色器中的一些值,颜色和纹理。 定义一个属性的语法[也可以叫语义,也可以叫语法糖]如下: diagram

    让我们来解释一下这个示意图。 当你第一次开始写一个新的属性时,你需要给这个书信一个 变量名(Variable Name) 。这个变量名能让着色器使用并且能让着色器代码获得来自该变量名绑定的GUI元素的值。这给我们节约了大量的时间因为我们不用自己来创建这么一个系统。属性的下一个元素时 检查器面板GUI名称( Inspector GUI Name ) 和属性的 类型(Type) ,这两个元素放在一对括号中。当玩家想要交互和调整着色器时, 检查器面板GUI名称( Inspector GUI Name ) 将会在材质的 检查器面板(Inspector tab) 中展示。类型(Type) 就是这个属性想要控制的数据类型。在Unity着色器中,有很多属性可以使用的类型。下面这个表展示了我们在着色器中可以使用的变量类型:

    类型说明
    Range (min, max)创建一个浮点类型的滑动条属性,值从最小值到最大值[min最小值,max最大值]
    Color检查器面板(Inspector tab) 中创建一个颜色选取框,当你打开的时候会弹出一个调色板,颜色值R,G,B,A
    2D创建了纹理选取框的GUI元素,可以让玩家通过拖拽的方式给着色器一张纹理
    Rect创建一个非2次幂纹理[NPOT]选取框,功能更 2D 属性类似
    Cube检查器面板(Inspector tab) 创建一个立方体纹理[大家想想天空盒],可以让玩家拖拽立方体纹理到着色器中
    Float检查器面板(Inspector tab) 中创建一个浮点型的值,但是没有滑动条–
    Vector创建一个有四个值的属性,能让你表示方向或者颜色

    最后就是这些属性的 默认值(Default Value) 了。可以在着色器代码中简单的给着色器的属性设置特定的值。在上一个图片属性改成颜色属性的列子中,属性

    _AmbientColor 的默认值是一个 Color 类型的默认值,其值为 1,1,1,1 。这个颜色属性需要一个 RGBA 或者 float4 或者 r,g,b,a=x,y,z,w 赋值。颜色属性第一次创建的时候默认值时白色。