一、OpenGL基础
游戏引擎是对底层绘图接口的包装,Cocos2d-x 也一样,它是对不同平台下 OpenGL 的包装。OpenGL 全称为 Open Graphics Library,是一个开放的、跨平台的高性能图形接口。OpenGL ES 则是 OpenGL 在移动设备上的衍生版本,具备与 OpenGL 一致的结构,包含了常用的图形功能。Cocos2d-x 就是一个基于 OpenGL 的游戏引擎,因此它的绘图部分完全由 OpenGL 实现。OpenGL 是一个基于 C 语言的三维图形 API,基本功能包含绘制几何图形、变换、着色、光照、贴图等。除了基本功能,OpenGL还提供了诸如曲面图元、光栅操作、景深、shader 编程等高级功能。
(1)状态机:
OpenGL 是一个基于状态的绘图模型,我们把这种模型称为状态机。为了正确地绘制图形,我们需要把 OpenGL 设置到合适的状态,然后调用绘图指令。(绘图流程和状态机优势)。
(2)坐标系:OpenGL 是一个三维图形接口,在程序中使用右手三维坐标系。
(3)渲染流水线:
当我们把绘制的图形传递给 OpenGL 后,OpenGL 还要进行许多操作才能完成 3D 空间到屏幕的投影。通常,渲染流水线过程
有如下几步:显示列表、求值器、顶点装配、像素操作、纹理装配、光栅化和片断操作等。OpenGL 从 2.0 版本开始引入了可编程着色器(shader)。
(4)绘图函数:
(5)矩阵与变换:OpenGL 对顶点进行的处理实际上可以归纳为接受顶点数据、进行投影、得到变换后的顶点数据这 3 个步骤。
在计算机中,坐标变换是通过矩阵乘法实现的。
注:详细参见《cocos2d-x高级开发教程》、《OpenGL编程指南》
二、Cocos2d-x绘图原理
void CCSprite::draw(void) { //1. 初始准备 CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); //2. 颜色混合函数 ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); //3. 绑定纹理 if (m_pobTexture != NULL) { ccGLBindTexture2D( m_pobTexture->getName() ); } else { ccGLBindTexture2D(0); } // // Attributes // //4. 绘图 ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) long offset = (long)&m_sQuad; // vertex //顶点坐标 int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods //纹理坐标 diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color //顶点颜色 diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); //绘制图形 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); //5. 调试相关的处理 #if CC_SPRITE_DEBUG_DRAW == 1 //调试模式 1:绘制边框 // draw bounding box CCPoint vertices[4]={ ccp(m_sQuad.tl.vertices.x,m_sQuad.tl.vertices.y), ccp(m_sQuad.bl.vertices.x,m_sQuad.bl.vertices.y), ccp(m_sQuad.br.vertices.x,m_sQuad.br.vertices.y), ccp(m_sQuad.tr.vertices.x,m_sQuad.tr.vertices.y), }; ccDrawPoly(vertices, 4, true); #elif CC_SPRITE_DEBUG_DRAW == 2 // draw texture box //调试模式 2:绘制纹理边缘 CCSize s = this->getTextureRect().size; CCPoint offsetPix = this->getOffsetPosition(); CCPoint vertices[4] = { ccp(offsetPix.x,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y+s.height), ccp(offsetPix.x,offsetPix.y+s.height) }; ccDrawPoly(vertices, 4, true); #endif // CC_SPRITE_DEBUG_DRAW CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); }
OpenGL绘图技巧(遮罩层和小窗预览,可编程着色器)