• 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质


    本系列文章由@浅墨_毛星云 出品,转载请注明出处。

      

    文章链接: http://hpw123.net/a/C__/kongzhitaichengxu/2014/1110/119.html

    作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442

    邮箱: happylifemxy@163.com 

    很多其它文章尽在:http://www.hpw123.net



    本篇文章中,我们学习了Unity Shader的基本写法框架,以及学习了Shader中Properties(属性)的具体写法,光照、材质与颜色的具体写法。

    写了6个Shader作为本文Shader解说的实战内容,最后创建了一个逼真的暴风雪场景进行了Shader的測试。

    依然是国际惯例先上本文配套程序的截图。

    先是一张远眺图:


    浅墨在场景中放置了一个自己主动旋转的剑阵,瞬间武侠气息爆棚:


    来一张近距离:


    看到银白色的世界漫天飞雪。剑阵列为圈旋转,有没有雪山飞狐的即视感呢?

     

    须要说明的是,因为CSDN的图片上传限制2Mb,这样画质的场景做成GIF上传不了。

    而静态的图片没有动态的表现力。感受不到风雪吹到自己身上的那种刺骨的感觉。所以在这里贴出的图,表现力已经是大打则扣了,而音效和背景音乐更是听不了,表现力就更是不如亲自执行了,所以浅墨推荐感兴趣的同学能够下载此场景的exe自己执行玩耍,赏玩。

    且此场景有些庞大。徒步走预计5分钟才干走到场景边界。

    Please enjoy~

     

    点击这里,下载此“雪山飞狐”场景的exe。

     

    另外提醒。场景unity源文件和源码在末尾提供下载。

    OK,我们正式開始。

     


    一、一些基本概念认知

     


    1.1 Shader和Material的基本概念认知

     

    先引用一段文字,阐述Shader和Material的基本关系:


    Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用。然后输出。

    画图单元能够根据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上相应的Shader。以及对Shader的特定的參数设置,将这些内容(Shader及输入參数)打包存储在一起,得到的就是一个Material(材质)。之后。我们便能够将材质赋予合适的renderer(渲染器)来进行渲染(输出)了。

    所以说Shader并没有什么特别奇妙的,它仅仅是一段规定好输入(颜色,贴图等)和输出(渲染器可以读懂的点和颜色的相应关系)的程序。而Shader开发人员要做的就是依据输入,进行计算变换,产生输出而已。


    这段文字出自猫都能学会的Unity3D Shader入门指南(一)》是比較好的Unity Shader的入门文章,可惜仅仅写了两篇,后面就没有继续了。浅墨在文章开头懒得写了,就讲这句引用了过来。


     

    1.2 背景知识说明


    在这里须要说明,学习Unity中的Shader编程,最好是之前对OpenGL或Direct3D的渲染状态等相关知识有一个主要的了解。假设之前没有太接触过这方面的知识,能够看看浅墨写的DirectX相关的教程。而须要大量恶补提升图形编程功力的童鞋。能够在NVIDIAAMD开发人员站点上能够找一些着色器教程和文档来啃啃。

     

    对于本期的光照和材质,须要的背景知识能够看浅墨之前写的这篇以DirectX为载体的光照和材质导论式的文章:

     

    【Visual C++】游戏开发笔记四十 浅墨DirectX教程之八 绘制真实质感的三维世界:光照与材质专场


    假设对当中的C++&DirectX的代码不太熟悉的话,没关系。看看概念。了解个大概就能够了。


     

    二、 Unity中Shader的三种基本类型

     


    我们知道,计算机图形学的中渲染管线一般能够分为两种类型:

     

    1.固定功能渲染管线(fixed-functionrendering pipelines)

    2.可编程渲染管线(programmablerendering pipelines)


    按这种分类思路。在Unity中,Shader便能够分成例如以下三种基本类型:


    1.固定功能着色器(Fixed Function Shader)

     

    2.表面着色器(Surface Shader)

     

    3.顶点着色器&片段着色器 (Vertex Shader & Fragment Shader)


    顾名思义,当中的固定功能着色器便是我们所说的固定功能渲染管线(fixed-functionrendering pipelines)的详细表现,而表面着色器、顶点着色器以及片段着色器便属于可编程渲染管线。

    以下分别对其进行简单的介绍。



    2.1 关于固定功能着色器


    这里的固定功能着色器能够说是Unity为Shader的书写自带的一层壳,Unity已经在内部为我们做了大量的工作,我们仅仅要略微记住一些keyword、一些规范就能够实现出非常多不错的效果。固定功能着色器是我们初学Unity Shader的近期几篇文章中的主要学习对象。

    而后面的表面着色器、顶点着色器以及片段着色器就是在固定功能着色器的基础上嵌套了CG语言的代码而成的更加复杂的着色器。

    我们来看看他们的一些基本概念。

     


    2.2 关于表面着色器


    表面着色器(Surface Shader)这个概念很多其它的仅仅是在Unity中听说。能够说是Unity自己发扬光大的一项使Shader的书写门槛减少和更易用的技术。我们会在接下来的学习中逐渐意识到Unity是怎样为我们把Shader的复杂性包装起来,使其书写的过程更便捷和易用的。


     

    2.3 关于顶点着色器和片段着色器


    研究过Direct3D和OpenGL着色器编程的童鞋们一定对这两者不陌生。我们来简介一下他们的用途。

    顶点着色器:产生纹理坐标,颜色,点大小。雾坐标。然后把它们传递给裁剪阶段。

    片段着色器:进行纹理查找,决定什么时候运行纹理查找,是否进行纹理查找,及把什么作为纹理坐标



    2.4 怎样区分Unity中的Shader类型


    在Unity中想要区分他们非常easy。后面熟悉了自然知道。

    在这里浅墨先剧透一下:



    • 没有嵌套CG语言,也就是代码段中没有CGPROGARAM和ENDCGkeyword的。就是固定功能着色器。

    • 嵌套了CG语言,代码段中有surf函数的,就是表面着色器。

    • 嵌套了CG语言,代码段中有#pragma vertex name和  #pragma fragment frag声明的,就是顶点着色器&片段着色器。

     

    三、Unity中将Shader赋给Material的两种方法



    在Unity中将Shader赋给Material使用的两种方法。

     

    【方法一】直接将Shader拖拽到Material之上。这样的方法我们上篇文章中已经多次讲到。也就是这样:


     


    【方法二】在Material的Inspector面板中选择。

    Unity中内建的Shader都是通过这样的方式来让Material使用的。

    在Material的Inspector中,其名字下方的Shader栏中选择。能够发现Unity已经为我们准备好了非常多种不同的Shader,基本能够满足居家旅行的需求了。

     

    而对于我们自己新写的Shader,也会在这个菜单条中显示出来。细心的朋友们看上图的时候,肯定就已经发现了。

    这里选择的菜单取决于我们Shader中定义Shader的第一行代码时紧接着Shaderkeyword的引號“”里面的书写方式:


     

    四、Unity 中Shader的基本框架

     


    由于着色器代码能够说专用性很强,因此Shader的设计者人为地规定了它的基本结构。而Unity中Shader总体的框架写法能够用例如以下的形式来概括:

     

    Shader "name" { [Properties] SubShaders[Fallback] }

     

    也就是说,Unity中全部着色器都是由Shaderkeyword開始,随后的字符串表示着色器的名字。这个名字会显示在Inspector检视面板中。全部用于这个着色器的代码必须放置在之后的大括号里:{ }(称为“块”)。ps:该名字应该是短且描写叙述性的文字。

    它并不须要和shader文件名称同样。而想要把着色器增加到Unity的子菜单里,名字须要用斜线(/)。比如:浅墨Shader编程/TheFirstShader就是一个名叫TheFirstShader的着色器。而这个着色器位于“浅墨Shader编程”的子菜单下。

    这样,我们就能够在Shader后面紧跟着的引號中用“/”来构造出子二级甚至多级的子菜单来,方便了后面Shader写多了时候的合理分类,不至于太乱。


    OK,我们继续讲。有图有真相,Shader总体的框架写法用图来说就是这样:


    看图能够知道。首先是一些属性定义。用来指定这段代码将有哪些输入。接下来是一个或者多个的子着色器,在实际执行中,哪一个子着色器被使用是由执行的平台所决定的。子着色器是代码的主体,每个子着色器中包括一个或者多个的Pass。在计算着色时,平台先选择最优先能够使用的着色器。然后依次执行当中的Pass,然后得到输出的结果。最后指定一个Fallback,可译为“回滚”。俗称备胎。用来处理全部SubShader都不能执行的情况(比方目标设备实在太老,全部SubShader中都有其不支持的特性,于是仅仅好用备胎了,不然就显示不出来)。

     

    不同的图形卡有不同的性能,这对游戏开发人员来说是永恒的问题,而这恰恰就是子着色器为什么能够发光发热的原因。若我们开发出了一种使用了当前业界前沿技术构成的Shader,这样的Shader眼下仅仅有百分之1的牛逼哄哄的显卡能够支持。

    比較明智的做法是,把这套採用最前沿技术的Shader作为我们众多SubShader的当中的一员,然后还得准备一堆Plan B。应对其它硬件上的执行。也就是说。我们为所期望的採用最新技术的效果编写一个子着色器,然后为之前古老的显卡再编制一些备用的着色器。

    这些子着色器能选择使用更低层次的方式来实现我们的效果,或者选择放弃实现某些细节。确保不管在什么机器上跑,都可以执行出正确的效果。尽管这些效果会有一些细微的区别,由于使用的SubShader是不一样的,但却保证了我们的Shader在不论什么机器上都跑得起来。

     

    PS:在实际进行表面着色器的开发时,我们就是直接在SubShader这个层次上写代码。系统会将把我们的代码编译成若干个合适的Pass。

     

    用一个实例代码来说明吧。

     

    我们在Project面板中右键->Create->Shader。新建一个Shader文件,然后双击打开,删掉原先代码,分分钟,我们依照上文的解说,对比着图示,就能够写出例如以下框架的Shader代码来:



    Shader "浅墨Shader编程/0.Shader框架演示样例"  
    {  
           //-------------------------------【属性】-----------------------------------------  
           Properties  
           {  
                  //纹理  
                  _MainTex("基本纹理",2D)="White"{TexGen ObjectLinear}       
           }  
       
           //---------------------------------【子着色器1】----------------------------------  
           SubShader  
           {  
                  //----------------通道---------------  
                  Pass  
                  {  
                         //设置纹理为属性中选择的纹理  
                         SetTexture[_MainTex]{combinetexture}  
                  }  
       
           }  
       
           //---------------------------------【备胎】----------------------------------------  
           //备胎设为Unity自带的普通漫反射  
           Fallback" Diffuse "  
    }  


     

    解释起来就是:

     

    1.着色器通过properties来可选的定义一个可通过材质设定界面来自己定义的列表。

    详细到上述代码中写的Properties。就是定义了一个基本属性,參数名叫做_MainTex,在编辑器中显示的名称叫做“基本纹理”。 且纹理生成模式为ObjectLinear。

    2.后面紧跟着核心部分子着色器SubShader。里面的一个Pass里面设置了纹理为我们属性中定义的那个_ MainTex。

    3.加入一句Fallback代码用于应对我们Shader中的SubShader不能正确执行的情况。

     

    须要注意的是,SubShader在UnityShader的代码段中必须有且至少有一个,而properties和fallback对于追求简单的Shader,是能够不写出来的。而复杂一点的Shader,当然各种properties、fallback什么的肯定都有,甚至有多个SubShader,而每一个SubShader中又有多个Pass。

     

    这个框架程序我们后面写新的Shader的时候就能够直接复制然后粘贴,接着在Properties中加入新的属性,SubShader中填充新的Pass以及开辟新的SubShader即可。就像做填空题一样。

     

    #p#分页标题#e#

     

    五、Properties 属性相关内容解说

     

    以下,我们具体地来看一看作为Shader框架中三大组成部分之中的一个的Properties属性的相关内容。

    properties一般定义在着色器的起始部分。我们能够在Shader书写的时候定义多种多样的属性,而使用Shader的时候能够直接在材质检视面板(Material Inspector)里编辑这些属性,取不同的值或者纹理。这能够说是Unity贴心&可见即所得的又一体现吧。

    以Unity自带的BasicVertex Lighting 基本顶点光照为例,一张非常直观的图就是这样:


    须要注意。Properties块内的语法都是单行的。

    每一个属性都是由内部名称開始,后面括号里是显示在检视面板(Inspector)中的名字和该属性的类型。等号后边跟的是默认值。

     

    5.1 Properties属性 相关代码写法列举


    这一小节我们列举Unity中Shader的Properties属性相关语法參考,能够在须要时进行查阅:



    Properties { Property [Property ...] }

    定义属性块,当中可包括多个属性,其定义例如以下:


    name ("display name", Range (min, max)) =number

    定义浮点数属性,在检视器中可通过一个标注最大最小值的滑条来改动。


    name ("display name", Color) =(number,number,number,number)

    定义颜色属性


    name ("display name", 2D) = "name" {options }

    定义2D纹理属性


    name ("display name", Rect) = "name"{ options }

    定义长方形(非2次方)纹理属性


    name ("display name", Cube) = "name"{ options }

    定义立方贴图纹理属性


    name ("display name", Float) = number

    定义浮点数属性


    name ("display name", Vector) =(number,number,number,number)

    定义一个四元素的容器(相当于Vector4)属性

     

     

    5.2 一些细节说明


    • 包括在着色器中的每个属性通过name索引(在Unity中, 通常使用下划线来開始一个着色器属性的名字)。属性会将display name显示在材质检视器中,还能够通过在等符号后为每个属性提供缺省值。

    • 对于Range和Float类型的属性仅仅能是单精度值。
    • 对于Color和Vector类型的属性将包括4个由括号围住的数描写叙述。
    • 对于纹理(2D, Rect, Cube) 缺省值既能够是一个空字符串也能够是某个内置的缺省纹理:"white", "black", "gray" or"bump"
    • 随后在着色器中,属性值通过[name]来訪问。


    接着,让我们看一个演示样例,了解属性Properties的实际使用方法

     


    Shader "浅墨Shader编程/SimpleWater"  
    {  
           Properties{  
                  //properties for water shader  
                  //水着色器的属性  
                  _WaveScale("Wave scale", Range (0.02,0.15)) = 0.07 // 滑动条  
                  _ReflDistort("Reflection distort", Range (0,1.5)) = 0.5  
                  _RefrDistort("Refraction distort", Range (0,1.5)) = 0.4  
                  _RefrColor("Refraction color", Color)  =(.34, .85, .92, 1) // 颜色  
                  _ReflectionTex("Environment Reflection", 2D) = "" {} // 纹理  
                  _RefractionTex("Environment Refraction", 2D) = "" {}  
                  _Fresnel("Fresnel (A) ", 2D) = "" {}  
                  _BumpMap("Bumpmap (RGB) ", 2D) = "" {}  
           }  
     //兴许代码省略  
    ………  
       
    }  


     

    5.3 关于纹理属性选项


    纹理属性在本文的第一个演示样例中就实用到,这里先再贴一遍2D纹理属性的写法:

     

    name ("display name", 2D) ="name" { options }

     

    须要注意的是,包括在纹理属性的大括号里的选项Options是可选的。可能的选项有例如以下:

     

    TexGen纹理生成类型。纹理的自己主动生成纹理坐标时的模式,能够是ObjectLinear, EyeLinear,SphereMap, CubeReflect, CubeNormal的当中之中的一个;这些模式和OpenGL纹理生成模式相相应。注意假设使用自己定义顶点程序。那么纹理生成将被忽略。

     

    LightmapMode 光照贴图模式

    假设我们给出这个选项。纹理将能被渲染器的光线贴图属性所影响。

    纹理不能被使用在材质中,而是取自渲染器的设定。

    这个我们以后会讲到。

     

     

    六、光照、材质与颜色相关内容解说

     

    灯光和材质參数经常被用来控制内置的顶点光照。

    而Unity中的顶点光照也就是Direct3D/OpenGL标准的按每顶点计算的光照模型—— 光照打开时。光照受材质块。颜色材质和平行高光命令的影响。

     

     

    我们来一起看一看光照、材质与颜色详细的语法。

     

    这里讲到的都是採用固定功能渲染的代码写法。以及一些控制选项。

    讲得有些细了,不用一次全记住,须要的时候回过头来进行查阅即可了。

     

     

    6.1 用于通道Pass中的代码写法列举


    这些代码通常是写在Pass{ }中的,细节例如以下:

     

    Color Color

    设定对象的纯色。颜色即能够是括号里的四值(RGBA)。也能够是被方框包围的颜色属性名。

     

    Material { Material Block }

    材质块被用于定义对象的材质属性。

     

    Lighting On | Off

    开启光照,也就是定义材质块中的设定是否有效。

    想要有效的话必须使用Lighting On命令开启光照,而颜色则通过Color命令直接给出。

     

    SeparateSpecular On | Off

    开启独立镜面反射。这个命令会加入高光光照到着色器通道的末尾。因此贴图对高光没有影响。

    仅仅在光照开启时有效。

     

    ColorMaterial AmbientAndDiffuse | Emission

    使用每顶点的颜色替代材质中的颜色集。AmbientAndDiffuse 替代材质的阴影光和漫反射值;Emission 替代 材质中的光发射值。

     

     

    6.2 材质块Material Block 中相关代码写法列举

     

    例如以下这些代码的使用的地方是在SubShader中的一个Pass{ }中新开一个Material{ }块,在这个Material{ }块中进行这些语句的书写。这些代码包括了包括材质怎样和光线产生作用的一些设置。

    这些属性默觉得值都被设定为黑色(也就是说不产生作用),也就是说他们普通情况下能够被忽略。当然,还是有非常多时候须要使用到他们的。

     

    Diffuse Color(R,G,B,A)

    漫反射颜色构成。这是对象的基本颜色。

     

    Ambient Color(R,G,B,A)

    环境色颜色构成.这是当对象被RenderSettings.中设定的环境色所照耀时对象所表现的颜色。

     

    Specular Color(R,G,B,A)

    对象反射高光的颜色。(R,G,B,A)四个分量分别代表红绿蓝和Alpha,取值为0到1之间。

     

    Shininess Number

    加亮时的光泽度,在0和1之间。

    0的时候你会发现更大的高亮也看起来像漫反射光照,1的时候你会获得一个细微的亮斑。

     

    Emission Color

    自发光颜色,也就是当不被不论什么光照所照到时,对象的颜色。(R,G,B,A)四个分量分别代表红绿蓝和Alpha,取值为0到1之间。


     

    而打在对象上的完整光照颜色终于是:

     

     FinalColor=

    Ambient * RenderSettings ambientsetting + (Light Color * Diffuse + Light Color *Specular) + Emission


     

    翻译过来的中文式子便是:

     

    终于颜色=环境光反射颜色* 渲染设置环境设置 *(灯光颜色*漫反射颜色+灯光颜色*镜面反射颜色)+自发光

     

    知道了这个式子,我们就知道了。在各种光的综合作用下。我们材质终于的颜色是怎么来的了。

    须要注意的是:方程式的灯光部分(也就是带括号的部分)对全部打在对象上的光线都是反复使用的。

    而我们在写Shader的时候经常会将漫反射和环境光光保持一致(全部内置Unity着色器都是如此)。

     

    七、Shader书写实战


    上面讲了一堆一堆的概念。预计大家一遍看下来头都大了。

    没关系。让我们看一些演示样例Shader的写法。弄清楚上面这一堆堆的概念是怎样应用的。

     

    1.单色Shader


    首先。用上文讲到的Color命令,写出一个有效代码只四行的袖珍Shader:


    Shader"浅墨Shader编程/1.基础单色"  
    {  
        //---------------------------------【子着色器】----------------------------------  
        SubShader  
        {  
            //----------------通道---------------  
            Pass  
            {  
                //设为蓝色单色  
                Color(0,0,0.6,0)  
            }  
        }  
    }  



    此Shader编译后赋给材质的效果例如以下:


     10

     

    2.材质颜色&开启光照的Shader


    相同的,我们能够在Pass中加上材质块Material,在当中将将材质的漫反射和环境光反射颜色设为相同,而且在该Pass中开启光照:



    Shader"浅墨Shader编程/2.材质颜色设置&开启光照"  
    {  
        //---------------------------------【子着色器1】----------------------------------  
        SubShader  
        {     
            //----------------通道---------------  
            Pass  
            {  
                //----------材质------------  
                Material  
                {  
                    //将漫反射和环境光反射颜色设为同样  
                    Diffuse(0.9,0.5,0.4,1)  
                    Ambient(0.9,0.5,0.4,1)  
                }  
                //开启光照  
                Lighting On  
            }  
        }  
    }  



    此Shader编译后赋给材质的效果例如以下:


    3.可调漫反射光的Shader


    在上面Shader的基础上,我们引入一个color属性,于是就得到了例如以下可调漫反射光颜色的Shader:

     


    Shader "浅墨Shader编程/3.简单的可调漫反射光照"  
     {  
        //-------------------------------【属性】-----------------------------------------  
        Properties   
        {  
            _MainColor ("主颜色", Color) = (1,.1,.5,1)  
          
        }  
      
        //---------------------------------【子着色器】----------------------------------  
        SubShader   
        {  
            //----------------通道---------------  
            Pass   
            {  
                //-----------材质------------  
                Material   
                {  
                    //可调节的漫反射光和环境光反射颜色  
                    Diffuse [_MainColor]  
                    Ambient[_MainColor]  
                }  
                Lighting On  
            }  
        }  
    }  



    此Shader编译后赋给材质的效果例如以下:


    4.光照材质完备beta版Shader

     

     我们把余下的Material属性补上,便有了此光照材质完备beta版的shader:

     

    Shader "浅墨Shader编程/4.光照材质完备beta版Shader"   
    {  
        //-------------------------------【属性】-----------------------------------------  
        Properties  
        {  
            _Color ("主颜色", Color) = (1,1,1,0)  
            _SpecColor ("反射高光颜色", Color) = (1,1,1,1)  
            _Emission ("自发光颜色", Color) = (0,0,0,0)  
            _Shininess ("光泽度", Range (0.01, 1)) = 0.7  
        }  
      
        //---------------------------------【子着色器】----------------------------------  
        SubShader   
        {  
            //----------------通道---------------  
            Pass   
            {  
                //-----------材质------------  
                Material   
                {  
                    //可调节的漫反射光和环境光反射颜色  
                    Diffuse [_Color]  
                    Ambient [_Color]  
                    //光泽度  
                    Shininess [_Shininess]  
                    //高光颜色  
                    Specular [_SpecColor]  
                    //自发光颜色  
                    Emission [_Emission]  
                }  
                //开启光照  
                Lighting On  
            }  
        }  
    }  



    此Shader编译后赋给材质的效果例如以下。能够自由定制的选项多了不少:

     

    5.简单的纹理加载Shader

     

    然后我们看一个简单的纹理加载Shader的写法:

     


    Shader "浅墨Shader编程/5.简单的纹理加载Shader"  
    {  
           //-------------------------------【属性】-----------------------------------------  
           Properties  
           {  
                  //纹理  
                  _MainTex("基本纹理",2D)="White"{TexGen SphereMap}  
           }  
           //---------------------------------【子着色器1】----------------------------------  
           SubShader  
           {  
                  //----------------通道---------------  
                  Pass  
                  {  
                         //设置纹理为属性中选择的纹理  
                         SetTexture[_MainTex]{combinetexture}  
                  }  
           }  
           //---------------------------------【备胎】----------------------------------------  
           //备胎设为Unity自带的普通漫反射  
           Fallback" Diffuse "  
    } 



    此Shader编译后赋给材质的效果例如以下:

     

    须要注意,这里用到了一点纹理生成的内容,详细使用方法我们下次再细讲。


    6.光照材质完备正式版Shader


    结合Shader4 beta版的光照材质Shader和Shader5简单的纹理加载,我们写成了这篇文章的终于版Shader:

     


    Shader "浅墨Shader编程/6.光照材质完备正式版Shader"   
    {  
        //-------------------------------【属性】-----------------------------------------  
        Properties   
        {  
            _Color ("主颜色", Color) = (1,1,1,0)  
            _SpecColor ("高光颜色", Color) = (1,1,1,1)  
            _Emission ("自发光颜色", Color) = (0,0,0,0)  
            _Shininess ("光泽度", Range (0.01, 1)) = 0.7  
            _MainTex ("基本纹理", 2D) = "white" {}  
        }  
      
        //--------------------------------【子着色器】--------------------------------  
        SubShader  
        {  
            //----------------通道---------------  
            Pass  
            {  
                //-----------材质------------  
                Material  
                {  
                    //可调节的漫反射光和环境光反射颜色  
                    Diffuse [_Color]  
                    Ambient [_Color]  
                    //光泽度  
                    Shininess [_Shininess]  
                    //高光颜色  
                    Specular [_SpecColor]  
                    //自发光颜色  
                    Emission [_Emission]  
                }  
                //开启光照  
                Lighting On  
                //开启独立镜面反射  
                SeparateSpecular On  
                //设置纹理并进行纹理混合  
                SetTexture [_MainTex]   
                {  
                    Combine texture * primary DOUBLE, texture * primary  
                }  
            }  
        }  
    }   



    当中。涉及到了纹理混合的知识,我们稍后会解说。

    此Shader编译后赋给材质的效果例如以下,能够发现,在这么多的可定制选项下,我们能够自由调节出自己喜欢的材质效果来:

     

    自由调节出各种诡异的材质:



    OK,很多其它的材质效果图就不放出了,大家下载文章末尾处提供的源project,然后找到这个Shader自己调着玩吧。本文中全部的Shader和Material都位于Shaders目录中:

    #p#分页标题#e#


     

    八、QianMo’s Toolkit升级到v1.1版

     

    上次公布QianMo’s Toolkit v1.0之后,发现有一些能够改进的地方,以及一些新功能,于是就花了点时间将Tookit更新了一下,写了一点新功能。升级到了v1.1。


    8.1 QianMo’s Toolkit v1.1版修改说明:


    1.新增加工具SetMaxFPS  用于突破Unity每秒渲染 60帧的设定,自由设置最大帧率。

    2.新增加工具ShowObjectInfoInGamePlay,用于公布游戏之后显示文本信息。之前的ShowObjectInfo仅能在Unity測试过程中显示文本信息。

    3.修复导入后的警告提示“Someare Mac OS X (UNIX) and some are Windows.”

     

    8.2 QianMo’s Toolkit v1.1版包括内容:

     

    ShowFPS:在游戏执行时显示帧率相关信息

    ShowObjectInfo:在測试过程里,于场景中和游戏窗体中分别显示加入给随意物体文字标签信息。隐藏和显示可选,基于公告板技术实现。

    ShowGameInfo:在游戏执行时显示GUI相关说明

    ShowLogo:在游戏执行时显示Logo

    ShowUI:在游戏执行时显示简单的镶边UI。

    SetMaxFPS :用于突破Unity每秒渲染 60帧的设定,自由设置最大帧率。

    ShowObjectInfoInGamePlay:用于公布游戏之后显示文本信息。

     


    点击这里单独下载QianMo’s Toolkit v1.1:


    QianMo’s Toolkit v1.1.unitypackage下载】  

     


    8.3 设置Unity中最大帧率的写法

     

    最好还是在这里贴一下设置最大帧率的代码,便须要的朋友參考:



    //-----------------------------------------------【脚本说明】-------------------------------------------------------  
    //      脚本功能:   设置在游戏执行时可达到的最大帧率  
    //      使用语言:   C#  
    //      开发所用IDE版本号:Unity4.5 06f 、Visual Studio 2010      
    //      2014年11月 Created by 浅墨      
    //      很多其它内容或交流。请訪问浅墨的博客:http://blog.csdn.net/poem_qianmo  
    //---------------------------------------------------------------------------------------------------------------------  
      
    //-----------------------------------------------【用法】-------------------------------------------------------  
    //      第一步:在Unity中拖拽此脚本到场景随意物体上。或在Inspector中[Add Component]->[浅墨's Toolkit v1.1]->[SetMaxFPS]  
    //      第二步:在面板中设置MaxFPSValue參数为须要的帧率值。以及其它參数  
    //---------------------------------------------------------------------------------------------------------------------  
    using UnityEngine;  
    using System.Collections;  
      
    //垂直同步数  
    public enum VSyncCountSetting  
    {  
        DontSync,  
        EveryVBlank,  
        EverSecondVBlank  
    }  
      
      
    [AddComponentMenu("浅墨's Toolkit v1.1/SetMaxFPS")]  
    public class SetMaxFPS : MonoBehaviour  
    {  
      
        public VSyncCountSetting VSyncCount = VSyncCountSetting.DontSync;//用于快捷设置Unity Quanity设置中的垂直同步相关參数  
        public bool MaxNoLimit = false;//不设限制。保持可达到的最高帧率  
        public int MaxFPSValue = 80;//帧率的值  
      
      
      
        void Awake()  
        {  
            //设置垂直同步相关參数  
            switch (VSyncCount)  
            {  
                //默认设置。不等待垂直同步,能够获取更高的帧率数  
                case VSyncCountSetting.DontSync:  
                    QualitySettings.vSyncCount = 0;  
                break;  
      
                //EveryVBlank,相当于帧率设为最大60  
                case VSyncCountSetting.EveryVBlank:  
                QualitySettings.vSyncCount = 1;  
                break;  
                //EverSecondVBlank情况,相当于帧率设为最大30  
                case VSyncCountSetting.EverSecondVBlank:  
                QualitySettings.vSyncCount = 2;  
                break;  
      
            }  
      
            //设置没有帧率限制。火力全开!

    if (MaxNoLimit) { Application.targetFrameRate = -1; } //设置帧率的值 else { Application.targetFrameRate = MaxFPSValue - 1; } } }



    拖动此脚本到场景的随意物体上。在Inspector新出现的这个脚本选项的Max FPS Value中填上自己期望的最大帧率即可了。前提是你的电脑有能力跑到这么高的帧数。或者直接勾上 Max No Limit的勾勾。便能够让你的电脑火力全开,用最高性能来跑出最大的帧率。

     

    九、终于游戏场景效果演示——雪山飞狐

     

    上一次中我们处于炎热的夏威夷群岛之中,这次的场景,最好还是让我们来到寒冷的冬季。领略刺骨的寒风。

    以大师级美工鬼斧神工的场景作品为基础,浅墨优化和压缩了此场景资源的尺寸。增加了音乐和音效,并改动了场景布局,增加了很多其它特效,于是便得到了如此这次让人颇显震撼的暴风雪场景。

    逼真的音效和暴风雪特效,让我们身临其境:



    浅墨在场景中放置了一个自己主动旋转的剑阵,瞬间武侠气息爆棚:

     

    有没有要想要随便拿一把兵器,跃跃欲试:

     

    我们将一些今天写的这些材质Shader运用到这些剑之上看看效果:



    最后,放一张今天学的Shader的全家福:

     

    本篇文章的演示样例程序请点击此处下载:

     

    【浅墨Unity3D Shader编程】之二 雪山飞狐篇配套Unityproject下载

     

     

     


    今天的文章到这里就基本结束了。这篇的内容算是许多。信息量是很大的。希望大家戒骄戒躁,看不懂的地方多看几遍。不用怕。Shader学起来事实上很easy。



    新的游戏编程之旅正在继续,下周一。我们不见不散。


  • 相关阅读:
    SHELL种类,版本及选择
    delete
    ctrl+alt+l:linux 锁屏 win+l:windows锁屏
    inux关于readlink函数获取运行路径的小程序
    网络版shell之网络编程练习篇--telnet服务端
    CentOS 6.5配置nfs服务
    linux操作系下RAR的使用
    BLOB二进制对象(blob.c/h)
    循环队列
    java的System.getProperty()方法能够获取的值
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/6862101.html
Copyright © 2020-2023  润新知