为了完成一些特效(比如,角色狂暴,但双脚又被石化),有时需要使用GL ES的的纹理缓冲(代码未整理):
void MySprite::myDraw(const cocos2d::Mat4 &transform)
{
do
{
GLint maxSizeOfFrameTexture = 0;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSizeOfFrameTexture);
if (contentSize.width > maxSizeOfFrameTexture || contentSize.height > maxSizeOfFrameTexture)
{
CCASSERT(false, "指定的纹理大小无效");
break;
}
<span style="white-space:pre"> </span>GLint viewport[4];
<span style="white-space:pre"> </span>glGetIntegerv(GL_VIEWPORT, viewport);<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>glViewport(0, 0, contentSize.width, contentSize.height);// 一定不能漏掉
GLuint frameBuffer[2];
GLuint frameTexture[2];
glGenFramebuffers(2, frameBuffer);
glGenTextures(2, frameTexture);
// 下面将纹理this->_texture->getName()的狂暴效果绘制到纹理frameTexture[0]中
// function usingFrameTexture()
cocos2d::GL::bindTexture2DN(textureUnit, frameTexture[0]);//textureUnit:GL ES中使用的是GL_TEXTURE0、GL_TEXTURE1等等,在cocos2d::GL中使用的是索引,即GL_TEXTUREXXX-GL_TEXTURE0
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, contentSize.width, contentSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameTexture[0], 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)//帧缓冲不完整,无法继续
{
glDeleteFramebuffers(2, frameBuffer);
glDeleteTextures(2, frameTexture);
break;;
}
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
// 此处使用狂暴着色器,绘画狂暴效果,使用的纹理为this->_texture->getName()
// ...
// 至此,狂暴效果将被绘制到纹理frameTexture[0]中
// 下面将纹理frameTexture[0]的脚部石化效果绘制到纹理frameTexture[1]中(还应当用到模板缓冲,此处省略了)
if (!usingFrameTexture(frameTexture[1], ...)) break;
// 此处使用石化着色器,绘画石化效果,使用的纹理为frameTexture[0]
// ...
// 至此,石化效果将被绘制到纹理frameTexture[1]中
// 下面将纹理frameTexture[1]绘制主缓冲
<span style="white-space:pre"> </span>glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);// 恢复视区
glBindFramebuffer(GL_FRAMEBUFFER, 0);
static cocos2d::GLProgram* program = cocos2d::GLProgramCache::getInstance()->getGLProgram(cocos2d::GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP);
program->use();
cocos2d::V3F_C4B_T2F_Quad realQuad = this->_quad;
transform.transformPoint(&realQuad.bl.vertices);
transform.transformPoint(&realQuad.br.vertices);
transform.transformPoint(&realQuad.tl.vertices);
transform.transformPoint(&realQuad.tr.vertices);
mySpriteDrawHelper().setup(&realQuad, 1, nullptr, 0);
cocos2d::GL::blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
cocos2d::GLProgramState::getOrCreateWithGLProgram(program)->apply(cocos2d::Mat4::ZERO);//仅使用P矩阵,因此apply中传入的数值不会被用到
cocos2d::GL::bindTexture2DN(textureUnit, frameTexture[1]);
static GLuint sampler0Location = program->getUniformLocation(cocos2d::GLProgram::UNIFORM_NAME_SAMPLER0);
program->setUniformLocationWith1i(sampler0Location, textureUnit); // 在上面的apply函数中,写死了UNIFORM_NAME_SAMPLER0的值为0,此处需要作出修正
glDrawArrays(GL_QUAD_STRIP, 0, 4);
<span style="white-space:pre"> </span>// 由于cocos2dx的缓冲机制,此处需要恢复program的sampler0Location
<span style="white-space:pre"> </span>program->setUniformLocationWith1i(sampler0Location, 0);
mySpriteDrawHelper().unsetup();
#if CC_ENABLE_GL_STATE_CACHE
cocos2d::GL::bindTexture2DN(textureUnit, -1);//不知道为何,不加本句的话会导致纹理错误(cocos2dx的bug?)
#endif
glDeleteFramebuffers(2, frameBuffer);
glDeleteTextures(2, frameTexture);
} while (false);//用do-while是为了在发生错误时可以立即中断操作,然后执行后续的操作(比如清理)
// ...
CHECK_GL_ERROR_DEBUG();
}