首页 > 代码库 > 基于Cocos2d-x学习OpenGL ES 2.0之多纹理

基于Cocos2d-x学习OpenGL ES 2.0之多纹理

没想到原文出了那么多错别字,实在对不起观众了。介绍opengl es 2.0的不多。相信介绍基于Cocos2d-x学习OpenGL ES 2.0之多纹理的,我是独此一家吧。~~

子龙山人出了一个系列:基于Cocos2d-x学习OpenGL ES 2.0。弄c++来搞cocos2dx的可以看看。

教程是参考iphone的教程来写的,坑点也有不少,最主要的坑点还是在版本。所以还是弄个cocos2dx 3.2比较好。前两天辉辉说cocos2dx 3.2也很操蛋,.h里声明的返回值在源码实现的时候返回类型竟然变了。不得不吐槽一下~

 

子龙山人的教程只能教你照葫芦画瓢,什么原理的东西是压根就没涉及,有的还因为cocos2dx的封装过度会产生一些误导。

cocos2dx对opengl es封装的有点让人恶心,如果想学习opengl es是不建议在cocos2dx下进行学习的。

废话少说吧,开始正文。

根据子龙山人的教程,弄出了立方体纹理贴图,但是假如想在同一个面上贴多个纹理呢?该怎么实现?

本文提到两个方法,第一就是获取两个纹理,分别画图贴纹理,意思就是装顶点,装索引,绑定纹理,画图一。装顶点,装纹理,画图二。此时用到的都是GL_TEXTURE0,在frag文件中,只需要一个采样器就ok。

第二中方法就是用两个sampler,装顶点,装索引,绑定纹理一,绑定纹理二,画图。就OK了。

说起来比较简单,真要自己动手做,对于一个新手来说,过程还是有点小郁闷的。

下面就上源码了,对于步骤和方法的含义,此处不作介绍。相信强大的google和百度可以发挥巨大的作用。

第一种是立方体六个面贴上纹理,其中一个面再次贴上第二个纹理。

所用到的shader文件:

 1 attribute vec4 a_position; // 1 2 attribute vec4 a_color; // 2 3 attribute vec2 TextureCoord; 4  5 varying vec4 DestinationColor; // 3 6 varying vec2 v_texCoord; 7  8  9 void main(void) { // 410     DestinationColor = a_color; // 511     v_texCoord = TextureCoord;12     gl_Position = CC_MVPMatrix * a_position; // 613 }
myshader.vert
1 varying  vec4 DestinationColor; // 12 varying vec2 v_texCoord;3 4 void main(void) { // 25 6     gl_FragColor = DestinationColor * texture2D(CC_Texture0, v_texCoord) ; // 37 }
myshader.frag

所用到的两张图

 

      

头文件:

#ifndef _CubeTexture_H__#define _CubeTexture_H__#include "cocos2d.h"using namespace cocos2d;class CubeTexture : public cocos2d::Layer{public:    // there‘s no ‘id‘ in cpp, so we recommend returning the class instance pointer    static cocos2d::Scene* createScene();    // Here‘s a difference. Method ‘init‘ in cocos2d-x returns bool, instead of returning ‘id‘ in cocos2d-iphone    virtual bool init();      virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated) override;    //we call our actual opengl commands here    void onDraw();    // implement the "static create()" method manually    CREATE_FUNC(CubeTexture);private:    Mat4 _modelViewMV;    CustomCommand _customCommand;    GLProgram *mShaderProgram;    GLint _colorLocation;    GLint _positionLocation;    GLint _textureLocation;    GLuint _textureUniform;    GLuint _textureID;    GLuint _textureID2;    GLuint vertexBuffer;    GLuint indexBuffer;        GLuint _vertexBuffer2;    GLuint _indexBuffer2;};#endif // __HELLOWORLD_SCENE_H__
CubeTexture.h
  1 #include "CubeTexture.h"  2 using namespace GL;  3   4 cocos2d::Scene* CubeTexture::createScene()  5 {  6     auto scene = Scene::create();  7     auto layer = CubeTexture::create();  8     scene->addChild(layer);  9     return scene; 10 } 11  12 bool CubeTexture::init() 13 { 14     if ( Layer::init() ) 15     { 16         mShaderProgram = new GLProgram; 17         mShaderProgram->initWithFilenames("myshader.vert","myshader.frag"); 18         mShaderProgram->link(); 19         mShaderProgram->updateUniforms(); 20  21         _textureID = Director::getInstance()->getTextureCache()->addImage( "HelloWorld.png" )->getName(); 22         _textureID2 = Director::getInstance()->getTextureCache()->addImage("item_powerup_fish.png")->getName(); 23         glGenBuffers( 1, &vertexBuffer ); 24         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer ); 25  26         glGenBuffers( 1, &indexBuffer ); 27         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer ); 28  29         return true; 30     } 31     return false; 32 } 33  34 void CubeTexture::draw( Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated ) 35 { 36     Layer::draw(renderer, transform, transformUpdated); 37   38     _customCommand.init(_globalZOrder); 39     _customCommand.func = CC_CALLBACK_0(CubeTexture::onDraw,this); 40     renderer->addCommand(&_customCommand); 41 } 42  43 void CubeTexture::onDraw() 44 { 45     Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); 46     Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); 47     Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); 48     Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); 49  50     Mat4 modelViewMatrix; 51     Mat4::createLookAt(Vec3(0,0,5), Vec3(0,0,0), Vec3(0,-1,0), &modelViewMatrix); 52     modelViewMatrix.translate(0, 0,0 ); 53  54     static float rotation = 20; 55     modelViewMatrix.rotate(Vec3(0,1,0),CC_DEGREES_TO_RADIANS(rotation)); 56  57     Mat4 projectionMatrix; 58     Mat4::createPerspective(60, 480/320, 1.0, 42, &projectionMatrix); 59     Director::getInstance()->multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, projectionMatrix); 60     Director::getInstance()->multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, modelViewMatrix); 61  62     typedef struct { 63         float Position[3]; 64         float Color[4]; 65         float TexCoord[2]; 66     } Vertex; 67 #define TEX_COORD_MAX   1 68  69     Vertex Vertices[] = { 70         // Front 71         {{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 72         {{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 73         {{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}}, 74         {{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}}, 75         // Back 76         {{1, 1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 77         {{-1, -1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 78         {{1, -1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}}, 79         {{-1, 1, -2}, {0, 0, 0, 1}, {0, 0}}, 80         // Left 81         {{-1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 82         {{-1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 83         {{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}}, 84         {{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}}, 85         // Right 86         {{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 87         {{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 88         {{1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}}, 89         {{1, -1, 0}, {0, 0, 0, 1}, {0, 0}}, 90         // Top 91         {{1, 1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 92         {{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 93         {{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}}, 94         {{-1, 1, 0}, {0, 0, 0, 1}, {0, 0}}, 95         // Bottom 96         {{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 97         {{1, -1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 98         {{-1, -1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},  99         {{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}}100     };101     int vertexCount = sizeof(Vertices) / sizeof(Vertices[0]);102 103     GLubyte Indices[] = {104         // Front105         0, 1, 2,106         2, 3, 0,107         // Back108         4, 5, 6,109         4, 5, 7,110         // Left111         8, 9, 10,112         10, 11, 8,113         // Right114         12, 13, 14,115         14, 15, 12,116         // Top117         16, 17, 18,118         18, 19, 16,119         // Bottom120         20, 21, 22,121         22, 23, 20122     };123 124     // 1) Add to top of file125     const Vertex Vertices2[] = {126         {{0.5, -0.5, 0.01}, {1, 1, 1, 1}, {1, 1}},127         {{0.5, 0.5, 0.01}, {1, 1, 1, 1}, {1, 0}},128         {{-0.5, 0.5, 0.01}, {1, 1, 1, 1}, {0, 0}},129         {{-0.5, -0.5, 0.01}, {1, 1, 1, 1}, {0, 1}},130     };131 132     const GLubyte Indices2[] = {133         1, 0, 2, 3134     };135 136     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);137     glBufferData(GL_ARRAY_BUFFER,sizeof(Vertices),Vertices, GL_STATIC_DRAW);138 139     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);140     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices),Indices,GL_STATIC_DRAW);141 142 143     _positionLocation = glGetAttribLocation(mShaderProgram->getProgram(), "a_position");144     _colorLocation = glGetAttribLocation(mShaderProgram->getProgram(), "a_color");145 146     _textureLocation = glGetAttribLocation(mShaderProgram->getProgram(), "TextureCoord");147     _textureUniform = glGetUniformLocation(mShaderProgram->getProgram(), "CC_Texture0");148 149     mShaderProgram->use();150     mShaderProgram->setUniformsForBuiltins();151 152     glEnableVertexAttribArray(_positionLocation);153     glEnableVertexAttribArray(_colorLocation);154     glEnableVertexAttribArray(_textureLocation);155 156     glVertexAttribPointer(_positionLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Position));157 158     glVertexAttribPointer(_colorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)offsetof(Vertex, Color));159 160     glVertexAttribPointer(_textureLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),161         (GLvoid*)offsetof(Vertex, TexCoord));162     //163     ////set sampler164      GL::bindTexture2DN(0, _textureID);165     //glActiveTexture( GL_TEXTURE0 );166     //glBindTexture(GL_TEXTURE_2D, _textureID);167     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);168     glEnable(GL_BLEND);169     glEnable(GL_DEPTH_TEST);170     glDrawElements(GL_TRIANGLES,  36, GL_UNSIGNED_BYTE, 0);171     glUniform1i(_textureUniform, 0); // unnecc in practice172 173     glGenBuffers(1, &_vertexBuffer2);174     glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);175     glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices2), Vertices2, GL_STATIC_DRAW);176 177     glGenBuffers(1, &_indexBuffer2);178     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);179     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices2), Indices2, GL_STATIC_DRAW);180 181     glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);182     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);183 184     GL::bindTexture2DN(0, _textureID2);185     glUniform1i(_textureUniform, 0); // unnecc in practice186 187     glVertexAttribPointer(_positionLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);188     glVertexAttribPointer(_colorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));189     glVertexAttribPointer(_textureLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));190 191     glDrawElements(GL_TRIANGLE_STRIP, sizeof(Indices2)/sizeof(Indices2[0]), GL_UNSIGNED_BYTE, 0);192 193     CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,vertexCount);194 195     CHECK_GL_ERROR_DEBUG();196     glDisable(GL_DEPTH_TEST);197 198     Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);199     Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);200 }
CubeTexture

运行结果:

   

 

方法二,所需要的shader文件:

1 attribute vec4 a_position; 2 attribute vec2 a_texCoord;3 4 varying vec2 v_texCoord; 5 6 void main(void) {7     gl_Position = CC_MVPMatrix * a_position; 8     v_texCoord = a_texCoord;9 }
multiTexture.vert
 1 precision mediump float; 2 varying vec2 v_texCoord; 3 //uniform sampler2D s_lightMap; 4 //uniform sampler2D s_baseMap; 5  6  7 void main(void) { 8     vec4 baseColor; 9     vec4 lightColor;10     //baseColor = texture2D( s_baseMap, v_texCoord);11     //lightColor = texture2D( s_lightMap, v_texCoord );12     baseColor = texture2D( CC_Texture0, v_texCoord);13     lightColor = texture2D( CC_Texture1, v_texCoord );    14     gl_FragColor = baseColor * ( lightColor + 0.25 ); 15 }
multiTexture

所需要的图

  

头文件

 1 #ifndef _MultiTexture_H__ 2 #define _MultiTexture_H__ 3  4 #include "cocos2d.h" 5  6 using namespace cocos2d; 7  8 class MultiTexture : public cocos2d::Layer 9 {10 public:11     // there‘s no ‘id‘ in cpp, so we recommend returning the class instance pointer12     static cocos2d::Scene* createScene();13 14     // Here‘s a difference. Method ‘init‘ in cocos2d-x returns bool, instead of returning ‘id‘ in cocos2d-iphone15     virtual bool init();  16 17     virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated) override;18     //we call our actual opengl commands here19     void onDraw();20 21     // implement the "static create()" method manually22     CREATE_FUNC(MultiTexture);23 24 private:25     Mat4 _modelViewMV;26     CustomCommand _customCommand;27 28     GLProgram *mShaderProgram;29     // attribute locations 30     GLint _positionLoc;31     GLint _texCoordLoc;32 33     // sampler locations 34     GLuint _baseMapLoc;35     GLuint _lightMapLoc;36     // Texture handle 37     GLuint _baseMapTexId;38     GLuint _lightMapTexId;39     40     GLuint VAO;41     GLuint vertexBuffer;42     GLuint indexBuffer;43 44 };45 46 #endif // __HELLOWORLD_SCENE_H__
MultiTexture.h

源文件

  1 #include "MultiTexture.h"  2   3 cocos2d::Scene* MultiTexture::createScene()  4 {  5     auto scene = Scene::create();  6     auto layer = MultiTexture::create();  7     scene->addChild(layer);  8     return scene;  9 } 10  11 bool MultiTexture::init() 12 { 13     if ( Layer::init() ) 14     { 15         mShaderProgram = new GLProgram; 16         mShaderProgram->initWithFilenames("multiTexture.vert","multiTexture.frag"); 17         mShaderProgram->link(); 18         mShaderProgram->updateUniforms(); 19  20         _baseMapTexId = Director::getInstance()->getTextureCache()->addImage( "HelloWorld.png" )->getName(); 21         _lightMapTexId = Director::getInstance()->getTextureCache()->addImage("crate.jpg")->getName(); 22         glGenVertexArrays(1, &VAO); 23         glBindVertexArray(VAO); 24  25         glGenBuffers( 1, &vertexBuffer ); 26         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer ); 27  28         glGenBuffers( 1, &indexBuffer ); 29         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer ); 30  31         return true; 32     } 33     return false; 34 } 35  36 void MultiTexture::draw( Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated ) 37 { 38     Layer::draw(renderer, transform, transformUpdated); 39  40     _customCommand.init(_globalZOrder); 41     _customCommand.func = CC_CALLBACK_0(MultiTexture::onDraw,this); 42     renderer->addCommand(&_customCommand); 43 } 44  45 void MultiTexture::onDraw() 46 { 47     Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); 48     Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); 49     Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); 50     Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); 51  52     typedef struct { 53         float Position[3]; 54         float TexCoord[2]; 55     } Vertex; 56 #define TEX_COORD_MAX   1 57  58     Vertex Vertices[] = { 59  60         {{-0.5, 0.5, 0}, {0, 0}}, 61         {{-0.5, -0.5, 0}, {0, TEX_COORD_MAX}}, 62         {{0.5, -0.5, 0}, { TEX_COORD_MAX,TEX_COORD_MAX}}, 63         {{0.5, 0.5, 0}, {TEX_COORD_MAX, 0}}, 64  65     }; 66     int vertexCount = sizeof(Vertices) / sizeof(Vertices[0]); 67  68     GLubyte Indices[] = { 69         0, 1, 2, 70         2, 3, 0, 71     }; 72  73     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); 74     glBufferData(GL_ARRAY_BUFFER,sizeof(Vertices),Vertices, GL_STATIC_DRAW); 75  76     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 77     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices),Indices,GL_STATIC_DRAW); 78  79     _positionLoc = glGetAttribLocation(mShaderProgram->getProgram(), "a_position"); 80     _texCoordLoc = glGetAttribLocation(mShaderProgram->getProgram(), "a_texCoord"); 81     //_baseMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "s_baseMap"); 82     //_lightMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "s_lightMap"); 83     _baseMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "CC_Texture0"); 84     _lightMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "CC_Texture1"); 85  86     glEnableVertexAttribArray(_positionLoc); 87     glEnableVertexAttribArray(_texCoordLoc); 88  89     glVertexAttribPointer(_positionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Position)); 90     glVertexAttribPointer(_texCoordLoc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 91         (GLvoid*)offsetof(Vertex, TexCoord)); 92  93     mShaderProgram->use(); 94     mShaderProgram->setUniformsForBuiltins(); 95      96     glEnable(GL_DEPTH_TEST); 97     glBindVertexArray(VAO); 98  99     GL::bindTexture2DN(0, _lightMapTexId);100     glUniform1i(_lightMapLoc, 0 ); // unnecc in practice101 102     GL::bindTexture2DN(1, _baseMapTexId);103     glUniform1i(_baseMapLoc, 1); // unnecc in practice104 105     glDrawElements(GL_TRIANGLES,6, GL_UNSIGNED_BYTE, 0 );106 107     glBindVertexArray(0);108     CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,6);109 110     CHECK_GL_ERROR_DEBUG();111     glDisable(GL_DEPTH_TEST);112 113     Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);114     Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);115 }
MultiTexture

运行效果:

 

  

第二种方法中,

cpp内的:

//_baseMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "s_baseMap");

//_lightMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "s_lightMap");
_baseMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "CC_Texture0");
_lightMapLoc = glGetUniformLocation(mShaderProgram->getProgram(), "CC_Texture1");

和shader内的

//baseColor = texture2D( s_baseMap, v_texCoord);
//lightColor = texture2D( s_lightMap, v_texCoord );
baseColor = texture2D( CC_Texture0, v_texCoord);
lightColor = texture2D( CC_Texture1, v_texCoord );

 

将注释解开,把下面两行注掉。同样可以。这说明了,cocos2dx在进行编译shader的时候内置了多个uniform值。大家可以看一下,其中就包括CC_Texture0系列。

其实用起来不算方便了,而不注意的人,可能会声明和内置变量相同的名字,此时,咳咳咳咳咳~ shader编译的时候就会出错了。不知道为啥cocos2dx要多次一举。

还有一点:

 

////set sampler
GL::bindTexture2DN(0, _textureID);
//glActiveTexture( GL_TEXTURE0 );
//glBindTexture(GL_TEXTURE_2D, _textureID);

我使用了GL::bindTexture2DN 方法,而并没有使用opengl es原装的 glActiveTexture 和glBindTexture这两个方法。其实GL::bindTexture2DN 内部就调用了后面的两个方法,那为何不直接用后面的两个方法呢?

原因是,直接用opengl es的方法,会出错!!!尼玛 这才是坑点。跟踪后发现,cocos2dx给GL相关的东西添加了一个StateCache的东西,当activeTexture时,需要更改cache内的东西。直接调用glActiveTexture的方法,就略去了往cache内塞东西的步骤,这样就出错了。

猜测是cocos2dx进行渲染的时候,调用了cache内的什么东西。尼玛,你还能封装的再恶心一点么?

所以说,不喜欢cocos2dx这种处理问题的方法的,可以完全抛开cocos2dx了。

 

基于Cocos2d-x学习OpenGL ES 2.0之多纹理