【译】Unity3D Shader 新手教程(16)标签:class style 代码com log 使用src html http 刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步。
该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D 中的表面着色器(Surface Shader)的,为学习更复杂的Shader编程打下基础。
动机如果你是刚刚接触Shader编程的新手,你可能不知道从何开始踏出Shader编程的第一步。
本教程将带你一步步完成一个表面着色器(Surface Shader)和片段着色器(Fragment Shader)。
本教程也将介绍在Unity3D Shader编程中所使用的一些函数和变量,这些内容可能和你在网上看到的不一样哦!如果你满足下面的条件,我觉得你应该看看这篇文章:如果你是shader编程的新手。
你想在你的游戏中使用shader做一些很炫酷的效果,但是你在网上找不到可用的Shader(译者注:o(╯□╰)o自己动手丰衣足食)。
由于缺乏对基础知识的了解,造成不能随心所欲使用Strumpy着色器编辑器(译者注:Strumpy Shader Editor,一种图形化编写shader的方式,看着很诱人!)。
你想在你的shader代码中手动处理纹理(Textures)本文是该系列教程的第一篇文章,随后我们会制作一些更复杂的shader。
相比起来,第一篇文章确实很简单。
关于作者我也是Shader编程的新手----所以我决定写这篇教程帮助大家入门——我当初也在入门上遇到很多苦恼。
事实上我并不是一个Shader编程专家。
当我想了解Shader编程时,我曾反复阅读官方文档,但是我最终发现官方文档讲述的顺序并不适合我学习shader。
所以我觉得我应该写一篇教程,并分享我所学到的知识。
不过写完教程之后,我发现再次阅读官方文档时,觉得明白多了。
尽管本教程中的所有例子都能正常运行,但是我相信肯定有更好shaders实现这些例子。
如果聪明的你对这些例子中的shaders有更好的建议,请在评论区留言!我之所以学习shader编程是因为我需要在我创建的游戏世界中创建些东西,但这个游戏世界创建起来有个麻烦之处,因为它是由不同角色组成的,而我必须创建由多个部分组成的一个统一网格(mesh)。
所以我只能对每个角色使用一次绘制调用(draw call)。
(译者注:完全不知道他在讲什么?所以我把原文放在下面给大家评评理)My reason for getting into shader programming was to build something that I needed for a world populated with an endless array of different characters. I needed to build a combined mesh out of multiple parts so I only have one draw call per character.通过打开和关闭角色的穿衣效果,我使用Megafiers(一个变形插件)修改了角色的基本网格(base meshes)。
其中的困难在于我只有一个纹理(texture),但是我却想给每个角色的皮肤,服饰以及其他的特征使用不同的颜色。
我想到一个方法----对每个角色使用不同的3个4x4纹理,并使用一个shader 来给模型上色。
我将在整个教程中详细描述我做的这个shader,但是现在—我想你们已经迫不及待地想看我创建的角色表演一段即兴的快闪舞(flash mob dance)(译者注:网上截的图片)。
着色器和材质(shaders&materials)一个shader所做的就是将一个模型的网格(mesh)渲染到屏幕上。
Shader可以被定义为一系列的属性(译者注:就像一个函数里面的参数一样,你可以改变函数的不同赋值来改变函数的输出结果),你可以通过改变这些属性来改变模型渲染到屏幕上的效果。
而这些属性被存放起来,放到一个叫做材质(material)的地方。
Unity3D Shader有以下几种表面着色器(surface shader)----后台自动为你做的绝大部分的工作,减少了你工作量,并且适合绝大多数需要shader 的情况。
片段着色器(fragment shader)----可以让你做更多的效果,但是此shader更难写。
你也可以用它做一些底层的工作,比如顶点光照(Vertex lighting,即在每个顶点存储该点的光照信息)。
顶点光照对于移动设备很有用(译者注:估计省内存吧)。
该shader对于一些需要多通道(multiple passes)的高级渲染效果也很有效。
本文中我们将关注点放在表面着色器上。
学习Shader的资源如果你要学习Shader编程,我向你推荐下面几个资源Martin Kraus‘s fantastic Wiki Book GLSLProgramming/UnityUnity‘s Shader ReferenceNVidia‘s tutorial on the CG programming languageCreativeTD‘s video series on writing surface shadersShader的流水化工作方式(译者注:Shader的工作方式也称为shader流水线(pipeline),因为shader工作方式很类似汽车流水线,将模型上一系列顶点数据和其他各种数据作为输入,用这个shader组成的流水线加工下,出来的就成了炫酷的效果了。
)你将在shader流水线中看到不明觉厉的各种术语,我将用我自己的语言尽量降低理解的难度。
Shader的工作就是输入一些3D几何信息,经过shader处理后将其变为2D的像素呈现在屏幕上。
好处是在shader处理过程中,你只需要改变少数几个属性就可以产生不同的效果。
对于表面着色器,该工作流程看起来像下面这样:(译者注:简单讲解一下这个流程图,首先要渲染的物体将自己的几何信息传递到Shader中,并且系统得到了该物体的顶点信息,然后你可以选择经不经过Vertex Function来处理这些顶点信息,随后经过光栅化(将三维几何信息映射到二维屏幕上,打个不恰当的比喻,相当于把3D模型拍扁到屏幕上,然后你就可以专心处理屏幕上的像素了),每个像素经过你的shader代码将得到最终的颜色值)注意在表面着色器(Surface Shader)中的函数退出之前,像素的颜色还没有计算出来。
这意味着你可以再次之前传入顶点的法向量来影响光照的计算。
片段着色器(Fragment Shader)有着同样的工作流程,但事实上,片段着色器中必须有Vertex Function(上图中的Vertex Function部分就是可选的(Optional)),而且需要在像素处理阶段做很多的工作才能产生最终的像素。
而表面着色器隐藏了这些。
(译者注:给我的感觉就是片段着色器向用户提供了更多的接口进行更高级的渲染)。
下图展示了你的代码如何被调用以及代码构成从上图我们可以看到,当你写一个shader的时候,你可能得有一些属性值(properties),并且有一个或多个Subshaders。
具体使用哪个Subshader进行处理取决于你的运行平台。
你应该还要指定一个Fallback shader,当你的subshader没有一个能运行在你的目标设备上,将使用Fallback shader(译者注:有点像备胎)。
每个Subshader都至少有一个通道(pass)作为数据的输入和输出。
你可以使用多个通道(passes)执行不同的操作,比如在一个Grab Pass中,你可以获取将要呈现到屏幕上的像素值(译者注:类似于glsl中的fragment buffer)。
当你想制作高级的扭曲效果,这非常有用。
虽然当你开始学习shader编程时,你可能并不会使用到它。
另外一个使用多通道(multiple passes)的原因是在不同时刻,你可能需要写入或者禁止写入深度缓存的使用。
当你写表面着色器时,我们将直接在Subshader这个层次上写代码,系统将把我们的代码编译成若干个合适的通道(pass)。
尽管shader最终产生的是二维像素,但是其实这些像素除了保存xy坐标外,本身保存着深度值(即每个像素点上的内容在原先3D场景中离照相机的远近),这样距离照相机近的物体就会把距离照相机远的物体遮挡住,在屏幕上显示时,就是将其像素值覆盖。
你可以控制是否在你的shader中使用深度缓存(Z-buffer)产生一些特效,或者在Pass中使用一些指令决定shader是否可以写入Z-buffer:比如使用ZWrite Off时,任何你输出的东西都不会更新Z-buffer的值,即关闭的Z-Buffer的写入功能。
你可以使用Z-buffer技术在别的物体上掏出一个洞,你可以先写入需要打洞区域的深度值,但不输出打洞区域所属的像素值,然后在你模型后面的物体的深度值将无法写入(因为Z-buffer觉得你的模型已经挡住了后面的物体)(译者注:这样你打洞区域显示的就是一开始使用的背景色,会造成一个洞穿过了这些物体的效果)。
下面是一些shader代码:希望你能看出上面代码是由Properties,SubShader,Fallback三段代码组成的。
理解Shader代码文章剩下的部分将讲述上面那段简单代码到底做了什么?真正的干货马上就来了,你必须好好掌握这些内容。
当你进行shader编程时,你必须使用正确的变量名和函数名来调用它们,事实上变量的名称在某些情况下能让人一眼看出它的特定含义。
创建并使用默认Shader(译者注:在详细介绍Shader之前,我们先简单介绍下shader如何使用。
)1. 我们先打开Unity(我的版本是4.6.1),创建新工程,并在Assets文件夹下创建三个目录,如下:2. 我们再创建一个cube。
可以在Inspector面板看到新创建的cube所使用的Material 如下。
3. 打开Material文件夹,我们在其中创建一个Shader和一个Material。
此时New Material的默认Shader为Diffuse。
我们将NewShader拖到New Material上。
可以看到该材质所使用的Shader变成我们新建的NewShader了。
当然你也可以直接点击材质编辑器中Shader下拉框,选择相应的Shader。