没想到原文出了那么多错别字,实在对不起观众了。介绍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 }
所需要的图
头文件
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 pointer
12 static cocos2d::Scene* createScene();
13
14 // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
15 virtual bool init();
16
17 virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated) override;
18 //we call our actual opengl commands here
19 void onDraw();
20
21 // implement the "static create()" method manually
22 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__
源文件
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了。
