《Cocos2d-x高级开发教程》学习笔记 OpenGL部分
来源:互联网 发布:vue数据交互 编辑:程序博客网 时间:2024/05/16 01:54
10.1 OpenGL简介
一、状态机
OpenGL是一个基于状态的绘图模型,我们把这种模型称为状态机。
为了正确地绘制图形,我们需要把OpenGL设置到合适的状态,然后调用绘图指令
OpenGL把所有的参数作为状态来保存,如果没有设置新的参数,则会一直采用当前的状态来绘图
我们可以把绘图设备人为地分为两个部分:"服务器端",负责具体的绘制渲染;"客户端",负责向服务器端发送绘图指令
GL_APICALL voidGL_APIENTRY glEnable (GLenum cap); //开启一个状态
GL_APICALL voidGL_APIENTRY glDisable (GLenum cap); //禁止一个状态
二、坐标系
OpenGL使用右手三维坐标系,初始化时,屏幕向右的方向为X方向,屏幕向上的方向为Y方向,由屏幕指向我们的方向为Z方向。
在不对OpenGL做任何设置的时候,初始的坐标系称作世界坐标系。
世界坐标系以屏幕中心为原点(0,0,0)
绘图坐标系,初始化时与世界坐标系重叠,当用glTranslatef(),glScalef(), glRotatef()对当前绘图坐标系进行平移、伸缩、旋转变换之后, 世界坐标系和当前绘图坐标系不再重合。改变以后,再用glVertex3f()等绘图函数绘图时,都是在当前绘图坐标系进行绘图,所有的函数参数也都是相 对当前绘图坐标系来讲的。
三、渲染流水线
过程:显示列表、求值器、顶点装配、像素操作、纹理装配、光栅化和片断操作等;
OpenGL ES 1.0版本采用固定渲染管线;OpenGL从2.0版本开始引入了可编程着色器(shader)。可编程着色器作为原有渲染管线中一些部分的代替品,不仅可以实现原有的渲染功能,还可以自由实现开发者自定义的渲染效果。可编程着色器主要包含顶点着色器和片段着色器,其中前者负责对顶点进行几何变换以及光照计算,后者负责处理光栅化得到的像素以及纹理。
10.1.2 绘图 (三角形带(triangle stripe )的概念,参考计算机图形学)
1.声明顶点坐标、纹理坐标、颜色三个静态数组,用来构建数据。
2.初始化纹理,CCTextureCache类的addImage方法载入纹理,然后用纹理的属性初始化四个顶点的纹理坐标,再用CCTexture2D保存下来。
3.绘制图片:绑定纹理、设置顶点数组和绘图。
具体参考Fishjoy的例子,例子中绘制的图片会被背景掩盖,解决方法是拉大窗口(程序设置)
10.1.3 矩阵与变换
当我们设置好OpenGL的坐标系,并传入顶点数据后,OpenGL就会通过一系列计算把顶点映射到世界坐标系之中,再把世界坐标系中的点投影到平面上。OpenGL维护了一个当前绘图矩阵,用于表示当前的绘图坐标系。这个矩阵被初始化为单位矩阵,此时绘图坐标系与世界坐标系相同,当我们不断地在绘图矩阵后乘上新的矩阵时,会相应地改变绘图坐标系
cocos2d-x 2.0以后的版本 已经采用OpenGL ES 2.0,放弃了固定的渲染流水线,取而代之的是自定义的各种着色器,引入第三方库Kamzmatah来进行矩阵计算,具体函数参考书中。
10.2 Cocos2d-x 绘图原理
10.2.1 精灵的绘制
绘制精灵的代码位于引擎源码的"sprite_nodes\CCSprite.cpp"中,分为5个部分:1. 设置OpenGL状态;2. 设置颜色混合模式;3.绑定纹理;4.绘图;5.调试相关处理。
10.2.2渲染树的绘制
Cocos2d-x游戏的层次:导演类CCDirector直接控制渲染树的根节点--场景(CCScene),场景包含多个层(CCLayer),层中包含多个精灵(CCSprite)。每一个上述的游戏元素都在渲染树中表示为节点(CCNode),游戏元素的归属关系就转换为了节点间的归属关系,进而形成树结构。visit()方法绘制一棵渲染树,每个节点需要绘制子节点。
引擎会根据不同的平台设法使系统不断地调用这个方法,从而完成游戏主循环。(mainloop)
visit方法分为4部分:1.进行先行的处理,矩阵圧栈;2.通过transform方法进行一些变换,draw方法不关心纹理绘制的位置,绘制到当前坐标系的原点,所以绘制前需要进行调整。3.递归绘制节点以其子节点;4.恢复,矩阵退栈。
10.2.3 坐标变换
transform,一堆坐标变换的方法。Cocos2d-x使用的一个开源几何计算库Kazmath
10.3TexturePacker与优化
10.3.1绘图瓶颈
因素:1.纹理过小;2.纹理切换次数过多;3.纹理过大;
10.3.2 碎图压缩与精灵框帧
运用TexturePacker将碎图合成一张纹理,并生成一个.plist文件,通过CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("all.plist");加载,即存放在精灵框帧的缓存内。
cannon =CCSprite::createWithSpriteFrameName(cannonPath); //从精灵框帧完成初始化
TexturePacker下载地址:http://www.codeandweb.com/texturepacker/download
10.3.3批量渲染
CCSpriteBatchNode可以一次批量提交所有子节点的绘图请求
10.3.4 色彩深度优化
通过修改颜色深度,降低游戏质量,以达到舒畅运行或者包大小的要求。
11 OpenGL绘图技巧
11.1 自定义绘图
由"CCDrawingPrimitives.h"和对应的cpp文件提供,包括了点、线、多边形、圆形和贝塞尔曲线等最基本的几何图形的绘制,还包括了一些基本的设置,如设置点的大小、绘制的颜色等。
形如ccDrawLine的绘图函数,每次都需要调用OpenGL渲染,效率低,只适用于少量绘制的情况。
11.2 遮罩层
又称为剪刀效果:开启遮罩效果后,一切的绘制提交都是正常渲染的,但最终只有屏幕上的指定区域会被绘制。
glEnable(GL_SCISSOR_TEST); //启动遮罩效果
glScissor(rect.origin.x,rect.origin.y, rect.size.width, rect.size.height); //设置遮罩效果
glDisable(GL_SCISSOR_TEST);//关闭遮罩效果
例子:表盘的效果,让0到9的数字顺序摆放,连续移动,只显示一个区域,数字依次通过;
11.3 数据交流
CCImage类,加载到内存的纹理图片,纹理以每个像素的颜色值保存在内存之中。
主要提供两个方面的功能:一方面是文件的加载与保存,另一方面是内存缓冲区的读写。
CCTexture2D类:该类所包含的纹理大小必须是2的幂次,只存在于显存中的纹理;
文件读写相关的方法:
boolinitWithImageFile(const char* strPath, EImageFormat imageType = kFmtPng);
boolinitWithImageFileThreadSafe(const char* fullpath, EImageFormat imageType =kFmtPng);
bool saveToFile(constchar* pszFilePath, bool bIsToRGB = true);
getData和getDataLen这两个方法提供了获取当前纹理的缓冲区的功能,而initWithImageData方法提供了使用像素数据初始化图片的功能
例子:实现截图功能的方法 glReadPixelsinitWithImageData
使用glReadPixels方法将当前绘图区的像素都读取到了一个内存缓冲区内,然后用这个缓冲区来初始化CCImage并返回
11.4 可编程管线
通过着色器定义每一个顶点或者像素的着色方式,产生更丰富的效果。
1.顶点着色器(vertex shader)
2.段色着色器(fragment shader)
这两个着色器不能单独使用,必须成对出现,这是因为顶点着色器会首先确定每一个显示到屏幕上的顶点的属性,然后这些顶点组成的区域被化分成一系列像素,这些像素的每一个都会调用一次段着色器,最后这些经过处理的像素显示在屏幕上,二者是协同工作的。
11.4.2 CCGLPragram
获取着色器程序接口 : const GLuintgetProgram(); 返回当前着色器程序的表示符。
导入着色器程序函数: boolinitWithVertexShaderByteArray(const GLchar* vShaderByteArray,const GLchar*fShaderByteArray);
bool initWithVertexShaderFilename(const char*vShaderFilename, const char* fShaderFilename);
第一个参数均指定了顶点着色器,后一个参数则指定了像素着色器;
11.4.3 变量传递
着色器存在两种输入数据,分别被标识为arrtibute和uniform
1.attribute变量是程序直接传递给顶点着色器的,段着色器不能访问,被限制为向量或者标量等简单数据结构;
2.uniform变量是全局性的,支持复杂的数据结构,可以通过uniformblock自定义复杂的数据结构;
以上两种变量的传递都要经过获取位置和设置两步
intglGetUniformLocation(GLuint program, const GLchar* name);//参数是当前绘图程序及需要获取的uniform变量名
对uniform变量的设置存在着一系列以"glUniform"为前缀的函数:例如:voidglUniform1i(GLint location, GLint x);
OpenGL的函数末尾总是紧接着类似“1i”和 “3f”这样的后缀
考虑到内存和显卡间数据交换的开销,引擎在CCGLProgram中进一步封装了一层缓冲机制,记录下每次传递的值,只有在传值不一的时候才真正设置到显卡数据中:
voidCCGLProgram::setUniformLocationWith1i(unsigned int location, GLint i1);
绑定一个attribute变量名到特定的标识符上,这样我们就可以直接通过名称来访问变量了:
voidaddAttribute(const char* attributeName, GLuint index);
根据同一个变量在不同调用间是否一致,可以分为一次性传值与数组传值。这两种传值方式是互斥的,要通过一组函数来切换:
voidglEnableVertexAttribArray(GLuint index);
voidglDisableVertexAttribArray(GLuint index);
没有开启数组传值的attribute变量使用"glVertexAttrib"系列函数传值
开启数组传值的attribute变量则通过以下的接口函数传值:
voidglVertexAttribPointer(GLuint indx, //变量标识符
GLint size, //变量的维数
GLenum type, //组成变量的基本类型
GLboolean normalized,//是否归一化,一般为false
GLsizei stride, //每次取值间隔
const GLvoid* ptr);//数组指针
11.5 水纹效果
11.5.2 ShaderNode类
11.5.3uniform变量准备
11.5.4 绘制
11.5.5 添加到场景
11.6 CCGrid3D
CCActionGrid3D特殊的动作类,也提供了一个实现水纹效果的波浪效果动作
- 《Cocos2d-x高级开发教程》学习笔记 OpenGL部分
- Cocos2d-x高级开发教程阅读笔记
- Cocos2d-x高级开发教程
- cocos2d-x学习笔记15:cocos2d-x教程资源总结
- 非常好的cocos2d-x开发学习教程
- 《Cocos2d-x 高级开发教程》读书笔记1:内存管理
- 【笔记】Cocos2d-x高级开发教程:制作自己的<捕鱼达人> 笔记一:序_前言_第一章
- Cocos2d-x学习笔记之Cocos2d-x开发环境搭建
- cocos2d-x游戏开发学习笔记
- Cocos2d-x游戏开发学习笔记
- cocos2d-x开发学习笔记(一)
- Cocos2D-X开发学习笔记2:定时器
- Cocos2d-x 学习笔记
- Cocos2d-x学习笔记
- Cocos2d-x学习笔记
- Cocos2d-x学习笔记
- cocos2d-x学习笔记
- cocos2d-x学习笔记
- 【数据缓存】
- JAVA中int、String的类型转换
- Linux之V4L2基础编程
- MySql 新建用户,新建数据库,用户授权,删除用户,修改密码
- MapReduce中的Shuffle和Sort分析
- 《Cocos2d-x高级开发教程》学习笔记 OpenGL部分
- 实验IOCP多线程是否会导致TCP乱序
- itunes下载的固件在哪? (XP和win7,Mac存放的位置不同)
- 电脑知识总大全
- HDFS设计优劣
- 汇总面试题
- 杀固定端口的进程
- Java项目生成静态页面
- 二分匹配——匈牙利算法;