没想到原文出了那么多错别字,实在对不起观众了。介绍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) { // 4 10 DestinationColor = a_color; // 5 11 v_texCoord = TextureCoord; 12 gl_Position = CC_MVPMatrix * a_position; // 6 13 }
1 varying vec4 DestinationColor; // 1 2 varying vec2 v_texCoord; 3 4 void main(void) { // 2 5 6 gl_FragColor = DestinationColor * texture2D(CC_Texture0, v_texCoord) ; // 3 7 }
所用到的两张图
头文件:
#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__
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 // Front 105 0, 1, 2, 106 2, 3, 0, 107 // Back 108 4, 5, 6, 109 4, 5, 7, 110 // Left 111 8, 9, 10, 112 10, 11, 8, 113 // Right 114 12, 13, 14, 115 14, 15, 12, 116 // Top 117 16, 17, 18, 118 18, 19, 16, 119 // Bottom 120 20, 21, 22, 121 22, 23, 20 122 }; 123 124 // 1) Add to top of file 125 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, 3 134 }; 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 sampler 164 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 practice 172 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 practice 186 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 }
运行结果:
方法二,所需要的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 }
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.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 practice 101 102 GL::bindTexture2DN(1, _baseMapTexId); 103 glUniform1i(_baseMapLoc, 1); // unnecc in practice 104 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 }
运行效果:
第二种方法中,
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了。