Shaer的使用
由于纹理图的背景色为黑色,所以英雄的周围总是有一圈黑框,Dierctx中直接提供了去除背景色的函数,但是cocos2d-x却没有,所以要解决这个问题只能通过两种方法,一是美工做图的时候直接使背景色透明,二是自己写Shader来去除背景色。
Cocos2d-x在类CCNode中提供了着色器的 成员变量,而CCSprite继承与CCNode,因此可以通过继承CCSprite并重写相关函数的方式来达到想要的效果。
添加一个类继承 CCSprite
class ColorSprite : public CCSprite
{
public:
static ColorSprite* create(const char* pszFileName);
virtual bool initWithTexture(CCTexture2D *pTexture);
virtual bool initWithSpriteFrame(CCSpriteFrame *pSpriteFrame);
virtual void draw(void);
};
ColorSprte.cpp
实现去除黑色背景的Shader,直接保存在一个字符串中
static const GLchar *transparentshader =
"\n\
#ifdef GL_ES \n\
precision lowp float; \n\
#endif \n\
varying vec4 v_fragmentColor; \n\
varying vec2 v_texCoord; \n\
uniform sampler2D u_texture; \n\
void main() \n\
{ \n\
float ratio=0.0; \n\
vec4 texColor = texture2D(u_texture, v_texCoord); \n\
ratio = texColor[0] > texColor[1]?(texColor[0] > texColor[2] ? texColor[0] : texColor[2]) :(texColor[1] > texColor[2]? texColor[1] : texColor[2]); \n\
if (ratio != 0.0) \n\
{ \n\
texColor[3] = ratio; \n\
} \n\
else \n\
{ \n\
texColor[3] = 0.0; \n\
} \n\
gl_FragColor = v_fragmentColor*texColor; \n\
}";
重写函数
ColorSprite* ColorSprite::create(const char *pszFileName)
{
ColorSprite *pRet = new ColorSprite();
if (pRet && pRet->initWithFile(pszFileName))
{
pRet->autorelease();
return pRet;
}else{
delete pRet;
pRet = NULL;
return NULL;
}
}
cocos2d-x的着色器提供两个加载shader的函数:
//通过保存了Shader的字符串加载Shader
initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
//通过文件加载Shader
initWithVertexShaderFilename(const char* vShaderFilename, const char* fShaderFilename)
bool ColorSprite::initWithSpriteFrame(CCSpriteFrame *pSpriteFrame)
{
CCAssert(pSpriteFrame != NULL, "");
bool bRet = initWithTexture(pSpriteFrame->getTexture());
// 加载顶点着色器和片元着色器
m_pShaderProgram = new CCGLProgram();
m_pShaderProgram ->initWithVertexShaderByteArray(ccPositionTextureA8Color_vert, transparentshader);
CHECK_GL_ERROR_DEBUG();
// 启用顶点着色器的attribute变量,坐标、纹理坐标、颜色
m_pShaderProgram->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
m_pShaderProgram->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
m_pShaderProgram->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
CHECK_GL_ERROR_DEBUG();
// 自定义着色器链接
m_pShaderProgram->link();
CHECK_GL_ERROR_DEBUG();
// 设置移动、缩放、旋转矩阵
m_pShaderProgram->updateUniforms();
CHECK_GL_ERROR_DEBUG();
setDisplayFrame(pSpriteFrame);
return bRet;
}
void ColorSprite::draw(void)
{
// CCLog("override draw!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");
CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called");
CC_NODE_DRAW_SETUP();
// 启用attributes变量输入,顶点坐标,纹理坐标,颜色
//
ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
ccGLBlendFunc(m_sBlendFunc.src, m_sBlendFunc.dst);
m_pShaderProgram->use();
m_pShaderProgram->setUniformsForBuiltins();
// 绑定纹理到纹理槽0
ccGLBindTexture2D(m_pobTexture->getName());
#define kQuadSize sizeof(m_sQuad.bl)
long offset = (long)&m_sQuad;
// vertex
int diff = offsetof( ccV3F_C4B_T2F, vertices);
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
// texCoods
diff = offsetof( ccV3F_C4B_T2F, texCoords);
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
// color
diff = offsetof( ccV3F_C4B_T2F, colors);
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
CHECK_GL_ERROR_DEBUG();
CC_INCREMENT_GL_DRAWS(1);
CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");
}
将原本的声明替换为ColorSprite * heroSprite; 并修改相关初始化方法;
程序执行效果如下