cocos變灰圖
阿新 • • 發佈:2019-02-03
轉載出處:http://blog.csdn.net/u010223072/article/details/49640147
本人使用cocos2dx-3.3
前言:遊戲中有很多按鈕控制元件,它們一般會有選中和未選中2種狀態。我們如果要區分這兩種狀態的表現,很多時候是直接叫美術給兩種狀態下的資源,或直接setColor設定顏色。這樣無疑增加了資源的大小或不美觀(看需求)。本節將介紹怎麼通過opengl es程式來實現圖片置灰操作。
注:這個置灰操作是基於Cocos-Lua的,具體原理分析這裡不打算介紹,主要講如何實現。
實現步驟
- Lua端操作:
1,置灰Lua程式碼(ShaderEffect.lua)
local ShaderEffect = { vertDefaultSource = "\n".. "attribute vec4 a_position; \n" .. "attribute vec2 a_texCoord; \n" .. "attribute vec4 a_color; \n".. "#ifdef GL_ES \n".. "varying lowp vec4 v_fragmentColor;\n".. "varying mediump vec2 v_texCoord;\n".. "#else \n" .. "varying vec4 v_fragmentColor; \n" .. "varying vec2 v_texCoord; \n".. "#endif \n".. "void main() \n".. "{\n" .. "gl_Position = CC_PMatrix * a_position; \n".. "v_fragmentColor = a_color;\n".. "v_texCoord = a_texCoord;\n".. "}", pszFragSource2 = "#ifdef GL_ES \n" .. "precision mediump float; \n" .. "#endif \n" .. "uniform sampler2D u_texture; \n" .. "varying vec2 v_texCoord; \n" .. "varying vec4 v_fragmentColor;\n".. "uniform vec2 pix_size;\n".. "void main(void) \n" .. "{ \n" .. "vec4 sum = vec4(0, 0, 0, 0); \n" .. "sum += texture2D(u_texture, v_texCoord - 4.0 * pix_size) * 0.05;\n".. "sum += texture2D(u_texture, v_texCoord - 3.0 * pix_size) * 0.09;\n".. "sum += texture2D(u_texture, v_texCoord - 2.0 * pix_size) * 0.12;\n".. "sum += texture2D(u_texture, v_texCoord - 1.0 * pix_size) * 0.15;\n".. "sum += texture2D(u_texture, v_texCoord ) * 0.16;\n".. "sum += texture2D(u_texture, v_texCoord + 1.0 * pix_size) * 0.15;\n".. "sum += texture2D(u_texture, v_texCoord + 2.0 * pix_size) * 0.12;\n".. "sum += texture2D(u_texture, v_texCoord + 3.0 * pix_size) * 0.09;\n".. "sum += texture2D(u_texture, v_texCoord + 4.0 * pix_size) * 0.05;\n".. "gl_FragColor = sum;\n".. "}", --變灰 psGrayShader = "#ifdef GL_ES \n" .. "precision mediump float; \n" .. "#endif \n" .. "varying vec4 v_fragmentColor; \n" .. "varying vec2 v_texCoord; \n" .. "void main(void) \n" .. "{ \n" .. "vec4 c = texture2D(CC_Texture0, v_texCoord); \n" .. "gl_FragColor.xyz = vec3(0.3*c.r + 0.15*c.g +0.11*c.b); \n".. "gl_FragColor.w = c.w; \n".. "}" , --移除變灰 psRemoveGrayShader = "#ifdef GL_ES \n" .. "precision mediump float; \n" .. "#endif \n" .. "varying vec4 v_fragmentColor; \n" .. "varying vec2 v_texCoord; \n" .. "void main(void) \n" .. "{ \n" .. "gl_FragColor = texture2D(CC_Texture0, v_texCoord); \n" .. "}" , pszFragSource1 = "#ifdef GL_ES \n" .. "precision mediump float; \n" .. "#endif \n" .. "varying vec4 v_fragmentColor; \n" .. "varying vec2 v_texCoord; \n" .. "void main(void) \n" .. "{ \n" .. "vec4 c = texture2D(CC_Texture0, v_texCoord); \n" .. "gl_FragColor.xyz = vec3(0.3*c.r + 0.15*c.g +0.11*c.b); \n".. "gl_FragColor.w = c.w; \n".. "}" , } function ShaderEffect:init() local pGrayProgram = cc.GLProgram:createWithByteArrays(self.vertDefaultSource,self.psGrayShader) pGrayProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION,cc.VERTEX_ATTRIB_POSITION) pGrayProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR,cc.VERTEX_ATTRIB_COLOR) pGrayProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD,cc.VERTEX_ATTRIB_FLAG_TEX_COORDS) pGrayProgram:link() pGrayProgram:use() pGrayProgram:updateUniforms() cc.GLProgramCache:getInstance():addGLProgram(pGrayProgram,"pGrayProgram") local pRemoveGrayProgram = cc.GLProgram:createWithByteArrays(self.vertDefaultSource,self.psRemoveGrayShader) pRemoveGrayProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION,cc.VERTEX_ATTRIB_POSITION) pRemoveGrayProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR,cc.VERTEX_ATTRIB_COLOR) pRemoveGrayProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD,cc.VERTEX_ATTRIB_FLAG_TEX_COORDS) pRemoveGrayProgram:link() pRemoveGrayProgram:use() pRemoveGrayProgram:updateUniforms() cc.GLProgramCache:getInstance():addGLProgram(pRemoveGrayProgram,"pRemoveGrayProgram") end function ShaderEffect:addGrayNode(node) --變灰的 local pProgram = cc.GLProgram:createWithByteArrays(self.vertDefaultSource,self.psGrayShader) pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION,cc.VERTEX_ATTRIB_POSITION) pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR,cc.VERTEX_ATTRIB_COLOR) pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD,cc.VERTEX_ATTRIB_FLAG_TEX_COORDS) pProgram:link() pProgram:use() pProgram:updateUniforms() node:setGLProgram(pProgram) end function ShaderEffect:removeGrayNode(node) local pProgram = cc.GLProgram:createWithByteArrays(self.vertDefaultSource,self.psRemoveGrayShader) pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION,cc.VERTEX_ATTRIB_POSITION) pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR,cc.VERTEX_ATTRIB_COLOR) pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD,cc.VERTEX_ATTRIB_FLAG_TEX_COORDS) pProgram:link() pProgram:use() pProgram:updateUniforms() node:setGLProgram(pProgram) end function ShaderEffect:AddBlur(node) local fileUtiles = cc.FileUtils:getInstance() local vertSource = self.vertDefaultSource local fragSource = fileUtiles:getStringFromFile("shaders/example_Blur.fsh") local pProgram = cc.GLProgram:createWithByteArrays(vertSource, fragSource) node:setGLProgram(pProgram) --local glprogramstate = cc.GLProgramState:getOrCreateWithGLProgram(pProgram) local size = node:getTexture():getContentSizeInPixels() node:getGLProgramState():setUniformVec2("pix_size", size) node:getGLProgramState():setUniformFloat("blurRadius", 20.0); node:getGLProgramState():setUniformFloat("sampleNum", 0.1); -- -- pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION,cc.VERTEX_ATTRIB_POSITION) -- pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR,cc.VERTEX_ATTRIB_COLOR) -- pProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD,cc.VERTEX_ATTRIB_FLAG_TEX_COORDS) pProgram:link() pProgram:use() pProgram:updateUniforms() end -- 按鈕置灰 function ShaderEffect:addGrayButton(button) if button == nil then cclog("param can't be nil") return end -- 遍歷按鈕的子節點 --[[local children = button:getChildren() if children and #children>0 then for _, aSprite in ipairs(children) do if aSprite.getVirtualRenderer then self:addGrayNode(aSprite:getVirtualRenderer():getSprite()) elseif aSprite.setGLProgram then self:addGrayNode(aSprite) end end end ]] -- 按鈕本身 local sprite9 = button:getVirtualRenderer() local sprite = sprite9:getSprite() self:addGrayNode(sprite) end -- 按鈕返回正常 function ShaderEffect:removeGrayButton(button) if button == nil then cclog("param can't be nil") return end -- 按鈕本身 local sprite9 = button:getVirtualRenderer() local sprite = sprite9:getSprite() self:removeGrayNode(sprite) end --遍歷變灰 function ShaderEffect:setGrayAndChild(node,isNotRecursive) if node == nil then return end local array = node:getSpriteChildren() for key, var in pairs(array) do var:setGLProgram(cc.GLProgramCache:getInstance():getGLProgram("pGrayProgram")) end if isNotRecursive ~= true then --children local array = node:getChildren() for key, var in pairs(array) do self:setGrayAndChild(var) end end end --遍歷取消變灰 function ShaderEffect:setRemoveGrayAndChild(node,isNotRecursive) if node == nil then return end local array = node:getSpriteChildren() for key, var in pairs(array) do var:setGLProgram(cc.GLProgramCache:getInstance():getGLProgram("pRemoveGrayProgram")) end if isNotRecursive ~= true then --children local array = node:getChildren() for key, var in pairs(array) do self:setRemoveGrayAndChild(var) end end end ShaderEffect:init() return ShaderEffect
使用
local ShaderEffect = require("ShaderEffect") --載入
ShaderEffect:setGrayAndChild(Button) --置灰
ShaderEffect:setRemoveGrayAndChild(Button) --取消置灰
2c++
Lua端程式碼需要呼叫C++端擴充套件的getSpriteChildren()介面(得到控制元件的精靈物件),下面就來看看C++端怎麼來擴充套件這個介面(這裡以Button置灰為例,其它控制元件思路一樣):
1,首先在基類CCNode.h中新增這個介面,保證其它控制元件(沒有實現的)至少不會執行出錯。
virtual Vector<Node*> getSpriteChildren() { Vector<Node*> vec; return vec; } //@cxx
2,既然以按鈕控制元件為例,就先找到UIButton.h中表示按鈕精靈資訊的成員,發現是這4個變量表示:
從這裡可以看出,要得到按鈕的所有精靈,還得去Scal9Sprite類和Label類中修改,先上UIButton類中getSpriteChildren()的實現:Scale9Sprite* _buttonNormalRenderer; //初始狀態圖片 Scale9Sprite* _buttonClickedRenderer; //點選狀態圖片 Scale9Sprite* _buttonDisableRenderer;//擡起後圖片 Label* _titleRenderer; //按鈕裡文字
Vector<Node*> Button::getSpriteChildren()
{
Vector<Node*> vec;
if (_buttonNormalRenderer) {
vec.pushBack(_buttonNormalRenderer->getSpriteChildren());
}
if (_buttonClickedRenderer) {
vec.pushBack(_buttonClickedRenderer->getSpriteChildren());
}
if (_buttonDisableRenderer) {
vec.pushBack(_buttonDisableRenderer->getSpriteChildren());
}
if (_titleRenderer) {
vec.pushBack(_titleRenderer->getSpriteChildren());
}
return vec;
}
3,上面按鈕圖片資源資料既然是返回的Scale9Sprite物件的指標,那我們就得去這個類中得到精靈資訊,具體getSpriteChildren()的實現如下:
Vector<Node*> Scale9Sprite::getSpriteChildren()
{
Vector<Node*> vec;
if (_scale9Image) {
vec.pushBack(_scale9Image);
}
if (_topLeftSprite) {
vec.pushBack(_topLeftSprite);
}
if (_topSprite) {
vec.pushBack(_topSprite);
}
if (_topRightSprite) {
vec.pushBack(_topRightSprite);
}
if (_leftSprite) {
vec.pushBack(_leftSprite);
}
if (_centerSprite) {
vec.pushBack(_centerSprite);
}
if (_rightSprite) {
vec.pushBack(_rightSprite);
}
if (_bottomLeftSprite) {
vec.pushBack(_bottomLeftSprite);
}
if (_bottomSprite) {
vec.pushBack(_bottomSprite);
}
if (_bottomRightSprite) {
vec.pushBack(_bottomRightSprite);
}
return vec;
}
4,按鈕的文字資料返回的是Label物件指標,同樣,我們得去Label類中實現getSpriteChildren()得到文字的精靈,程式碼如下:
Vector<Node*> Label::getSpriteChildren()
{
Vector<Node*> vec;
if (_textSprite) {
vec.pushBack(_textSprite);
}
return vec;
}
5,好,這樣按鈕的4個相關精靈資料都能得到了,接下來就是tolua繫結到Lua端呼叫,如何繫結,前面章節有介紹。(Lua Shader那邊反正是要最終得到 Sprite* 精靈物件來進行處理,遇到間接的紋理物件就一層一層的剝吧…)