`
wsliujian
  • 浏览: 95110 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Cocos2Dx之渲染流程

 
阅读更多

           渲染时一个游戏引擎最重要的 部分。渲染的效率决定了游戏的流畅度清晰度,跟前面的介绍的内容相比,渲染是最具技术含量的事情,也是一个需要很多专业知识的事情。这里我们有这个机会, 来学习下一个游戏引擎的渲染是怎么做的。Cocos2Dx是一个2D框架,可以简单地看做z轴在一个平面上,Cocos2Dx采用的OpenGL技术决定 了往3D渲染上面走也不是不行的。最新3.2版本已经支持3D骨骼动画的CCSprite。3.2版本还有很多其他的变化,可谓是一次伤筋动骨的大版本, 现在还不跳跃,继续基于2.2.3进行分析。

 

这篇文章先分析简单的CCSprite和CCLayer是怎么渲染出来的,过一下整个渲染的流程。后续我们再分析一些高级功能。

 

要能够使用OpenGL,肯定第一步是要先初始化OpenGL,并且创建一个可以在上面绘制的场景的窗口。OpenGL本身是跟操作系统,窗口系统 无关的图形接口。因此初始化肯定也是平台相关。这就是为什么CCEGLView在每个平台下面都有自己实现的原因。继续使用Windows平台进行分析, 其他平台大同小异。

 

回忆前面讲到游戏启动流程的时候,我们会在AppDelegate::applicationDidFinishLaunching调用 pDirector->setOpenGLView(CCEGLView::sharedOpenGLView())来设置OpenGL使用的 View。sharedOpenGLView是CCEGLView的一个单例访问接口。CCEGLView::sharedOpenGLView第一次被 调用的时候会首先创建一个平台相关的CCEGLView对象,然后调用其Create()函数。

 

Windows上面的Create函数我们已经看过,它会设置窗口样式,然后创建一个窗口。窗口创建完毕后会调用CCEGLView::initGL。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//file:\cocos2dx\platform\win32\CCEGLView.cpp
bool CCEGLView::initGL()
{
    m_hDC = GetDC(m_hWnd);
    SetupPixelFormat(m_hDC);
    m_hRC = wglCreateContext(m_hDC);
    wglMakeCurrent(m_hDC, m_hRC);
    const GLubyte* glVersion = glGetString(GL_VERSION);
    if atof((const char*)glVersion) < 1.5 )
    {
        return false;
    }
    GLenum GlewInitResult = glewInit();
    if (GLEW_OK != GlewInitResult)
    {
        return false;
    }
    if(glew_dynamic_binding() == false)
    {
        return false;
    }
    glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
    return true;
}

 

CCEGLView::initGL首先设置像素格式。像素格式是OpenGL窗口的重要属性,它包括是否使用双缓冲,颜色位数和类型以及深度位数 等。像素格式可由Windows系统定义的所谓像素格式描述子结构来定义(PIXELFORMATDESCRIPTOR)。应用程序通过调用 ChoosePixelFormat函数来寻找最接近应用程序所设置的象素格式,然后调用SetPixelFormat来设置使用的像素格式。 WglCreateContext函数创建一个新的OpenGL渲染描述表,此描述表必须适用于绘制到由m_hDC返回的设备。这个渲染描述表将有和设备 上下文(DC)一样的像素格式。wglMakeCurrent将刚刚创建的渲染描述符表设置为当前线程使用的渲染环境。完成这些操作之后,OpenGL的 基本环境已经准备好了。后续的处理是为了使用OpenGL扩展。glewInit初始化GLEW。GLEW(OpenGL Extension Wrangler Library)是一个跨平台的C/C++库,用来查询和加载OpenGL扩展。OpenGL并存的版本比较多,有些特性并没有存在于OpenGL核心当 中,是以扩展形式存在。作为一个跨平台的游戏框架,处理OpenGL的版本差异是必须要做的。glew_dynamic_binding启用帧缓冲对象 (FBO)。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static void SetupPixelFormat(HDC hDC)
{
    int pixelFormat;
    PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR), // 大小
        1, // 版本
        PFD_SUPPORT_OPENGL | // 像素格式必须支持OpenGL
        PFD_DRAW_TO_WINDOW | // 渲染到窗口中
        PFD_DOUBLEBUFFER, // 支持双缓冲
        PFD_TYPE_RGBA, // 申请RGBA颜色格式
        32, // 选定的颜色深度
        0, 0, 0, 0, 0, 0, // 忽略的色彩位
        0, // 无Alpha缓存
        0, // 忽略Shift Bit
        0, // 无累加缓存
        0, 0, 0, 0, // 忽略聚集位
        24, // 24位的深度缓存
        8, // 蒙版缓存
        0, // 无辅助缓存
        PFD_MAIN_PLANE, // 主绘图层
        0, // 保留
        0, 0, 0, // 忽略层遮罩
    };
    pixelFormat = ChoosePixelFormat(hDC, &pfd);
    SetPixelFormat(hDC, pixelFormat, &pfd);
}

 

从设置的像素格式上可以看出,Windows上启用了双缓冲,使用RGBA颜色,32位颜色深度。

 

不同平台上面,OpenGL的初始化流程不完全一样。详细的区别可以查看平台相关的CCEGLView类。

 

OpenGL初始化完成后,就可以进行绘制操作了。CCDisplayLinkDirector::mainLoop会调用drawScene() 来绘制场景。drawScene本身做的工作还比较多,比如前面介绍的调度器处理。这里我们抛开渲染无关的内容,只看跟渲染紧密相关的代码实现。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void CCDirector::drawScene(void)
{
    //清除颜色缓冲区和深度缓冲去
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //该节点的转换矩阵入栈
    kmGLPushMatrix();
    // draw the scene
    if (m_pRunningScene)
    {
        m_pRunningScene->visit();
    }
    // 该节点的转换矩阵出栈
    kmGLPopMatrix();
    // 交换缓冲区
    if (m_pobOpenGLView)
    {
        m_pobOpenGLView->swapBuffers();
    }
}

 

一个场景包含当前窗口可以看到的所有内容。由于OpenGL是基于状态的,比如设置的颜色,如果不去清楚或者修改就一直会使用下去。我们当然不希望上一次绘制场景产生的缓冲区数据被绘制到现在的场景当中。所以drawScene()首先清楚颜色缓冲区和深度缓冲区。

 

关于kmGLPushMatrix和kmGLPopMatrix,有必要先介绍下背景。Cocos2Dx使用了模型视图矩阵、投影矩阵和纹理矩阵。 模型视图矩阵完成模型和视图的变换,包括平移、旋转和缩放。投影矩阵完成三维空间的顶点映射到二维的屏幕上,有两种投影:正射投影和透视投影。纹理矩阵用 来对纹理进行变换。关于矩阵变换参考注1的资料。

 

OpenGL通过使用齐次坐标,平移、旋转和缩放变换都可以通过矩阵乘法完成。但是矩阵乘法是有顺序的,左乘和右乘的结果是不一样的,因此应该变换 的顺序很重要。由于存在多个矩阵,并且为了简化复杂模型变换,OpenGL使用栈来存放矩阵。kmGLPushMatrix()函数将当前栈的栈顶矩阵复 制后压栈,对应的kmGLPopMatrix()用于出栈,还有kmGLLoadIdentity()用于将栈顶矩阵初始化成单位矩阵。需要注意的 是,OpenGL使用的矩阵是列优先的矩阵。

 

kmGLPushMatrix()内部调用lazyInitialize()来延迟初始化Cocos2Dx使用的三类矩阵:模型视图矩阵、投影矩阵 和纹理矩阵。初始化的过程中,不但为三个类型的矩阵都创建了一个堆栈(内部通过数组实现的),还在每个堆栈中都压入一个单位矩阵。单位矩阵左乘任何顶点, 顶点不会变化。单位矩阵不会影响后续的变换。current_stack表示了当前使用的堆栈,可以通过kmGLMatrixMode(mode)来切换 当前使用的矩阵堆栈。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void lazyInitialize()
{
    if (!initialized) {
        kmMat4 identity; 
        km_mat4_stack_initialize(&modelview_matrix_stack);
        km_mat4_stack_initialize(&projection_matrix_stack);
        km_mat4_stack_initialize(&texture_matrix_stack);
        current_stack = &modelview_matrix_stack;
        initialized = 1;
        kmMat4Identity(&identity);
        km_mat4_stack_push(&modelview_matrix_stack, &identity);
        km_mat4_stack_push(&projection_matrix_stack, &identity);
        km_mat4_stack_push(&texture_matrix_stack, &identity);
    }
}

 

CCDirector::drawScene()第一次被调用的时候,会初始化模型视图矩阵、投影矩阵和纹理矩阵分别对应的矩阵栈。然后在每个栈中 压入一个单位矩阵。随后kmGLPushMatrix()复制一个模式视图矩阵栈的单位矩阵,然后放到栈顶上。然后渲染当前的场景,最后将栈顶的矩阵出 栈。为什么要这样做呢?设想当前的节点需要做一个平移操作,对应的变换矩阵是T1(压栈),假设当前节点的子节点Z序比当前节点大,那么当前节点的所有顶 点执行T1p以后,对于它的子节点也需要做平移,使用的同样是变换矩阵T1。这个节点绘制完以后,就该绘制下一个节点了(出栈),下一个节点的变换矩阵为 T2(压栈),再用T2做该节点及其子节点的变换。可以看出,这样的处理方式非常自然、简单。

 

CCScene的visit继承的是CCNode的visit,它的实现我们前面已经分析过了。这里再看看跟渲染相关的内容。 CCNode::visit()先复制一个栈顶元素并压栈,然后计算出一个此节点相对于父节点的变换矩阵,然后把它转换为OpenGL格式的矩阵并右乘在 当前绘图矩阵之上,从而得到此节点的世界变换矩阵。随后,根据子节点的Z序确定渲染顺序,然后根据渲染顺序依次渲染子节点或自身。如果是渲染自身,直接调 用draw函数。CCSprite的draw函数为空,什么都不做。当前节点及其子节点绘制完成之后,再执行出栈操作。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void CCNode::visit()
{
    kmGLPushMatrix();
    this->transform();
    CCNode* pNode = NULL;
    unsigned int i = 0;
    if(m_pChildren && m_pChildren->count() > 0)
    {
        sortAllChildren();
        // draw children zOrder < 0
        ccArray *arrayData = m_pChildren->data;
        for( ; i < arrayData->num; i++ )
        {
            pNode = (CCNode*) arrayData->arr[i];
            if ( pNode && pNode->m_nZOrder < 0 )
            {
                pNode->visit();
            }
            else
            {
                break;
            }
        }
        // self draw
        this->draw();
        for( ; i < arrayData->num; i++ )
        {
            pNode = (CCNode*) arrayData->arr[i];
            if (pNode)
            {
                pNode->visit();
            }
        }
    }
    else
    {
        this->draw();
    }
    kmGLPopMatrix();
}

 

CCNode::visit的核心是transform()。transform()根据当前节点的位置、旋转角度和缩放比例等属性计算出一个此节 点相对于父节点的变换矩阵,然后把它转换为OpenGL格式的矩阵并右乘在当前绘图矩阵之上。transform()是负责CCSprite处理的各种变 换的核心函数。下一篇文章继续讨论。

 

现在继续分析渲染的流程。前面提到了,CCScrene的draw()函数不做任何事情。下面我们依次看CCSprite和CCLayer是如何绘制出来的。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void CCSprite::draw(void)
{
    CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");
    CC_NODE_DRAW_SETUP();
    ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst );
    ccGLBindTexture2D( m_pobTexture->getName() );
    ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
    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();
    CC_INCREMENT_GL_DRAWS(1);
    CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");
}

 

CCSprite::draw()首先设置使用的OpenGL状态。然后设置混合函数,绑定纹理。随后设置顶点数据,包括顶点坐标、顶点颜色和纹理 坐标。因为使用的是顶点数组的方式绘图,所以调用glDrawArrays绘制。GL_TRIANGLE_STRIP参数的意义见注2。代码里面用了很多 EMSCRIPTEN宏,他是一个Javscript的LLVM后端处理库,应该是跟JS相关的支持代码。

 

CC_NODE_DRAW_SETUP设置绘图环境。实际上设置了OpenGL服务器端的状态和着色器。OpenGL是C/S架构,因此客户端和服 务器端都有状态需要维护。ccGLEnable在当前版本上什么都没有做,使用服务器端默认状态。着色器的设置,首先选择当前顶点或片段使用的着色器,然 后检查同一着色器使用的Uniform数据是否有变化,有变化的话,重新设置着色器使用的Uniform数据。关于Uniform,参见注4。

 

1
2
3
4
5
6
7
8
#define CC_NODE_DRAW_SETUP() \
do { \
    ccGLEnable(m_eGLServerState); \
    { \
        getShaderProgram()->use(); \
        getShaderProgram()->setUniformsForBuiltins(); \
    } \
while(0)

 

混合的设置在渲染的过程中也非常重要。它决定了在视景框内不同深度的模型颜色如何显示出来,透明效果就依靠它实现。渲染的过程是有顺序 的,glBlendFunc函数决定后画上去的颜色与已经存在的颜色如何混合到一起。把将要画上去的颜色称为“源颜色”,把原来的颜色称为“目标颜色”。 OpenGL 会把源颜色和目标颜色各自取出,并乘以一个系数(源颜色乘以的系数称为“源因子”,目标颜色乘以的系数称为“目标因子”),然后相加,这样就得到了新的颜 色。关于OpenGL混合的详细计算模型,参考注5。

 

CCSprite混合使用的源因子和目标因子,以及使用的着色器在CCSprite::initWithTexture里面指定的。可以看出 CCSprite的源因子是GL_ONE(CC_BLEND_SRC),目标因子是 GL_ONE_MINUS_SRC_ALPHA(CC_BLEND_DST)。这样的参数组合,表示使用1.0作为源因子,实际上相当于完全的使用了这种 源颜色参与混合运算,目标颜色乘以1.0减去源颜色的alpha值。CCSprite使用的着色器是 kCCShader_PositionTextureColor。

 

CCSprite::draw使用glVertexAttribPointer来设置定点数据。它的原型:

 

1
void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,const GLvoid * pointer);

 

  • index是要修改的定点属性的索引值。实际上就是指定,现在设置的顶点数据是顶点坐标,还是纹理坐标,还是顶点颜色。

  • size是顶点数据的大小。

  • type是顶点数据的类型。CCSprite::draw设置的顶点坐标是3个浮点数表示的;纹理坐标是两个浮点数表示的;颜色是4个无符号数表示的。

  • normalized是否进行归一化。颜色需要归一化操作,也就是讲[0-255]整数的颜色,归一化为[0-1]浮点数的颜色。

  • stride是设置同一类型的数据之间的间隔。这个标志可以让我们把颜色数据、顶点坐标数据和纹理坐标数据放到一个数组里面。

  • pointer指向数据地址。

 

CCSprite使用了一个四元组ccV3F_C4B_T2F_Quad来存放四个顶点ccV3F_C4B_T2F,ccV3F_C4B_T2F包 含了顶点的坐标、颜色和纹理坐标。因此对于顶点坐标数据,第一个坐标与第二个坐标之间,还有一个大小为ccV3F_C4B_T2F的数据间隔。这就是为什 么glVertexAttribPointer的stride参数设置kQuadSize。纹理坐标和颜色放在顶点坐标之后,在通过 glVertexAttribPointer设置它们的时候需要计算偏移,offsetof就是完成这个计算的。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct _ccV3F_C4B_T2F_Quad
{
    ccV3F_C4B_T2F tl; //! top left
    ccV3F_C4B_T2F bl; //! bottom left
    ccV3F_C4B_T2F tr; //! top right
    ccV3F_C4B_T2F br; //! bottom right
} ccV3F_C4B_T2F_Quad;
typedef struct _ccV3F_C4B_T2F
{
    ccVertex3F vertices; //! vertices (3F)
    ccColor4B colors; //! colors (4B)
    ccTex2F texCoords; // tex coords (2F)
} ccV3F_C4B_T2F;

 

由于CCSprite继承了CCNodeRGBA,它可以设置绘制使用的颜色和不透明度。默认颜色是黑色(255, 255, 255, 255)。

 

CCLayer并没有draw()的缺省实现,使用的是它继承的CCNode的draw()函数,什么都不做。但它的子类CCLayerColor 可以自己绘制出来,它继承了CCLayerRGBA和CCBlendProtocol(CCSprite通过CCTextureProtocol间接继承 CCBlendProtocol)。我们看看CCLayerColor是如何绘制自身的。

 

1
2
3
4
5
6
7
8
9
10
11
12
void CCLayerColor::draw()
{
    CC_NODE_DRAW_SETUP();
    ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_Color );
    // vertex
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, m_pSquareVertices);
    // color
    glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_FALSE, 0, m_pSquareColors);
    ccGLBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst );
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    CC_INCREMENT_GL_DRAWS(1);
}

 

绘制的步骤与CCSprite类似。只是顶点没有开启纹理坐标,CCLayerColor只是显示设置的颜色,并不支持纹理贴图。因此,glVertexAttribPointer设置顶点数据的时候,没有绑定和设置纹理坐标。

 

CCLayerColor::initWithColor里面设置了CCLayerColor混合方式和着色器。混合使用的源因子是 GL_SRC_ALPHA,目标因子是GL_ONE_MINUS_SRC_ALPHA。这个混合组合是比较常见的组合。表示源颜色乘以自身的alpha 值,目标颜色乘以1.0减去源颜色的alpha值。这样一来,源颜色的alpha值越大,则产生的新颜色中源颜色所占比例就越大,而目标颜色所占比例则减 小。CCLayerColor使用的着色器是kCCShader_PositionColor。

 

现在已经看完了怎么渲染出CCSprite和CCLayerColor。自己派生的CCSprite渲染也是一样的方式。游戏退出的时候需要做OpenGL的清理工作。清理工作放在CCEGLView::destroyGL()里面。Windows上面依次调用:

 

1
2
wglMakeCurrent(m_hDC, NULL);
wglDeleteContext(m_hRC);

 

设置设备描述符表使用的图形描述符为空,然后删除图形描述符。

 

注1:模式视图矩阵和投影矩阵http://www.songho.ca/opengl/gl_transform.html。该网站上还有模拟矩阵变换的小程序,非常直观。

 

注2:GL_TRIANGLES是以每三个顶点绘制一个三角形。第一个三角形使用顶点 v0,v1,v2,第二个使用v3,v4,v5,以此类推。如果顶点的个数n不是3的倍数,那么最后的1个或者2个顶点会被忽略。 GL_TRIANGLE_STRIP则稍微有点复杂,其规律是:

 

  1. 构建当前三角形的顶点的连接顺序依赖于要和前面已经出现过的2个顶点组成三角形的当前顶点的序号的奇偶性(如果从0开始):

  2. 如果当前顶点是奇数:组成三角形的顶点排列顺序:T = [n-1 n-2 n]。

  3. 如果当前顶点是偶数:组成三角形的顶点排列顺序:T = [n-2 n-21 n]。

 

 

以上图为例,第一个三角形,顶点v2序号是2,是偶数,则顶点排列顺序是v0,v1,v2。第二 个三角形,顶点v3序号是3,是奇数,则顶点排列顺序是v2,v1,v3,第三个三角形,顶点v4序号是4,是偶数,则顶点排列顺序是v2,v3,v4, 以此类推。这个顺序是为了保证所有的三角形都是按照相同的方向绘制的,使这个三角形串能够正确形成表面的一部分。对于某些操作,维持方向是很重要的,比如 剔除。注意:顶点个数n至少要大于3,否则不能绘制任何三角形。GL_TRIANGLE_FAN与GL_TRIANGLE_STRIP类似,不过它的三角 形的顶点排列顺序是T = [n-1 n-2 n]。各三角形形成一个扇形序列。

 

注3:EMSCRIPTEN:Emscripten 是 Mozilla 的 Alon Zakai 开发的一个独特 LLVM 后端,可以将任意 LLVM 中间码编译成 JavaScript,大大简化了现有代码在 Web 时代的重用。Emscripten 并非通常的 LLVM 后端,本身使用 JavaScript 写成。它可以将任何通过 LLVM 前端(比如 C/C++ Clang )生成的 LLVMIR 中间码编译成 JavaScript,从而显著降低移植现有代码库到 Web 环境的损耗。

 

注4:uniform变量是外部application程序传递给(vertex和 fragment)shader的变量。因此它是application通过函数glUniform**()函数赋值的。在(vertex和 fragment)shader程序内部,uniform变量就像是C语言里面的常量(const ),它不能被shader程序修改。(shader只能用,不能改)。如果uniform变量在vertex和fragment两者之间声明方式完全一 样,则它可以在vertex和fragment共享使用。(相当于一个被vertex和fragment shader共享的全局变量)。uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。
注5:OpenGL可以设置混合运算方 式,包括加、减、取两者中较大的、取两者中较小的、逻辑运算等。下面用数学公式来表达一下这个运算方式。假设源颜色的四个分量(指红色,绿色,蓝 色,alpha值)是(Rs, Gs, Bs,  As),目标颜色的四个分量是(Rd, Gd, Bd, Ad),又设源因子为(Sr, Sg, Sb, Sa),目标因子为(Dr, Dg, Db,  Da)。则混合产生的新颜色可以表示为: (Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)。源因子和目标因子是可以通过 glBlendFunc函数来进行设置的。glBlendFunc有两个参数,前者表示源因子,后者表示目标因子。这两个参数可以是多种值,下面介绍比较 常用的几种。

 

  • GL_ZERO:     表示使用0.0作为因子,实际上相当于不使用这种颜色参与混合运算。

  • GL_ONE:      表示使用1.0作为因子,实际上相当于完全的使用了这种颜色参与混合运算。

  • GL_SRC_ALPHA:表示使用源颜色的alpha值来作为因子。

  • GL_DST_ALPHA:表示使用目标颜色的alpha值来作为因子。

  • GL_ONE_MINUS_SRC_ALPHA:表示用1.0减去源颜色的alpha值来作为因子。

  • GL_ONE_MINUS_DST_ALPHA:表示用1.0减去目标颜色的alpha值来作为因子。

分享到:
评论

相关推荐

    cocos2d-x-cocos2d-x-2.2.2.zip

    此外,cocos2d-x的事件系统也是其核心特性之一。它允许开发者方便地处理触摸、键盘、鼠标等各种输入事件,构建出响应性强的交互界面。同时,它的动作(Actions)和动画(Animations)系统,让开发者能够轻松实现复杂...

    Cocos2d-JS游戏开发

    在游戏性能方面,Cocos2d-JS提供了优化策略,如批处理渲染、纹理 atlases、预加载资源等,确保游戏在各种设备上运行流畅。同时,其跨平台特性使得开发者一次编写,即可部署到iOS、Android、Web等多个平台,大大节省...

    Cocos2d-x实战 JS卷 Cocos2d-JS开发

    《Cocos2d-x实战 JS卷 Cocos2d-JS开发》是一本深入探讨Cocos2d-x游戏引擎JavaScript版本使用的专业书籍。Cocos2d-x是全球范围内广泛采用的游戏开发框架,尤其适用于2D游戏的制作,而Cocos2d-JS则是其JavaScript接口...

    cocos2d-x 3.0

    《cocos2d-x 3.0:游戏开发中的角色移动技术详解》 在游戏开发领域,cocos2d-x是一款广泛使用的开源2D游戏引擎,尤其在移动平台上的应用非常广泛。cocos2d-x 3.0版本带来了许多性能优化和新特性,使得开发者能够更...

    Cocos2d-x实战C++卷关东升著完整版pdf

    此外,Cocos2d-x提供了丰富的图形渲染功能,包括2D渲染、粒子系统、图集(Atlas)管理等。理解这些功能可以帮助开发者高效地绘制游戏画面,提升游戏视觉效果。同时,音效和音乐管理也是游戏体验的重要组成部分,书中...

    经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip

    《cocos2d-x 3.8:经典游戏引擎源码解析》 cocos2d-x 是一个跨平台的游戏开发框架,它基于C++,同时提供了Lua和JavaScript的绑定,让开发者可以方便地在多种操作系统上创建2D游戏、演示程序和其他图形交互应用。这...

    Cocos2d-x 3.x游戏开发实战pdf含目录

    本书首先会介绍Cocos2d-x 3.x的基础知识,包括安装环境、项目创建、构建流程以及基本的场景管理。读者将学习如何在不同平台上配置Cocos2d-x开发环境,了解项目的目录结构和构建过程,掌握Scene、Layer、Node等核心...

    Cocos2d-x实战 JS卷

    3. **图形渲染**:学习如何使用Cocos2d-x的绘图API,包括纹理、精灵批处理、动画和粒子系统,创建丰富的视觉效果。 4. **物理引擎**:了解Cocos2d-x内置的Box2D或Chipmunk物理引擎,如何模拟真实世界的物理行为,如...

    cocos2d-x-2.1.4.rar

    《cocos2d-x 2.1.4:探索移动游戏开发的新篇章》 cocos2d-x 是一个跨平台的2D游戏开发框架,它为开发者提供了强大的工具和技术支持,使得游戏开发变得更为便捷。2.1.4 版本是这个框架的一个重要里程碑,它在前一...

    Cocos2d-x 闪电特效

    Cocos2d-x是一款流行的开源游戏开发框架,它基于C++,并利用OpenGL进行图形渲染。在游戏开发中,特效的实现是至关重要的,能够极大地提升游戏的视觉体验和玩家的沉浸感。"Cocos2d-x 闪电特效"正是这样一个专题,它...

    cocos2d-x-3.1.zip

    3. **渲染引擎**:Cocos2d-x 3.1包含了强大的2D渲染引擎,能够处理精灵(Sprites)、纹理(Textures)、动画(Animations)、粒子系统(Particle Systems)等图形元素。 4. **场景管理**:使用Scene类来管理游戏的...

    Cocos2d-x实战:C++卷(2版)源代码

    10. **性能优化**:Cocos2d-x提供了性能监控工具,源代码中可能包含了一些优化技巧,如减少不必要的渲染、合理安排任务调度等。 通过学习这些源代码,开发者不仅能理解Cocos2d-x的基本用法,还能学习到游戏开发的...

    cocos2d-html5-v2.2.3.zip

    4. **渲染引擎**:Cocos2d-html5使用Canvas元素进行2D渲染,它可以高效地处理图像、文本和图形,同时提供动画功能。通过CSS3和WebGL的支持,游戏画面可以达到较高的性能和视觉效果。 5. **物理引擎**:Cocos2d-...

    cocos2d的学习资料

    1. **渲染引擎**:cocos2d-x使用OpenGL ES作为图形后端,提供了一系列的2D绘图API,如精灵(Sprite)、层(Layer)、场景(Scene)、动作(Action)等,使得开发者可以方便地创建丰富的2D视觉效果。 2. **场景管理*...

    cocos2d-iphone-2.0.tar.gz

    11. **Performance Improvements**:Cocos2d-iPhone 2.0在性能上做了大量优化,包括更快的渲染、内存管理和多线程支持。 12. **Multitouch Support**:针对iOS设备的多点触控特性,Cocos2d-iPhone提供了易于使用的...

    cocos2d-x 动画工具 Flash2Cocos2d-x 1.3

    《cocos2d-x 动画工具 Flash2Cocos2d-x 1.3:将Flash创意带入移动游戏开发》 在移动游戏开发领域,cocos2d-x是一款广泛使用的开源游戏引擎,以其高效、跨平台的特性深受开发者喜爱。而Flash2Cocos2d-x则是一个专为...

    Cocos2d-x学习笔记

    - 学习渲染流程:Cocos2d-x使用OpenGL作为渲染接口,初学者需要学习OpenGL基础以及Cocos2d-x中的渲染流程和优化技巧。 - 掌握事件处理:游戏中的事件处理是交互的核心,需要学习如何响应用户输入和处理游戏中各种...

    《Cocos2d-Js开发之旅-从HTML5到原生手机游戏》完整源码

    《Cocos2d-Js开发之旅-从HTML5到原生手机游戏》是一本深入探讨Cocos2d-Js框架的书籍,旨在帮助开发者从HTML5游戏开发过渡到原生移动平台的游戏制作。Cocos2d-Js是Cocos2d-x家族的一员,是一个跨平台的、基于...

    Cocos2D-X开发学习笔记-渲染框架之图形的绘制

    本教程将深入讲解Cocos2D-X中的渲染框架,特别是如何进行图形的绘制,这对于创建游戏场景、角色动画以及用户界面至关重要。 在Cocos2D-X中,图形绘制是通过各种Node对象实现的,如Sprite(精灵)、Label(文本标签...

    cocos2d3D扑克翻牌特效

    在cocos2d-lua中,我们可以通过OpenGL ES来处理图形渲染。要实现翻牌特效,需要掌握基本的OpenGL变换,如平移(translate)、旋转(rotate)和缩放(scale)等。 四、翻牌动画实现 1. 初始状态:扑克牌正面朝下,...

Global site tag (gtag.js) - Google Analytics