创建第一个着色器

最近学习了一段时间Unity Shader相关知识,在进一步自顶向下学习计算机图形学之前,先将之前看《Unity 5.x Shaders and Effects Cookbook》 的学习笔记整理一下。

几个都是表面白色的方块材质,光的方向观察者的角度会使他们有不同程度的白——这种三维图像的真实感是由着色器Shader实现——模拟了光的作用。

Unity Shader Material Object

Unity中一个object最多有一个renderer来决定它的视效,但是renderer自己可以有多个materials,而每个material都是一种shader的包装wrapper。

Materials are definitions of how a surface should be rendered, including references to textures used, tiling information, colour tints and more. The available options for a material depend on which shader the material is using.

Shaders are small scripts that contain the mathematical calculations and algorithms for calculating the colour of each pixel rendered, based on the lighting input and the Material configuration.

Textures are bitmap images. A Material may contain references to textures, so that the Material’s shader can use the textures while calculating the surface colour of an object. In addition to basic colour (albedo) of an obejct’s surface, textures can represent many other aspects of a material’s surface such as its reflectivity or roughness.


标准着色器 Standard Shader

步骤

  1. 创建一个新的Unity Project
  2. 在Assets目录下新建一个文件夹:Shaders
  3. 在Assets目录下新建一个文件夹:Materials
  4. 创建一个plane 和几个模型Asset Store下载了书本模型组成的scene
  5. Shaders文件夹中创建Create/Shader/Standard Surface Shader更名为StandardDiffuse
  6. Material文件夹中创建Create/Material更名为StandardDiffuse
  7. Material选择该Shader,并赋给一个对象

Init Scene

以下是Unity中 Standard Surface Shader 默认创建的为我们写好的代码

Shader “Custom/StandardDiffuse” {

    Properties {

        _Color (“Color”Color) = (1,1,1,1)

        _MainTex (“Albedo (RGB)”2D) = “white” {}

        _Glossiness (“Smoothness”Range(0,1)) = 0.5

        _Metallic (“Metallic”Range(0,1)) = 0.0

    }

    SubShader {

        Tags { “RenderType”=“Opaque” }

        LOD 200

        CGPROGRAM

        // Physically based Standard lighting model, and enable shadows on all light types

        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting

        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {

            float2 uv_MainTex;

        };

        half _Glossiness;

        half _Metallic;

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o) {

            // Albedo comes from a texture tinted by color

            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;

            o.Albedo = c.rgb;

            // Metallic and smoothness come from slider variables

            o.Metallic = _Metallic;

            o.Smoothness = _Glossiness;

            o.Alpha = c.a;

        }

        ENDCG

    }

    FallBack “Diffuse”

}

小结

  1. 第一行是对shader的描述,path可以自定义让它在shader drop-down list中好找一些
  2. 这是一个Surface Shader based on physically-based rendering,意思是这种shader会通过模拟光打在物体上的的物理行为来达到真实感效果。
  3. 最后一行表明,当这个shader在当前环境中运行失败后,会默认调用Unity自带的Diffuse Shader;
  4. Unity内部使用的是Cg来实现的,它把这些实现细节封装了起来,提供我们一种基于构件的编写shader的方法,像调整图片的uv坐标、矩阵转换等工作它都帮你做好了。而以前,我们需要重复编写一些基本功能的代码,来从头创建一个shader。当你的经验逐渐丰富起来,自然而然就会想要了解Unity是怎样处理图像处理单元(GPU)的工作的。如果你想了解Unity是怎样调用Cg的,可以到Unity的安装目录Unity45\Editor\Data\CGIncludes  下查看
  5. 在Unity5之前,主要的两种shader是Diffuse和Specular,顾名思义他们各自用于不光滑和镜面的材料。
  1. 编写Shaders总是一个效率和真实感的取舍过程。相比以前的Diffuse和Specular shaders Standard Shader是专门设计用于真实感的材料 realistic materials

为着色器添加属性Properties

着色器的属性允许你在material的inspector中暴露一些GUI元素以此其他用户可以修改这些着色器的值。

上一小节的shader代码中可以看到Properties代码恰好对应了inspector中的GUI元素_MainText对应了texture元素

Properties {

        _Color (“Color”Color) = (1,1,1,1)

        _MainTex (“Albedo (RGB)”2D) = “white” {}

        _Glossiness (“Smoothness”Range(0,1)) = 0.5

        _Metallic (“Metallic”Range(0,1)) = 0.0

    }

步骤

  1. 复制一个StandardDiffuse2
  2. 删除_MainText那一行
  3. 删除_MainTex的其他引用
  4. 用fixed4 c = _Color替换surf()的第一行
  5. 用这个新的shader施加于原来的Material上就会发现texture swatch没有了
  6. 增加属性_AmbientColor (“Ambient Color”, Color) = (1,1,1,1)
  7. 增加属性_MySliderValue (“This is a Slider”, Range(0,10)) = 2.5

 

现在我们的MaterialInspector

同时StandardDiffuse2的代码如下

Shader “FirstShaders/StandardDiffuse2” {

    Properties {

        _Color (“Color”Color) = (1,1,1,1)

        _Glossiness (“Smoothness”Range(0,1)) = 0.5

        _Metallic (“Metallic”Range(0,1)) = 0.0

        _AmbientColor (“Ambient Color”Color) = (1,1,1,1)

        _MySliderValue (“This is a Slider”Range(0,10)) = 2.5

    }

    SubShader {

        Tags { “RenderType”=“Opaque” }

        LOD 200

        CGPROGRAM

        // Physically based Standard lighting model, and enable shadows on all light types

        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting

        #pragma target 3.0

        struct Input {

            float2 uv_MainTex;

        };

        half _Glossiness;

        half _Metallic;

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o) {

            // Albedo comes from a texture tinted by color

            fixed4 c = _Color;

            o.Albedo = c.rgb;

            // Metallic and smoothness come from slider variables

            o.Metallic = _Metallic;

            o.Smoothness = _Glossiness;

            o.Alpha = c.a;

        }

        ENDCG

    }

    FallBack “Diffuse”

}

小结

  1. Unity使用如图的语法来定义属性,变量名、在Inspector 中的GUI名、类型、默认值
  2. Unity支持的SurfaceShaderPropertyTypes如图
  3. 我们删除的_MainTex (“Albedo (RGB)”2D) = “white” {},之后会谈论到

5

6

下一节将会解释如何将这些属性用来创建更有趣的着色器。


在Surface Shader中使用Properties

既然我们已经创建了一些属性,让我们试试如何在Shader中访问和使用它们,以便通过调整Inspector中的变量来改变渲染效果。

步骤

1、在上一节最后代码的基础上,在CGPROGRAM一行后写

float4 _AmbientColor;

float _MySliderValue;

2、使用_Color和_AmbientColor来计算新的c

3、最后代码和效果的是这样的

Shader “FirstShaders/StandardDiffuse2” {

    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

        CGPROGRAM

        #pragma surface surf Standard fullforwardshadows

        #pragma target 3.0

        struct Input {

            float2 uv_MainTex;

        };

        float4 _AmbientColor;

        float _MySliderValue;

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o) {

            fixed4 c = pow((_Color + _AmbientColor), _MySliderValue);

            o.Albedo = c.rgb;

            o.Alpha = c.a;

        }

        ENDCG

    }

    FallBack “Diffuse”

}

小结

  1. 如果我们想要在SubShader{}代码块中使用声明的属性,还需要在CGPROGRAM内部声明一个和Properties中名字相同的变量。这将自动建立链接,Inspector中操作的数据和这里变量操作的数据是相同的。
  2. 还需要声明它的类型,如上面的float4、float等,这和Properties中的属性是不同的。
  3. pow()函数是一个内置幂函数。可以访问Cg的网站,来查看更详细的信息,同时也可以学到更多关于Cg Shading Language的内容。
  4. 如果shader中有错,Unity不会阻止游戏运行,但是shader会显示成洋红色magenta,错误会显示在shaderinspector下。

「Unity Shaders」Surface Shaders and Texture Mapping

 本文内容参考《Unity 5.x Shaders and Effects Cookbook》 表面着色器和材质贴图 总的来说,一个表面着色器有两个关键的步骤。第一,必须确定材质的物理...

阅读全文

《Effective c++》、《Inside C++ Model》 小结(一)

最近瞻仰了一下Scott Meyers久负盛名的《effective c++》,特来总结一下,以加深一下印象与防止自己今后记忆力衰退。这本书里很多都是工程上很有意思的tips...

阅读全文

网易互娱2017实习生招聘在线笔试第一场

本周五参加了网易互娱2017实习生招聘在线笔试第一场(难倒还有好几场),题目总体上比较基础,一读题就有思路,不过手速快才能写完。 比赛链接 题目1 : ...

阅读全文

欢迎留言