美术给出一套资源后,可以通过改变图片色相,复用同一套资源产生出多套资源的效果:
上图中蓝色是原始图片,利用代码改变图片色相后,可以产生效果差异明显的资源出来。像一些传统的游戏,如星际争霸等,都是通过这种技术实现了同一兵种,不同颜色种族的特效。
实现理论原理看上去非常神奇的转换,实际上是利用了HSV格式图像处理的技术:
传统RGB模型:RGB是一种加色模式 将不同比例的RED/GREEN/BLUE混合在一起得到新的颜色
HSV(HSB)模型:通过色相/饱和度/亮度来得到颜色
H(hue):色相 表示颜色的类型 值域[0,360]
S(Saturation):饱和度 从灰度到纯色 值域[0,1]
V(Value or Brightness):亮度 从黑色到特定饱和度的颜色 值域[0,1]
HSV模型图
RGB到HSV的转换公式
HSV到RGB的转换公式
公式可以参考
http://baike.baidu.com/subview/541362/8445478.htm?fr=aladdin
利用上述转换公式,实现代码如下(透明像素不处理):
<span >Texture2D* HelloWorld::initTextureWithImage(Image *image,float _fhue){ unsigned char* tempData = NulL; bool hasAlpha = image->hasAlpha(); Size imageSize = Size((float)(image->getWIDth()),(float)(image->getHeight())); Texture2D::PixelFormat pixelFormat; unsigned int wIDth = image->getWIDth(); unsigned int height = image->getHeight(); // Repack the pixel data into the right format unsigned int length = wIDth * height; unsigned int newDataLen = 0; // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBBB" float _f = _fhue / 60; //节省运算 if (hasAlpha) { // compute pixel format pixelFormat = Texture2D::PixelFormat::RGBA8888; tempData = new unsigned char[length * 4]; newDataLen = length * 4; unsigned char *outPixel8 = tempData; unsigned int* inPixel32 = (unsigned int*)image->getData(); for (unsigned int i = 0; i < length; ++i,++inPixel32) { unsigned char* _colRGB = outPixel8; *outPixel8++ = (*inPixel32 >> 0) & 0xFF; // R *outPixel8++ = (*inPixel32 >> 8) & 0xFF; // G *outPixel8++ = (*inPixel32 >> 16) & 0xFF; // B *outPixel8 = (*inPixel32 >> 24) & 0xFF; // A //透明图层不做处理 if (*outPixel8++) { unsigned char _r = *_colRGB; unsigned char _g = *(_colRGB + 1); unsigned char _b = *(_colRGB + 2); unsigned char min = (_r < _g) ? _r : _g; min = (min < _b) ? min : _b; unsigned char max = (_r > _g) ? _r : _g; max = (max > _b) ? max : _b; unsigned char temp = (max - min); float hsbH = 0; //temp if (temp) { if (max == _r) { if (_g >= _b) { hsbH = (float)(_g - _b) / (float)temp; } else { hsbH = ((float)(_g - _b) / (float)temp) + 6; } } else if (max == _g) { hsbH = ((float)(_b - _r) / (float)temp) + 2; } else if (max == _b) { hsbH = ((float)(_r - _g) / (float)temp) + 4; } } else { hsbH = 0; } hsbH += _f; if (hsbH < 0) hsbH += 6; else if (hsbH > 6) hsbH -= 6; char i = (int)hsbH; hsbH = hsbH - i; switch (i) { case 6: case 0: (*_colRGB++) = max; (*_colRGB++) = min + (int)(hsbH*temp); (*_colRGB++) = min; break; case 1: (*_colRGB++) = max - (int)(hsbH*temp); (*_colRGB++) = max; (*_colRGB++) = min; break; case 2: (*_colRGB++) = min; (*_colRGB++) = max; (*_colRGB++) = min + (int)(hsbH*temp); break; case 3: (*_colRGB++) = min; (*_colRGB++) = max - (int)(hsbH*temp); (*_colRGB++) = max; break; case 4: (*_colRGB++) = min + (int)(hsbH*temp); (*_colRGB++) = min; (*_colRGB++) = max; break; case 5: (*_colRGB++) = max; (*_colRGB++) = min; (*_colRGB++) = max - (int)(hsbH*temp); break; default: break; } } } } else { pixelFormat = Texture2D::PixelFormat::RGB888; tempData = new unsigned char[length * 3]; newDataLen = length * 3; unsigned char *out3 = image->getData(); unsigned char *outPixel8 = tempData; for (unsigned int i = 0; i < length; ++i) { unsigned char _r = *out3++; unsigned char _g = *out3++; unsigned char _b = *out3++; //changeHSLForRgb(255,0); // unsigned char *_NowRGB = changeHSLForRgb(_r,_g,_b,_fhue); // _r = *_NowRGB++; // _g = *_NowRGB++; // _b = *_NowRGB++; *outPixel8++ = _r; // R *outPixel8++ = _g; // G *outPixel8++ = _b; // B } } Texture2D* _text2d = new Texture2D(); _text2d->initWithData(tempData,newDataLen,pixelFormat,wIDth,height,imageSize); delete[] tempData; //_text2d->_hasPremultiplIEdAlpha = image->hasPremultiplIEdAlpha(); return _text2d;}</span>
利用Shader实现
Shader可以利用GPU提升渲染效率:
colorHSL.fsh
#ifdef GL_ESprecision mediump float;#endifvarying vec2 v_texCoord;uniform sampler2D CC_Texture0;uniform float u_dH;uniform float u_dS;uniform float u_dL;voID main() { vec4 texcolor=texture2D(CC_Texture0,v_texCoord); float r=texcolor.r; float g=texcolor.g; float b=texcolor.b; float a=texcolor.a; //convert rgb to hsl float h; float s; float l; { float max=max(max(r,g),b); float min=min(min(r,b); //----h if(max==min){ h=0.0; }else if(max==r&&g>=b){ h=60.0*(g-b)/(max-min)+0.0; }else if(max==r&&g<b){ h=60.0*(g-b)/(max-min)+360.0; }else if(max==g){ h=60.0*(b-r)/(max-min)+120.0; }else if(max==b){ h=60.0*(r-g)/(max-min)+240.0; } //----l l=0.5*(max+min); //----s if(l==0.0||max==min){ s=0.0; }else if(0.0<=l&&l<=0.5){ s=(max-min)/(2.0*l); }else if(l>0.5){ s=(max-min)/(2.0-2.0*l); } } //(h,s,l)+(dH,dS,dL) -> (h,l) h=h+u_dH; s=min(1.0,max(0.0,s+u_dS)); l=l+u_dL; //convert (h,l) to rgb and got final color vec4 finalcolor; { float q; if(l<0.5){ q=l*(1.0+s); }else if(l>=0.5){ q=l+s-l*s; } float p=2.0*l-q; float hk=h/360.0; float t[3]; t[0]=hk+1.0/3.0;t[1]=hk;t[2]=hk-1.0/3.0; for(int i=0;i<3;i++){ if(t[i]<0.0)t[i]+=1.0; if(t[i]>1.0)t[i]-=1.0; }//got t[i] float c[3]; for(int i=0;i<3;i++){ if(t[i]<1.0/6.0){ c[i]=p+((q-p)*6.0*t[i]); }else if(1.0/6.0<=t[i]&&t[i]<0.5){ c[i]=q; }else if(0.5<=t[i]&&t[i]<2.0/3.0){ c[i]=p+((q-p)*6.0*(2.0/3.0-t[i])); }else{ c[i]=p; } } finalcolor=vec4(c[0],c[1],c[2],a); } finalcolor+=vec4(u_dL,u_dL,0.0); gl_Fragcolor=finalcolor;}
以下适用COCOS2.2版本
.H中增加以下代码
voID setHSLMode();voID setHSL(float h,float s,float l);voID updateHSL();float m_dH;float m_dS;float m_dL;gluint m_dhlocation;gluint m_dSlocation;gluint m_dLlocation;
具体实现
voID GamecolorSprite::setHSLMode(){ ccBlendFunc blendFunc={GL_SRC_Alpha,GL_ONE_MINUS_SRC_Alpha}; this->setBlendFunc(blendFunc); GLchar * fragSource = (GLchar*) CCString::createWithContentsOffile(CCfileUtils::sharedfileUtils()->fullPathForfilename("colorHSL.fsh").c_str())->getCString(); CGLProgramWithUnifos* pProgram = new CGLProgramWithUnifos(); pProgram->initWithVertexShaderByteArray(ccpositionTexturecolor_vert,fragSource); this->setShaderProgram(pProgram); pProgram->release(); CHECK_GL_ERROR_DEBUG(); this->getShaderProgram()->addAttribute(kCCAttributenameposition,kCCVertexAttrib_position); this->getShaderProgram()->addAttribute(kCCAttributenamecolor,kCCVertexAttrib_color); this->getShaderProgram()->addAttribute(kCCAttributenameTexCoord,kCCVertexAttrib_TexCoords); CHECK_GL_ERROR_DEBUG(); this->getShaderProgram()->link(); CHECK_GL_ERROR_DEBUG(); this->getShaderProgram()->updateUniforms(); CHECK_GL_ERROR_DEBUG(); m_dhlocation = glGetUniformlocation(getShaderProgram()->getProgram(),"u_dH"); m_dSlocation = glGetUniformlocation(getShaderProgram()->getProgram(),"u_dS"); m_dLlocation = glGetUniformlocation(getShaderProgram()->getProgram(),"u_dL"); updateHSL();}
voID GamecolorSprite::setHSL(float h,float l){ m_dH = h; m_dS = s; m_dL = l; updateHSL();}
voID GamecolorSprite::updateHSL(){ gluniform1f(m_dhlocation,m_dH); gluniform1f(m_dSlocation,m_dS); gluniform1f(m_dLlocation,m_dL);}总结
以上是内存溢出为你收集整理的Cocos2D-X shader(四) 利用shader改变图片色相(Hue)全部内容,希望文章能够帮你解决Cocos2D-X shader(四) 利用shader改变图片色相(Hue)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)