使用表面着色器的属性

现在我们已经为着色器创建了一些属性,这里我们将要正式的把这些属性跟着色器关联起来,这些属性就像着色器的调节器一样,可以让材质拥有更好的交互性。

我们可以在材质的**检查器面板(Inspector tab)**使用着色器属性的值,因为我们为这个属性添加了一个变量名,但是如果你在着色器代码中想要通过这个变量名来获得这个值,我们仍然还有很多事情要做。


  • 操作步骤

    下面的步骤展示了如何在表面着色器中使用属性:

    1. 开始之前,我们先删除下面的行的代码,就好像我们在章节创建一个基本的标准着色器中删除属性的操作步骤一样,删除**_MainTex**属性:
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    
    sampler2D _MainTex;
    
    fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    
    1. 下一步,添加下面这些行的代码到着色器代码中,添加到CGPROGRAM下面, add the following lines of code to the shader, below the CGPROGRAM line:
    float4 _AmbientColor;
    float _MySliderValue;
    
    1. 当第二部完成之后,我们就可以在着色器中使用属性的值了。我们把**_Color属性的值与_AmbientColor值相加,并且把两者的结果赋值给o.Albedo**。为了达成目的,我们需要在着色器代码中的**surf()**方法中添加如下代码:
    void surf (Input IN, inout SurfaceOutputStandard o) 
    {
          fixed4 c        = pow((_Color + _AmbientColor), _MySliderValue);
          o.Albedo        = c.rgb;
          o.Metallic      = _Metallic;
          o.Smoothness    = _Glossiness;
          o.Alpha         = c.a;
    }
    
    1. 最终你的代码将会是如下所示。如果你在你的VSCode中保存好然后返回Unity编辑器,你的着色器将会重新编译。 如果没有什么错误,那么现在你可以修改材质的环境光和自发光的颜色,当然也可以通过滑动条增加最终颜色的饱和度。听巧妙的噢。
    Shader "CookbookShaders/StandardDiffuse3" 
    {
          // We define Properties in the properties block
          Properties 
          {
              _Color ("Color", Color) = (1,1,1,1)
              _AmbientColor("Ambient Color", Color) = (1,1,1,1)
              _MySliderValue("This is a Slider", Range(0,10)) = 2.5
          }
          SubShader 
          {
              Tags { "RenderType"="Opaque" }
              LOD 200
              // We need to declare the properties variable type inside of the 
              //CGPROGRAM so we can access its value from the properties block.
              CGPROGRAM
              #pragma surface surf Standard fullforwardshadows
              #pragma target 3.0
              struct Input { float2 uv_MainTex;};
              fixed4 _Color;
              float4 _AmbientColor;
              float  _MySliderValue;
              void surf (Input IN, inout SurfaceOutputStandard o) 
              {
                  // We can then use the properties values in our shader
                  fixed4 c = pow((_Color + _AmbientColor), _MySliderValue);
                  o.Albedo = c.rgb;
                  o.Alpha = c.a;
              }
              ENDCG
          }
          FallBack "Diffuse"
    }  
    
  • 提示 下载示例代码 你可以在Packt网站登陆后,下载所有已购买书籍的所有示例代码文件,下载地址:http://www.packtpub.com。如果你是在别处购买的书,那么请访问: http://www.packtpub.com/support然后注册,以便通过邮件直接获取相关的代码文件。

  • 注意 pow(arg1, arg2)这个方法是内建的,他的功能跟数学的幂函数power是等价的。第一个参数是底数,第二参数是指数 。想了解更深入的了解**pow()方法,请去看Cg语言的教程。下面这个网址提供了非常棒的资源,能让你学习更多有关着色器的知识,并且里面有Cg着色器语言的所有函数的表:
    http://http.developer.nvidia.com/CgTutorial/cg_tutorial_appendix_e.html 下面的屏幕截图展示了通过材质的
    检查器面板(Inspector tab)**来控制材质的属性,从而控制材质的颜色和饱和度:


  • 原理介绍

    当你在属性(Properties )代码块中声明一个新的属性时,等于是在材质的检查器面板( Inspector tab)给着色器添加了可以访问调整值[tweaked value]的方式。这个值存储在这个属性的变量名中。在这个例子中,_AmbientColor_Color 和**_MySliderValue这三个变量就是我们用来保存调整值的。为了让你能够在SubShader{}** 这个代码块中使用这些值,你需要在这个代码块中对应创建三个变量,而且这三个变量的名字要跟属性代码块中的变量名保持一致。这样的话Unity会自动把**SubShader{}代码块和属性代码块中的变量关联起来,然后让着色器知道这些变量使用的是相同的数据。另外,这个属性声明同时也告诉我们在SubShader{}**代码块中对应的变量的数据类型,在后续有关着色器的优化相关的章节中,会用到这些。

    当你再subshader代码块中创建好变量后,接下来你就可以再surf()方法中使用它们的值。在这个例子中,_Color_AmbientColor与**_MySliderValue这三个变量获得了来自材质的检查器面板(Inspector tab)** 对应的值。变量**_Color跟变量_AmbientColor这两个值相加,并且把这个值当作底数,_MySliderValue**的值当作指数,进行幂运算。

    大多数着色器都是从一个标准着色器开始,然后一步一步修改它直到它们符合设计的样子。我们现如的这个例子为以后需要散射组件的表面着色器打好了基础。

    注意 材质时一种资源(assets)。这意味着,当你的游戏在编辑器中运行时,你对它的任何改变都将会是永久的[这里解释一下,一般在Unity编辑器运行时,你对游戏做的修改,在停止运行后,又会恢复到运行之前的状态,这里材质不一样,修改之后,即使停止运行,它也不会恢复]。如果你不小心错误修改了属性的值,你可以通过快捷键Ctrl + Z取消这个修改。


  • 相关补充

    跟其他一些编程语言一样,Cg也是不允许有错误。如果你的着色器代码中有错误的话,着色器将不会起作用。当着色器不起作用时,你的材质会因为没有着色器而以品红的方式渲染:

    • 忘记括号匹配。 如果忘记用花括号对代码块进行配对匹配,那么编译器就会在代码文档的最后,开始或者新的代码块中提示错误。

    • 忘记写分号结束语句。这是最常见的错误,同时也是最容易定位和修复的错误。通常会在下一行开始产生一个错误。

    • 在**属性(Properties)代码块中定义了一个属性,但是没有在SubShader{}代码块中定义对应的变量。【这两者是需要成对出现的,也就是说在属性(Properties)块里面定义了一个新的属性,那么在SubShader{}**代码块中就需要声明一个与之对应的变量】

    • 更Unity中的C#脚本不一样,Cg语言中的浮点值不需要在后面加f来表示浮点类型:浮点值1.0就写作1.0,而不是1.0f

    着色器中提示的错误很具有误导性,特别是因为它们那严格的语法约束。如果看不懂错误什么意思,那就直接百度或者谷歌。 或者去Unity的论坛搜索一下看看,里面可能就有跟你遇到相同问题(修复了相同问题)的开发者。


    • 额外内容

      第二章表面着色器和纹理纹理,我们会了解如何去掌握表面着色器(Surface Shaders)跟它们的属性(properties )。如果使用着色器的所有潜能和特性,到底能做些什么?如果你对这个问题感兴趣,你应该去看一看第十章更高级的着色器技术 。里面有本书的一些最高级的着色器技术。