Shaders: ShaderLab 和 固定函数着色器

Shaders: ShaderLab 和 固定函数着色器

此教程教你踏出自建Shader的第一步,帮助你控制你的游戏画面,优化图形性能。

Unity配备了一个强大的着色和材质语言——ShaderLab。它跟CgFX和Direct3D Effects(.FX)语言相似——它描述了显示一个材质所需的所有东西。

Shader描述了在Unity的材质面板上展示的属性,提供了针对不同图形硬件能力的多种着色器实现(SubShader),每个SubShader完整描述了图形硬件的渲染状态以及所使用的顶点、片元程序。Shader程序使用高级的Cg/HLSL编程语言书写。

在这个教程里我们描述了如何编写一个非常简单的固定函数着色器。在下一章我们将会介绍顶点和片元着色器程序。我们假定读者基本了解OpenGL或Direct3D渲染状态、了解HLSL、Cg、GLSL或者Metal着色器编程语言。

准备开始

想要创建新的shader,可以选择Assets>Create>Shader>Unlit Shader菜单,或者从已有的shader复制一份。在Project视图里双击这个新shader开启编辑。

Unity有一种非常简单的shader的方式,称之为固定函数。为了简单起见,我们从它开始。在shader导入时,固定函数将会被转换成常规的顶点和片元程序。

我们从一个非常基础的shader开始:

Shader "Tutorial/Basic" {
    Properties {
        _Color ("Main Color", Color) = (1,0.5,0.5,1)
    }
    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
            }
            Lighting On
        }
    }
}

这个简单的shader演示了最简单的基础shader之一。它定义了一个颜色属性 Main Color,并赋予了一个默认的粉色(red=100%, green=50%, blue=50%, alpha=100%)。然后使用一个Pass来渲染物体,在Pass里设置了Diffuse材质值为属性里的_Color值,并打开了逐顶点的光照。

创建一个新的材质就可以测试这个shader。在创建的材质资源面板上最上方的Shader下拉列表里选择Tutorial/Basic,然后将这个材质赋予某些物体。调节材质面板上的颜色并观察变化。是时候开始更复杂的shader了!
Shaders: ShaderLab 和 固定函数着色器_第1张图片

基础的顶点光照

如果你打开一个现存的复杂shader,那么很难获得整体上的了解。为了让你开始,我们将会剖析内建的VertexLit着色器,这个着色器随Unity附带。这个着色器使用固定函数管线来做标准的逐顶点光照。

注:这个教程太老了。2018.4的builtin_shader包里面的Legacy Shaders/VertexLit的第一个Pass能部分对上,但是还是有一些差异。

Shader "VertexLit" {
    Properties {
        _Color ("Main Color", Color) = (1,1,1,0.5)
        _SpecColor ("Spec Color", Color) = (1,1,1,1)
        _Emission ("Emmisive Color", Color) = (0,0,0,0)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.7
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }

    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
                Ambient [_Color]
                Shininess [_Shininess]
                Specular [_SpecColor]
                Emission [_Emission]
            }
            Lighting On
            SeparateSpecular On
            SetTexture [_MainTex] {
                constantColor [_Color]
                Combine texture * primary DOUBLE, texture * constant
            }
        }
    }
}

所有的着色器使用Shader关键词开始,并跟着一个表示其名字的字符串。这个名字将会显示在Inspector面板上。所有的代码都需要放进跟在这之后的花括号内,称之为块(block)。

  • 名字应该要简单和描述性。名字不需要跟.shader文件名相同。
  • 如果想要将着色器放进Unity的子菜单里面,那么使用斜线分隔符,例如 MyShaders/Test 将会在 MyShaders 菜单下看到 Test 子菜单。

shader由一个Properties块和若干个SubShader块构成。这些将在下面的小节详细介绍。

Properties

在shader的开头你可以定义任何属性,艺术家可以在材质面板上编辑这些属性。在VertexLit的例子里,Properties如下:

Shaders: ShaderLab 和 固定函数着色器_第2张图片

属性在Properties块内逐条列出。每个属性以一个内部名称开始(例如上面的_Color, _MainTex)。内部名称之后是一个圆括号包裹的Inspector标题和属性类型。最后以属性的默认值结尾。

在这里插入图片描述

可用的属性类型见 [Properties Reference](file:///D:/Users/hoxily/Documents/UnityDocs/Documentation.2018.4/en/Manual/SL-Properties.html)。根据属性类型,默认值具有不同的形式。以颜色为例,默认值是一个4维向量。

现在我们已经定义了属性,改准备编写实际的shader了。

着色器主体

不同的图形硬件具有不同的能力。举例来说,有些显卡支持片元程序,有些则不支持。有些支持每个Pass使用4张纹理,而另一些则仅支持到2张甚至1张纹理。为了能充分发挥用户的硬件性能,一个着色器可以包含多个SubShader。当Unity渲染一个着色器时,它将会遍历所有SubShader并使用第一个硬件支持的SubShader。

Shader "Structure Example" {
    Properties { /* ...着色器参数... */ }
    SubShader {
        // ...要求 DX11 / GLES3.1 硬件的子着色器...
    }
    SubShader {
        // ...虽然效果差一些但是能在所有硬件上跑的子着色器 :)
    }
}

这个系统允许Unity支持所有现存的硬件并且能够最大化画面质量。然而这会造成着色器变长。

在每个子着色器里面你可以设置被所有Pass共享的渲染状态,你也可以定义渲染Pass自身。完整的可用命令参见 [SubShader Reference](file:///D:/Users/hoxily/Documents/UnityDocs/Documentation.2018.4/en/Manual/SL-SubShader.html)

Passes

每个SubShader都是一系列Pass的集合。对于每个Pass,物体几何都会被渲染,因此至少需要1个Pass。

// ...摘录分割线...
// 在Pass里定义的命令会将图形硬件配置成以特定方式渲染几何物体。
Pass {
    // Material 指令块将 Properties块定义的属性值绑定到固定函数光照材质设定里。
    Material {
        Diffuse [_Color]
        Ambient [_Color]
        Shininess [_Shininess]
        Specular [_SpecColor]
        Emission [_Emission]
    }
    // Lighting On 指令开启了标准的顶点光照。
    Lighting On
    // SeparateSpecular On 指令使得镜面高光使用了单独的颜色。
    SeparateSpecular On
    // 以上 Material、Lighting On、SeparateSpecular On指令直接对应于OpenGL/Direct3D里的固定函数硬件模型。参见 OpenGL red book。

    // SetTexture 指令定义了我们想要使用的纹理,以及在渲染中如何混合、结合以及应用。
    // 此处括号内的 _MainTex 就是我们想要使用的纹理。SetTexture内部是一个Combiner块。
    // Combiner块决定了这个纹理如何应用。
    // Combiner块里的指令将会在渲染到屏幕的每个像素上执行。
    SetTexture [_MainTex] {
        // 设置颜色常量——也就是材质的颜色——为 _Color
        constantColor [_Color]
        // 使用Combine指令来指明如何混合纹理或者混合纹理和颜色。
        // 一般格式为:Combine ColorPart, AlphaPart
        // ColorPart和AlphaPart分别定义了如何混合RGB颜色和Alpha分量。

        // 下面的指令中,texture是指来自当前纹理(此处为_MainTex)的颜色。它与primary顶点颜色相乘。
        // primary颜色指的是顶点光照颜色,由上面的材质参数计算得出。最后颜色乘以了2以增加光照亮度(DOUBLE)。
        // 逗号后的alpha值为当前纹理的alpha分量乘以constant值(由上面constantColor指令设置的)。
        Combine texture * primary DOUBLE, texture * constant

        // 除了primary还有previous模式。previous是指前面的SetTexture指令的结果,可以用来结合多个纹理或者颜色。
    }
}
// ...摘录分割线...

总结

这个VertexLit着色器配置了标准的顶点光照,然后设置了纹理结合参数,结果就是渲染的灯光亮度加倍了。

我们也可以将更多Pass放进着色器里,它们将会依次渲染。暂时并不需要多Pass,因为我们已经获得想要的效果了。我们只需要一个SubShader,因为我们并不需要任何高级特性。上面这个着色器可以在Unity支持的任何显卡上运行。

这个顶点光照着色器是最基本的着色器之一。我们不需要任何特定硬件操作,也不需要使用ShaderLab/CG/HLSL提供的特殊炫酷命令。

在下一章我们将介绍如何使用CG/HLSL语言编写自定义的顶点和片元程序

你可能感兴趣的:(shader,unity)