原文链接 : http://www.cocoachina.com/bbs/read.php?tid=282479
首先是shader文件
hueChange.fsh
varying vec2 v_texCoord; uniform mat3 u_hue; uniform float u_alpha; void main() { vec4 pixColor = texture2D(CC_Texture0, v_texCoord); vec3 rgbColor ; rgbColor = u_hue * pixColor.rgb; gl_FragColor = vec4(rgbColor.r,rgbColor.g,rgbColor.b, pixColor.a * u_alpha); } hueChange.vsh attribute vec4 a_position; attribute vec2 a_texCoord; attribute vec4 a_color; varying vec2 v_texCoord; void main() { gl_Position = CC_PMatrix * a_position; v_texCoord = a_texCoord; } CCSpriteWithHue.h #ifndef __SnippetsProject__CCSpriteWithHue__ #define __SnippetsProject__CCSpriteWithHue__ #include "cocos2d.h" USING_NS_CC; class CCSpriteWithHue :public Sprite { private://variable GLint m_hueLocation; GLint m_alphaLocation; protected://variable public://variable CC_SYNTHESIZE_READONLY(GLfloat, m_hue, Hue); private://method protected://method virtual void setupDefaultSettings(); virtual void getUniformLocations(); virtual void updateColorMatrix(); virtual void updateAlpha(); virtual GLfloat alpha(); virtual void updateColor(); virtual bool initWithTexture(Texture2D *texture, const Rect& rect, bool rotated); virtual void initShader(); public://method CCSpriteWithHue(); virtual ~CCSpriteWithHue(); static CCSpriteWithHue* create(const std::string& filename); virtual void setHue(GLfloat _hue); };CCSpriteWithHue.cpp
#include "CCSpriteWithHue.h" void xRotateMat(float mat[3][3], float rs, float rc); void yRotateMat(float mat[3][3], float rs, float rc); void zRotateMat(float mat[3][3], float rs, float rc); void matrixMult(float a[3][3], float b[3][3], float c[3][3]); void hueMatrix(GLfloat mat[3][3], float angle); void premultiplyAlpha(GLfloat mat[3][3], float alpha); CCSpriteWithHue::CCSpriteWithHue() { } CCSpriteWithHue::~CCSpriteWithHue() { } CCSpriteWithHue* CCSpriteWithHue::create(const std::string& filename) { CCSpriteWithHue *sprite = new (std::nothrow) CCSpriteWithHue(); if (sprite && sprite->initWithFile(filename)) { sprite->autorelease(); return sprite; } CC_SAFE_DELETE(sprite); return nullptr; } bool CCSpriteWithHue::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated) { if (!Sprite::initWithTexture(texture, rect, rotated)) { return false; } this->setupDefaultSettings(); this->initShader(); return true; } void CCSpriteWithHue::setupDefaultSettings() { this->m_hue = 0.0; } void CCSpriteWithHue::initShader() { GLProgram * p = new GLProgram(); this->setGLProgram(p); p->release(); p->initWithFilenames("hueChange.vsh", "hueChange.fsh"); p->link(); p->updateUniforms(); this->getUniformLocations(); this->updateColor(); } void CCSpriteWithHue::getUniformLocations() { m_hueLocation = glGetUniformLocation(this->getGLProgram()->getProgram(), "u_hue"); m_alphaLocation = glGetUniformLocation(this->getGLProgram()->getProgram(), "u_alpha"); } void CCSpriteWithHue::updateColorMatrix() { this->getGLProgram()->use(); GLfloat mat[3][3]; memset(mat, 0, sizeof(GLfloat)*9); hueMatrix(mat, m_hue); premultiplyAlpha(mat, this->alpha()); glUniformMatrix3fv(m_hueLocation, 1, GL_FALSE, (GLfloat *)&mat); } void CCSpriteWithHue::updateAlpha() { this->getGLProgram()->use(); glUniform1f(m_alphaLocation, this->alpha()); } GLfloat CCSpriteWithHue::alpha() { return _displayedOpacity / 255.0f; } void CCSpriteWithHue::setHue(GLfloat _hue) { m_hue = _hue; this->updateColorMatrix(); } void CCSpriteWithHue::updateColor() { Sprite::updateColor(); this->updateColorMatrix(); this->updateAlpha(); } #pragma mark - void xRotateMat(float mat[3][3], float rs, float rc) { mat[0][0] = 1.0; mat[0][1] = 0.0; mat[0][2] = 0.0; mat[1][0] = 0.0; mat[1][1] = rc; mat[1][2] = rs; mat[2][0] = 0.0; mat[2][1] = -rs; mat[2][2] = rc; } void yRotateMat(float mat[3][3], float rs, float rc) { mat[0][0] = rc; mat[0][1] = 0.0; mat[0][2] = -rs; mat[1][0] = 0.0; mat[1][1] = 1.0; mat[1][2] = 0.0; mat[2][0] = rs; mat[2][1] = 0.0; mat[2][2] = rc; } void zRotateMat(float mat[3][3], float rs, float rc) { mat[0][0] = rc; mat[0][1] = rs; mat[0][2] = 0.0; mat[1][0] = -rs; mat[1][1] = rc; mat[1][2] = 0.0; mat[2][0] = 0.0; mat[2][1] = 0.0; mat[2][2] = 1.0; } void matrixMult(float a[3][3], float b[3][3], float c[3][3]) { int x, y; float temp[3][3]; for(y=0; y<3; y++) { for(x=0; x<3; x++) { temp[y][x] = b[y][0] * a[0][x] + b[y][1] * a[1][x] + b[y][2] * a[2][x]; } } for(y=0; y<3; y++) { for(x=0; x<3; x++) { c[y][x] = temp[y][x]; } } } void hueMatrix(GLfloat mat[3][3], float angle) { #define SQRT_2 sqrt(2.0) #define SQRT_3 sqrt(3.0) float mag, rot[3][3]; float xrs, xrc; float yrs, yrc; float zrs, zrc; // Rotate the grey vector into positive Z mag = SQRT_2; xrs = 1.0/mag; xrc = 1.0/mag; xRotateMat(mat, xrs, xrc); mag = SQRT_3; yrs = -1.0/mag; yrc = SQRT_2/mag; yRotateMat(rot, yrs, yrc); matrixMult(rot, mat, mat); // Rotate the hue zrs = sin(angle); zrc = cos(angle); zRotateMat(rot, zrs, zrc); matrixMult(rot, mat, mat); // Rotate the grey vector back into place yRotateMat(rot, -yrs, yrc); matrixMult(rot, mat, mat); xRotateMat(rot, -xrs, xrc); matrixMult(rot, mat, mat); } void premultiplyAlpha(GLfloat mat[3][3], float alpha) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { mat[i][j] *= alpha; } } }使用实例
CCSpriteWithHue *hueSprite = CCSpriteWithHue::create("HelloWorld.png"); hueSprite->setHue(1.6);//值在 0 ~ 2 Pi 之间 hueSprite->setPosition(visibleSize.width / 2, visibleSize.height / 2); this->addChild(hueSprite); 运行效果
setHue(1.6):
setHue(2.6):
setHue(3.6):
