【複習筆記】 cocos2d-x 2.x 渲染特效實現 七 輝光效果
阿新 • • 發佈:2019-01-22
輝光效果經常用來做一些物體的自發光,這種發光效果不需要光照計算,只是在貼圖上進行發光的模擬效果,所以有著很好的效率。輝光效果意味著貼圖會變亮。為了對發光的部分做計算,需要一張glowmap貼圖,當我們使用src和dst都為GL_ONE的方式,混合glowmap和原圖時,原圖就會對按照glowmap的樣子變亮了~但是作為輝光的效果,僅僅只有變亮是不夠的,由於光線在穿過空氣時亮度會衰減,所以周圍會有一圈逐漸消失的光暈。所以我們利用原圖的模糊貼圖的做glowmap,這樣輝光就會有很好的光暈效果了~因為簡單模糊效果不夠細膩,光暈效果會不是很好,所以我們用高斯模糊來實現~
這次,我們需要對一個節點樹的做高斯模糊處理,原因是這樣之後,可以實現節點樹的輝光效果,另外,單張貼圖圖片邊緣不能模糊延伸的問題也可以得到解決~由於之前高斯模糊是需要做一次RTT才能實現的,而在這之前,要得到節點樹的整屏貼圖也要做一次RTT,所以,這次渲染過程中包含有兩次RTT,按照先後順序,具體作用分別是:生成節點樹的貼圖,做橫向的高斯模糊。
由於在shader中重用了高斯模糊,橫向和縱向兩次的渲染程式碼,所以利用u_BlurDis[1]變數還區分是當前是橫向處理還是縱向處理,並且在第二次縱向處理最終可以生成高斯模糊之後,順便使模糊貼圖透明,發亮,並用一般混合方式(ONE,ONE減SCR ALPHA)在發亮貼圖下混合源貼圖。fragment shader程式碼如下:void CCEffectSprite::visitGlow() { float blursDis[2] = {_pixelSpan/_screenBufferSize.width, _pixelSpan/_screenBufferSize.height}; GLint size = sizeof(ccV3F_C4B_T2F); long data = (long)&m_sQuad; /**/ // gen a empty texture glGenTextures(1, &_texture); glBindTexture(GL_TEXTURE_2D, _texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _screenBufferSize.width, _screenBufferSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // gen a off-screen framebuffer GLint oldFBO; glGetIntegerv(GL_RENDERBUFFER_BINDING, &oldFBO); glGenFramebuffers(1, &_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { CCLOG("glCheckFramebufferStatus ERROR! 0x%04x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); } // ************ first draw ****************** CCNode::visit(); // ****************************************** // gen a empty texture GLuint _texture2; glGenTextures(1, &_texture2); glBindTexture(GL_TEXTURE_2D, _texture2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _screenBufferSize.width, _screenBufferSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // gen a off-screen framebuffer GLuint _framebuffer2; glGenFramebuffers(1, &_framebuffer2); glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer2); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture2, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { CCLOG("glCheckFramebufferStatus ERROR! 0x%04x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); } // ************** second draw ***************** // reset stack kmGLMatrixMode(KM_GL_MODELVIEW); kmGLPushMatrix(); kmGLLoadIdentity(); kmGLMatrixMode(KM_GL_PROJECTION); kmGLPushMatrix(); kmGLLoadIdentity(); glViewport(0, 0, _screenBufferSize.width, _screenBufferSize.height); CC_NODE_DRAW_SETUP(); ccGLBlendFunc(m_sBlendFunc.src, m_sBlendFunc.dst); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _texture); ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex); // uniforms glUniform2f(_uniforms[kUniformBlurDis], blursDis[0], 0.0f); // attributes ccV3F_C4B_T2F_Quad tempQuad; memset(&tempQuad, 0, sizeof(tempQuad)); tempQuad.tl.vertices = vertex3(-1, 1, -1); tempQuad.bl.vertices = vertex3(-1, -1, -1); tempQuad.tr.vertices = vertex3(1, 1, -1); tempQuad.br.vertices = vertex3(1, -1, -1); tempQuad.tl.colors = ccc4(255, 255, 255, 255); tempQuad.bl.colors = ccc4(255, 255, 255, 255); tempQuad.tr.colors = ccc4(255, 255, 255, 255); tempQuad.br.colors = ccc4(255, 255, 255, 255); tempQuad.tl.texCoords = tex2(0, 1); tempQuad.bl.texCoords = tex2(0, 0); tempQuad.tr.texCoords = tex2(1, 1); tempQuad.br.texCoords = tex2(1, 0); data = (long)&tempQuad; glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, size, (GLvoid *)data); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, size, (GLvoid *)(data + sizeof(ccVertex3F))); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, size, (GLvoid *)(data + sizeof(ccVertex3F) + sizeof(ccColor4B))); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // ************************************** // ************** third draw ***************** glBindFramebuffer(GL_FRAMEBUFFER, oldFBO); CC_NODE_DRAW_SETUP(); ccGLBlendFunc(m_sBlendFunc.src, m_sBlendFunc.dst); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _texture2); ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex); // uniforms glUniform2f(_uniforms[kUniformBlurDis], 0.0f, blursDis[1]); // attributes glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, size, (GLvoid *)data); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, size, (GLvoid *)(data + sizeof(ccVertex3F))); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, size, (GLvoid *)(data + sizeof(ccVertex3F) + sizeof(ccColor4B))); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // ************************************** // restore stack kmGLMatrixMode(KM_GL_PROJECTION); kmGLPopMatrix(); kmGLMatrixMode(KM_GL_MODELVIEW); kmGLPopMatrix(); CCDirector::sharedDirector()->setViewport(); /**/ glDeleteTextures(1, &_texture); glDeleteFramebuffers(1, &_framebuffer); glDeleteTextures(1, &_texture2); glDeleteFramebuffers(1, &_framebuffer2); }
程式碼中,利用高斯模糊貼影象素乘以0.5,並把其透明變為原來的0.1倍後才作為glowmap使用~這樣會有好一點的發亮效果~最終效果如下:uniform sampler2D CC_Texture0; uniform sampler2D u_Texture1; uniform sampler2D u_Texture2; uniform vec2 u_BlurDis; varying vec4 v_Color; varying vec2 v_TexCoord; void main() { /**/ vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0); finalColor += texture2D(CC_Texture0, v_TexCoord - u_BlurDis * 4.0) * 0.05; finalColor += texture2D(CC_Texture0, v_TexCoord - u_BlurDis * 3.0) * 0.09; finalColor += texture2D(CC_Texture0, v_TexCoord - u_BlurDis * 2.0) * 0.12; finalColor += texture2D(CC_Texture0, v_TexCoord - u_BlurDis * 1.0) * 0.15; finalColor += texture2D(CC_Texture0, v_TexCoord) * 0.18; finalColor += texture2D(CC_Texture0, v_TexCoord + u_BlurDis * 1.0) * 0.15; finalColor += texture2D(CC_Texture0, v_TexCoord + u_BlurDis * 2.0) * 0.12; finalColor += texture2D(CC_Texture0, v_TexCoord + u_BlurDis * 3.0) * 0.09; finalColor += texture2D(CC_Texture0, v_TexCoord + u_BlurDis * 4.0) * 0.05; if (u_BlurDis[1] == 0.0) { gl_FragColor = v_Color * finalColor; } else { vec4 originColor = texture2D(CC_Texture0, v_TexCoord); vec4 blurColor = v_Color * finalColor; vec4 glowColor = blurColor * 0.5; glowColor.a = glowColor.a * 0.1; gl_FragColor = glowColor + (1.0 - glowColor.a) * originColor; } }