Cocos2D-X3.X3D图形学渲染技术讲解(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-14 05:04:56

点击下载

作者:姜雪伟

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Cocos2D-X3.X3D图形学渲染技术讲解

Cocos2D-X3.X3D图形学渲染技术讲解试读:

内容简介

本书主要介绍Cocos2D-X 3.X以上版本使用的3D图形学渲染技术,以及关于3D引擎的架构和模型加密等,全书共分12章,主要内容包括可编程流水线、OpenGL编程、矩阵变换算法、3D坐标系统、包围盒算法、3D架构设计、3D特效、Shader渲染、3D模型渲染、引擎的滤镜渲染、3D骨骼动画、3D模型加密。

本书重点介绍3D引擎架构设计、Shader渲染、3D特效、3D模型渲染算法及模型骨骼动画。第12章介绍了3D模型加密算法,在游戏开发中对模型加密是必须要实现的。

本书适合具备一定游戏开发经验的初学者和3D项目开发经验的游戏开发者阅读。前言PREFACE

当今,网络游戏和VR虚拟现实得到了蓬勃发展,越来越多的IT从业者加入到这个行业中。在2D游戏开发领域,Cocos2D引擎已占据大半江山,而3D领域几乎已被Unity全部占领,Cocos2D-X引擎在3D开发方面的投入明显不足,到现在3D引擎版本也只是个半成品,配套的编辑器还没有制作,如果想用它开发3D游戏,限制还是很大的。但Cocos2D最大的优势是代码开源,而且代码量相对来说比较小,对于想学习3D游戏开发的爱好者来说是一个优势。开发者可以在此基础上进行功能扩展,实用性非常强。它不像UE4引擎那样代码量很大,初学者不易学习,而且在移动端包体非常大,这也是UE4引擎的一个劣势,而Unity的包体相对Cocos2D包体也是比较大的,代码不开源,所以Cocos2D引擎的3D模块还是值得开发者学习和借鉴的。随着时间的推移,Cocos2D中的3D模块肯定会独立于Cocos2D成为真正的3D引擎,因此开发者现在学习非常及时。

Cocos2D-X在2D领域的参考资料非常多,有针对性的书籍也很多,但是关于Cocos2D在3D开发方面的书籍市面上还没有。本书并不是介绍Cocos2D的基础知识以及安装步骤的,而是针对Cocos2D中的3D模块进行讲解:包括GPU编程、3D模型、3D模型骨骼动画、3D模型材质渲染、3D模型加密等核心技术。衡量3D引擎最重要的指标就是渲染,本书围绕3D渲染进行讲解,对学习3D游戏开发的从业人员非常有帮助。

很多以前从事2D游戏开发的人员也在转向3D游戏开发,但是他们对3D的知识了解得比较少,经验就更无从谈起了。他们对学习3D知识非常渴望,就笔者的了解,他们也学习过许多关于3D方面知识的书,但是在技能方面提升不明显,笔者曾经也迷茫,不知道该如何学习才能快速提高自己的技能。经过多年的研发积累,笔者通过编写此书帮助初学者快速提升3D技能,借助Cocos2D中的3D模块给想从事3D项目开发的人员介绍关于3D模块的开发,书中知识点并没有做到面面俱到,但都是最实用的技术,可以直接应用到项目开发中。

任何跨平台3D引擎的渲染都是基于OpenGL库实现的,它们的底层都是对OpenGL的封装,通过对Cocos2D引擎中3D模块的剖析,让学习者更容易掌握3D渲染技术。尤其对于GPU编程,很多人对编写Shader望而却步,其实如果真正明白其实现原理,掌握起来并没有想象的那么难。本书针对开发者所关心的3D问题逐一讲解,用通俗的语言结合实际案例让读者真正明白3D渲染技术,本书在讲解中会将图形学算法运用到Shader编程中,最终实现非常绚丽的效果。

本书由姜雪伟著,参与本书编写的还有张燕华、姜翠香、吕凤珍、姜瑞庆、张晓宾、朱晓磊和张兴华,在此一并表示感谢。

关于本书的代码,读者可以登录华信教育资源网(http://www.hxedu.com.cn)免费注册后再进行下载。著 者第1章 可编程流水线

现今,可编程流水线已经深深地在3D引擎上打下了烙印,目前市面上大部分3D引擎都是基于可编程流水线开发的,也就是用GPU编程开发。提到可编程流水线,就不得不提固定流水线,其实它们的目的是一样的,就是把游戏虚拟场景在屏幕上显示出来,只是它们中间的处理过程是不同的。固定流水线通过名字可以看出它是按照固定的流程绘制出物体的,详情可查看笔者已出版的书籍《手把手教你架构3D游戏引擎》一书,在书里有对固定流水线的详细讲解,以及用固定流水线实现了一个比较弱小的3D游戏引擎。本章重点介绍的是可编程流水线,通过字面意思知道它是“可变”的流水线,意味着它的矩阵计算并不是在CPU中计算得到的,而是通过GPU编程多线程实现的。下面结合可编程流水线流程图,介绍可编程流水线的原理,可编程流水线流程图如图1-1所示。图1-1 可编程流水线流程图

在图1-1中,茶壶模型是美术人员利用Max工具建造的模型,将模型的顶点传输到GPU中的顶点着色器中,进行矩阵变换,并且通过光栅化插值操作,将计算的结果传输到片段着色器中绘制,最终将其输出到手机屏幕上,这整个流程就是可编程流水线。矩阵的变换操作都是在顶点着色器中进行的,为了帮助读者更好地理解可编程流水线,把固定流水线流程图给读者展示出来,如图1-2所示。

该图展示的是固定流水线,之所以称为“固定”,是因为模型在屏幕上显示的过程必须要经历这些固定的操作步骤。可变流水线把矩阵的换算放到GPU中进行了,从而把CPU解放出来,优化了运算效率。图1-2 固定流水线1.1 GPU功能介绍

GPU(英文全称:Graphics Processing Unit)是嵌入在显卡的芯片处理器,是专门用于处理顶点着色器和片段着色器的。关于顶点着色器和片段着色器会在后面章节中讲解。以前计算机显卡没有GPU芯片时,大部分游戏都是基于2D游戏或像素游戏开发的,效果可想而知。随着硬件的飞速发展,显卡具有了自己的芯片处理器GPU,3D游戏引擎强大的渲染功能也随之发展起来,3D游戏中各种绚丽多彩的效果都是通过GPU编程实现的。比如,玩家常说的次世代网络游戏渲染效果,充分利用了GPU的渲染功能,它非常适合对游戏的模型材质渲染和游戏的场景渲染,游戏场景的渲染被称为后处理,这些效果包括:Bloom效果、Blur效果、SSAO效果、PSSM效果、HDR效果等。

不论在PC端还是在移动端,都可以利用GPU编程渲染出好的效果,引擎中最能体现GPU强大功能的渲染效果,比如海水的反射、折射、高光效果,笔者在自己研发的项目中已实现过,如图1-3所示。图1-3 海水的反射、折射效果

下面是笔者利用Cocos2D-X引擎中的3D渲染模块实现的模型材质渲染,模型的材质含有高光、法线、反射效果,如图1-4所示。图1-4 含有高光、法线渲染效果图

另外,利用Cocos2D-X引擎中的3D模块实现的高光、法线、环境映射效果如图1-5所示。图1-5 高光、法线、环境映射效果

无论是利用商业还是开源3D游戏引擎,通过GPU编程都可以实现比较绚丽的效果。GPU的渲染功能还是非常强大的,图1-4和图1-5实现的Shader渲染效果在后面章节中会给读者介绍。1.2 GPU编程语言

GPU功能在模型材质渲染方面这么强大,那如何才能实现材质的渲染,或者说是GPU是如何工作的?这就要从GPU的编程语言说起,GPU的编程语言出现了三个派系,传统的图形学领域内使用的GPU编程语言有:基于OpenGL的GLSL、基于DirectX的HLSL,还有Nvidia公司的CG。由于目前移动端硬件的快速发展,越来越多的产品在移动端运行,在GPU渲染方面也要求具有跨平台编程的GPU语言,跨平台的GPU语言就是OpenGL图形库使用的GLSL语言,它也是市面上各个跨平台引擎使用最多的GPU编程语言。

对于初学者来说,一提到Shader编程都有种望而生畏的感觉,或者说不知道如何下手,其实GPU说白了只是一种脚本语言,这种脚本语言类似于C语言的语法;另外,在GPU编程中使用了顶点着色器和片段着色器,其中在顶点着色器编程中使用了大量的矩阵计算,对于矩阵之间换算不清楚的读者,可以学习一下大学的《线性代数》课程,结合着固定流水线学习效果更佳。作为学习GPU编程的初学者来说,要想快速地学习GPU编程,笔者推荐先学习GLSL编程语言,因其结构类似于C语言,更容易上手。GLSL底层是用C语言实现的,GLSL着色器代码主要分为两部分:VertexShader(顶点着色器)和Fragment(片段着色器),有时也会在代码中看到Geometry Shader(几何着色器)。掌握了GLSL语言的编写,就可以很轻松地进行各种跨平台引擎的材质渲染和场景渲染。脚本语言都是相通的,CG语言和HLSL语言的语法跟GLSL类似,下面会通过案例让大家认识GLSL编程语言。1.3 GPU编程案例

目前在移动端游戏开发中,大部分引擎的渲染都是用GLSL编写脚本语言。GLSL是为图形算法量身定制的,先介绍GLSL编写着色器的内容:在着色器文件的第一行一般要写版本声明,接着是用uniform定义的输入和输出变量,以及主函数main的实现。每个着色器的入口点都是main函数,这跟C语言很类似。在main函数中处理所有的输入变量,并将结果传输给片段着色器。如果你不知道什么是uniform也不用担心,在后面的章节中会进行讲解。下面以顶点着色器代码和片段着色器代码为例,给大家介绍一下OpenGL中的GLSL脚本的顶点着色器代码编写,如下所示:

//position变量的属性位置值为0

layout(location=0)in vec3 position;

//为片段着色器指定一个颜色输出

out vec4 vertexColor;

void main()

{

//注意如何把一个vec3作为vec4的构造器的参数

gl_Position=vec4(position,1.0);

//把输出变量设置为暗红色

vertexColor=vec4(0.5f,0.0f,0.0f,1.0f);

}

与顶点着色器对应的是片段着色器代码,如下所示:

下面再把代码给读者解释一下,以上代码也是最基本的Shader编程脚本。在顶点着色器中声明了一个vertexColor变量作为vec4输出,并在片段着色器中声明了一个与顶点着色器相同的变量vertexColor,用于接收顶点着色器计算的数值,从而让片段着色器中的vertexColor和顶点着色器中的vertexColor链接起来,从顶点着色器成功地向片段着色器发送数据,这就是顶点着色器和片段着色器成对出现的原因,因为二者是互相关联的。

uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。其次,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。将上面的代码修改成uniform修饰的变量,修改后的片段着色器代码如下:

在片段着色器中声明了一个uniform vec4的ourColor,并把片段着色器的输出颜色设置为uniform值的内容,因为uniform是全局变量,可以在任何着色器中定义它们,而无须通过顶点着色器作为中介。顶点着色器中不需要这个uniform,所以不用在那里定义它。已在Shader中定义的参数需要通过C++代码将参数传递给它,在C++中的代码需要调用OpenGL库的接口函数,如下所示:

GLfloattimeValue=glfwGetTime();

GLfloatgreenValue=(sin(timeValue)/2)+0.5;

GLintvertexColorLocation=glGetUniformLocation(shaderProgram,"ourColor");

glUseProgram(shaderProgram);

glUniform4f(vertexColorLocation,0.0f,greenValue,0.0f,1.0f);

再把上面函数代码段给读者解释一下:代码段中通过glfwGetTime函数获取运行的秒数,然后使用sin函数让颜色在0.0~1.0之间变换,最后将结果存储到greenValue里。

接着,用glGetUniformLocation函数查询uniform ourColor的位置值,为查询函数提供着色器程序和uniform的名字(这是希望获得的位置值的来源)。如果glGetUniformLocation函数返回-1,则表示没有在着色器中找到这个位置值。否则,通过glUniform4f函数设置uniform的值。注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform声明的变量之前你必须先使用程序(调用glUseProgram),因为它是激活着色器脚本的。小结

GPU编程也称为图形学编程,在程序优化、程序加速方面应用得比较多,因为GPU本身是多线程运行的,所以在Shader编程中,一般不要使用if else、for、while等条件判断或循环语句,这样不利于GPU的多线程运行,因为这些条件语句会打断程序的流畅运行,这是编写Shader代码时应该注意的问题。下面再说一下编程时的具体问题,如果你声明了一个uniform变量,却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误。另外,OpenGL在其核心是一个C库,所以它不支持类型重载,在函数参数不同时就要为其定义新的函数。学习GLSL编程先从其语法入手,至少保证能看懂其他人编写的代码,这样自己才能在别人编写的基础上做出修改,更进一步自己能够编写GLSL语言脚本。第2章 OpenGL 编程

市面上,跨平台引擎使用的底层图形库都是OpenGL,很多人认为OpenGL是一个API(Application Programming Interface,应用程序编程接口),因为它包含了一系列操作图形、图像的函数。实际上,OpenGL本身并不是一个API,它是一个由Khronos组织制定并维护的规范。OpenGL规范规定了库中的每个函数如何执行,以及它们的输出值。本书介绍的OpenGL面向OpenGL3.3以上的版本。2.1 OpenGL库介绍

OpenGL库是用C语言编写的,同时也支持多种语言的派生,但其内核仍是一个C库。由于C的一些语言结构不易被翻译到其他的高级语言,因此OpenGL开发的时候引入了一些抽象层。“对象(Object)”就是其中的一个。

在OpenGL中一个对象是指一些选项的集合,它代表OpenGL状态的一个子集。例如,可以用一个对象来代表绘图窗口的设置,之后就可以设置它的大小、支持的颜色位数等。可以把对象看作一个C风格的结构体(Struct):

使用OpenGL时,建议使用OpenGL定义的基元类型。例如使用float时会加上前缀GL(因此写作GLfloat)、int写成GLInt等。下面通过一段代码介绍如何理解OpenGL中的对象概念,如下所示:

//创建对象

GLuint objectId=0;

glGenObject(1,&objectId);

//绑定对象至上下文

glBindObject(GL_WINDOW_TARGET,objectId);

//设置当前绑定到GL_WINDOW_TARGET的对象的一些选项

glSetObjectOption(GL_WINDOW_TARGET,GL_OPTION_WINDOW_WIDTH,800);

glSetObjectOption(GL_WINDOW_TARGET,GL_OPTION_WINDOW_HEIGHT,600);

//将上下文对象设回默认

glBindObject(GL_WINDOW_TARGET,0);

给大家解释一下代码含义:这一小段代码展现了使用OpenGL编写代码时常见的工作流。首先需要创建一个对象,然后用一个id保存它的引用(实际数据被存储在后台),然后将对象绑定至上下文的目标位置(实例中窗口对象目标的位置被定义成GL_WINDOW_TARGET)。接下来设置窗口的选项,最后将目标位置的对象id设回0,从而解绑这个对象。设置的选项将被保存在objectId所引用的对象中,一旦重新绑定这个对象到GL_WINDOW_TARGET位置,这些选项就会重新生效。如下语句:

glBindObject(GL_WINDOW_TARGET,objectId);

函数的功能是绑定对象至上下文,OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行,OpenGL的状态通常被称为OpenGL上下文(Context)。换句话说,就是当更改OpenGL状态,比如设置某些选项后,用OpenGL上下文来渲染。下面再介绍一下在OpenGL的Shader编程中经常使用的着色器。2.2 着色器介绍

着色器是使用一种叫作GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的特性。

着色器中定义了输入变量和输出变量:uniform、varying、attribute及main函数编写。每个着色器的入口点都是main函数,在这个函数中处理所有的输入变量,并将结果输出到已定义的输出变量中。

着色器是各自独立的小程序,它们都是一个整体的一部分,每个着色器都有输入和输出,这样才能进行数据交流和传递。GLSL定义了in和out关键字专门来实现这个目的,每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。但在顶点和片段着色器中会有些不同。顶点着色器应该接收的是一种特殊形式的输入,否则就会效率低下。顶点着色器的输入特殊在它从顶点数据中直接接收输入。而片段着色器需要一个vec4颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果没有在片段着色器中定义输出颜色,OpenGL就会把物体渲染为默认的黑色(或白色)。

下面介绍顶点着色器和片段着色器是如何结合在一起的,如果开发者打算从一个着色器向另一个着色器发送数据,则必须在发送方着色器中声明一个输出,在接收方着色器中声明一个相同定义的输入。当类型和名字都一样时,OpenGL就会把两个变量链接到一起,它们之间就能发送数据了(这是在链接程序对象时完成的)。以代码为例说明一下,首先给大家展示的是顶点着色器代码:

//position变量的属性位置值为0

layout(location=0)in vec3 position;

//为片段着色器指定一个颜色输出

顶点着色器中实现了位置及颜色的输出,下面是片段着色器代码:

通过顶点着色器和片段着色器代码可以看到,在顶点着色器中声明了一个vertexColor变量作为vec4输出,并在片段着色器中声明了一个相同的vertexColor。由于它们名字相同且类型相同,片段着色器中的vertexColor就和顶点着色器中的vertexColor链接了。它们的链接当然是在GPU内部实现的,在这里不需要再继续深入理解,只要知道原理就可以了。由于在顶点着色器中将颜色设置为深红色,最终的片段也是深红色的。实现的效果如图2-1所示。图2-1 OpenGL实现的三角形2.3 OpenGL属性

在GPU编程中,经常需要定义一些变量,这些变量需要一些修饰。通常Shader代码编写中有三个变量修饰定义:uniform、varying、attribute,下面以uniform为例给大家介绍一下。uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。无论你把uniform值设置成什么,uniform都会一直保存它们的数据,直到它们被重置或更新。下面在一个着色器中添加uniform关键字,用来声明一个变量,以下面片段着色器代码为例给读者介绍一下:

在片段着色器中声明了一个uniform vec4的ourColor,并把片段着色器的输出颜色设置为uniform值的内容。因为uniform是全局变量,可以在任何着色器中定义它们,而无须通过顶点着色器作为中介。在这里友情提示一下,如果声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误。另外,在定义变量时,如果是在Shader内部使用的常量定义,就不要用任何声明修饰,直接编写就可以了,例如定义一个三维位置点代码如下:

vec3 pos=new vec3(100,100,100);

继续讲解上述片段着色器代码,目前uniform还是空的,还没有给它添加任何数据,下面的语句就做这件事,首先需要找到着色器中uniform属性的索引/位置值。当得到uniform的索引/位置值后,就可以更新它的值了。代码如下所示:

GLint vertexColorLocation=glGetUniformLocation(shaderProgram,"ourColor");

glUseProgram(shaderProgram);

glUniform4 f(vertexColorLocation,0.0f,1.0f,0.0f,1.0f);

用glGetUniformLocation函数查询uniform ourColor的位置值。主要是为查询到的函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)。如果glGetUniform-Location返回-1就代表没有找到这个位置值。最后,可以通过glUniform4f函数设置uniform值。注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前必须先使用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置uniform的。uniform变量一般用来表示变换矩阵、材质、光照参数和颜色等信息。有时在Shader变量声明中会用到attribute定义类型,它只能在顶点着色器中使用,不能在片段着色器中声明attribute变量,也不能使用。一般用attribute变量来表示一些顶点的数据,如顶点坐标、法线、纹理坐标、顶点颜色等。

在OpenGL代码中,一般用函数glBindAttribLocation来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer为每个attribute变量赋值。以下是顶点着色器代码实例,给读者展示一下使用uniform、attribute、varying三个变量定义的Shader代码片段:

最后介绍varying变量,varying变量是顶点着色器Shader和片段着色器Shader之间做数据传递用的。一般顶点着色器Shader修改varying定义的变量值,片段着色器Shader使用该varying定义的变量值。因此varying定义的变量在顶点着色器程序和片段着色器程序之间的声明必须是一致的,实例代码如下所示:

在片段着色器中首先定义了v_texCoord纹理坐标,同时也声明了纹理取样sampler2D定义的纹理贴图,它最终的颜色设置为gl_FragColor,作为最终的颜色返回值。接下来通过案例的方式给大家做系统的讲解。2.4 OpenGL案例

游戏美工制作的模型由于导出格式加密成二进制的原因,对于大部分开发者来说模型内容都是不可见的,在这里根据以前的开发经验给读者介绍一下模型内部组成。模型的最基本组成:顶点、法线、UV坐标等数值,模型中的顶点是必需的,因为每个3D模型都是由点组成的三角面或四边形,在引擎加载中都是以三角面为基本单元加载的。为了更好地给大家展示,下面自定义一个三角形,也是为了给后面模型文件内部的介绍以及模型文件加载铺路,自定义的三角形结构体如下:

GLfloat vertices[]={

//位置 //颜色

0.5f,-0.5f,0.0f, 1.0f,0.0f,0.0f, //右下

-0.5f,-0.5f,0.0f, 0.0f,1.0f,0.0f, //左下

0.0f, 0.5f,0.0f, 0.0f,0.0f,1.0f //顶部

};

三角形的定义用了数组的形式,包括顶点的三维坐标和颜色值,将定义的颜色和位置信息通过GPU渲染展示出来,这就需要编写顶点着色器和片段着色器代码,下面是对应的完整顶点着色器代码:

通过这两个着色器就可以把定义的三角形显示在屏幕上,下面把定义的顶点数组在内存内部的结构体解释一下。定义好的顶点也称为VBO(Vertex Buffer Object),顶点缓存对象在内存的分布图如图2-2所示。图2-2 顶点的VBO内存存储

学习Shader编程,对于顶点的一些存储,至少要明白其在内存是如何存放的。了解了其在内存的布局后,即可调用OpenGL库的接口函数glVertexAttribPointer更新顶点格式,代码如下所示:

//位置属性

glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,6*sizeof(GLfloat),(GLvoid*)0);

glEnableVertexAttribArray(0);

//颜色属性

glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,6*sizeof(GLfloat),(GLvoid*)(3*sizeof(GL-float)));

glEnableVertexAttribArray(1);

在设置函数参数时,第五个参数的含义是必须向右移动6个float,其中3个是位置值,另外3个是颜色值。这使步长值为6乘以float的字节数,从而指定一个偏移量。对于每个顶点来说,位置顶点属性在前,所以它的偏移量是0。颜色属性紧随位置数据之后,所以偏移量就是3*sizeof(GLfloat),用字节来计算就是12字节。其渲染的效果图如图2-3所示。图2-3 三角形渲染效果图

通过给读者展现的代码可以看到Shader的编写还是比较容易掌握的,在以上代码中没有使用任何算法运算,只是为了通过Shader的编写渲染一个简单的三角形。小结

学习OpenGL编程首先要了解Shader编程语言的基本语法,这与传统的学习语言类似。如果开发者有C语言背景更好,这样学习起来更顺手。掌握语法后,网上有很多这方面的教程,试着拿别人编写的Shader脚本运行,看一下效果,然后再在已有的代码基础上进行修改,逐步地去掌握。另外,Shader脚本在程序中是不可以调试的,如果遇到问题,只能通过赋值操作或注释行操作以及使用特定值操作,最终通过排除法找到问题所在。第3章 矩阵变换算法

说到矩阵变换,读者第一时间会想到大学时学的《线性代数》课程,矩阵变换在游戏开发中或者说对于GPU编程作用有多大?本章就这个问题给读者逐一介绍。可以这么说,3D引擎的基础是矩阵变换,所有的3D引擎都会涉及矩阵变换的运算。矩阵变换在任何3D引擎中都是必备的技术,对GPU编程也是一样,GPU实现的是模型的渲染处理,材质渲染处理与模型自身的顶点运算是息息相关的。在游戏场景中的所有模型都会进行一系列的仿射变换,平移、旋转、缩放这些都离不开矩阵的运算。既然矩阵变换这么重要,下面就为读者介绍底层的矩阵运算。3.1 矩阵平移变换算法

首先介绍矩阵的平移变换,它的原理是在原始向量的基础上加上另一个向量,从而获得一个在不同位置的新向量,在位移向量基础上移动了原始向量。读者都知道,在3D空间中不论点还是向量都是三维的,用三维的点做平移变换是无法实现的,如果读者自己感兴趣可以测试一下,这个比较简单。既然三维的点无法完成平移变换,就需要将三维的点转成四维的点。四维的点也称为齐次坐标,就是在三维点的基础上再加一位w,这样就可以做平移变换了,下面通过实例给读者介绍。假设点P(x,y,z),平移向量T(Tx,Ty,Tz),经过平移后得到新的位置,可以用如下公式表示:

在3D空间中,如果用3×3矩阵位移值就没地方放置了,无法实现位移,所以是不可行的,因为游戏开发中经常需要加载3D模型,模型也是三维点的集合,做平移变换时需要模型中的每个点都要与平移矩阵相乘,这些计算对用户来说是不可见的,它封装在引擎底层。开发者在操作3D编辑器时经常需要模型从一个位置移到另一个位置,如角色在场景中移动,角色移动的过程也是矩阵变换的过程。作者自研引擎实现的场景中也封装了大量的矩阵运算,自研引擎实现效果如图3-1所示。图3-1 游戏场景渲染效果图

在Cocos2D-X引擎中实现的代码如下所示:3.2 矩阵旋转变换算法

在3D空间中旋转需要定义一个角和一个旋转轴(Rotation Axis),物体会沿着给定的轴旋转特定角度,实现旋转功能。在3D空间中有三个轴:X轴、Y轴、Z轴,其中X轴在屏幕上表示的方向是从左指向右,Y轴在屏幕上表示的方向是从下指向上,Z轴在屏幕上表示的方向分为两种:一种是从屏幕里指向外面,通常称为右手坐标系,另一种是从屏幕外面指向屏幕里面,通常称为左手坐标系。角色旋转主要分为三种:绕X轴旋转、绕Y轴旋转、绕Z轴旋转,在此基础上又可以延伸出绕XZ轴旋转、绕XYZ轴旋转等不同的旋转组合。下面讲解基本的绕X轴、Y轴、Z轴旋转的矩阵算法,绕X轴旋转矩阵算法如下所示:

绕X轴旋转的Cocos2D-X引擎中的实现代码如下所示:

绕Y轴旋转矩阵算法如下所示:

绕Y轴旋转的Cocos2D-X引擎中的实现代码如下所示:

绕Z轴旋转矩阵算法如下所示:

绕Z轴旋转的Cocos2D-X引擎中的实现代码如下所示:

另外,Cocos2D-X引擎还提供了绕某个向量旋转的代码函数,如下所示:

以上关于矩阵算法的函数就是把矩阵之间的运算通过代码实现出来而已,作为开发者必须掌握基本的运算。3.3 矩阵缩放变换算法

矩阵缩放变换在游戏中的使用也是非常广泛的,如游戏关卡中Boss的硕大外形,就需要有针对性地对Boss模型在场景中放大相应的倍数,对游戏关卡中的小怪也需进行缩小操作,模型的放大或缩小也是通过矩阵换算得到的,换算矩阵如下所示:

其中S1、S2、S3是放大系数,如果读者使用过Unity,就会知道在Unity的Transform组件中有一项Scale专门用于设置缩放系数。设置好的缩放系数会传递给Unity引擎进行矩阵换算,由于Unity引擎中的代码对开发者是不开放的,下面借助Cocos2D-X引擎中的代码给读者展示,在类文件Mat4.cpp中有关于缩放函数的实现,代码如下所示:

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载