加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Cocos2D-X shader(四) 利用shader改变图片色相(Hue)

发布时间:2020-12-14 17:20:46 所属栏目:百科 来源:网络整理
导读:背景 美术给出一套资源后,可以通过改变图片色相,复用同一套资源产生出多套资源的效果: 上图中蓝色是原始图片,利用代码改变图片色相后,可以产生效果差异明显的资源出来。像一些传统的游戏,如星际争霸等,都是通过这种技术实现了同一兵种,不同颜色种族

背景

美术给出一套资源后,可以通过改变图片色相,复用同一套资源产生出多套资源的效果:


上图中蓝色是原始图片,利用代码改变图片色相后,可以产生效果差异明显的资源出来。像一些传统的游戏,如星际争霸等,都是通过这种技术实现了同一兵种,不同颜色种族的特效。

实现理论原理

看上去非常神奇的转换,实际上是利用了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

普通代码实现

利用上述转换公式,实现代码如下(透明像素不处理):

[cpp] view plain copy
  1. <spanstyle="font-family:SimSun;font-size:14px;">Texture2D*HelloWorld::initTextureWithImage(Image*image,float_fhue)
  2. {
  3. unsignedchar*tempData=NULL;
  4. boolhasAlpha=image->hasAlpha();
  5. SizeimageSize=Size((float)(image->getWidth()),(float)(image->getHeight()));
  6. Texture2D::PixelFormatpixelFormat;
  7. unsignedintwidth=image->getWidth();
  8. unsignedintheight=image->getHeight();
  9. //Repackthepixeldataintotherightformat
  10. unsignedintlength=width*height;
  11. unsignedintnewDataLen=0;
  12. //Convert"RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"to"RRRRRRRRGGGGGGGGBBBBBBBB"
  13. float_f=_fhue/60;//节省运算
  14. if(hasAlpha)
  15. {
  16. //computepixelformat
  17. pixelFormat=Texture2D::PixelFormat::RGBA8888;
  18. tempData=newunsignedchar[length*4];
  19. newDataLen=length*4;
  20. unsignedchar*outPixel8=tempData;
  21. unsignedint*inPixel32=(unsignedint*)image->getData();
  22. for(unsignedinti=0;i<length;++i,++inPixel32)
  23. {
  24. unsignedchar*_colRGB=outPixel8;
  25. *outPixel8++=(*inPixel32>>0)&0xFF;//R
  26. *outPixel8++=(*inPixel32>>8)&0xFF;//G
  27. *outPixel8++=(*inPixel32>>16)&0xFF;//B
  28. *outPixel8=(*inPixel32>>24)&0xFF;//A
  29. //透明图层不做处理
  30. if(*outPixel8++)
  31. {
  32. unsignedchar_r=*_colRGB;
  33. unsignedchar_g=*(_colRGB+1);
  34. unsignedchar_b=*(_colRGB+2);
  35. unsignedcharmin=(_r<_g)?_r:_g;
  36. min=(min<_b)?min:_b;
  37. unsignedcharmax=(_r>_g)?_r:_g;
  38. max=(max>_b)?max:_b;
  39. unsignedchartemp=(max-min);
  40. floathsbH=0;//temp
  41. if(temp)
  42. {
  43. if(max==_r){
  44. if(_g>=_b)
  45. {
  46. hsbH=(float)(_g-_b)/(float)temp;
  47. }
  48. else
  49. {
  50. hsbH=((float)(_g-_b)/(float)temp)+6;
  51. }
  52. }
  53. elseif(max==_g){
  54. hsbH=((float)(_b-_r)/(float)temp)+2;
  55. }
  56. elseif(max==_b){
  57. hsbH=((float)(_r-_g)/(float)temp)+4;
  58. }
  59. }
  60. else
  61. {
  62. hsbH=0;
  63. }
  64. hsbH+=_f;
  65. if(hsbH<0)
  66. hsbH+=6;
  67. elseif(hsbH>6)
  68. hsbH-=6;
  69. chari=(int)hsbH;
  70. hsbH=hsbH-i;
  71. switch(i){
  72. case6:
  73. case0:
  74. (*_colRGB++)=max;
  75. (*_colRGB++)=min+(int)(hsbH*temp);
  76. (*_colRGB++)=min;
  77. break;
  78. case1:
  79. (*_colRGB++)=max-(int)(hsbH*temp);
  80. (*_colRGB++)=max;
  81. (*_colRGB++)=min;
  82. break;
  83. case2:
  84. (*_colRGB++)=min;
  85. (*_colRGB++)=max;
  86. (*_colRGB++)=min+(int)(hsbH*temp);
  87. break;
  88. case3:
  89. (*_colRGB++)=min;
  90. (*_colRGB++)=max-(int)(hsbH*temp);
  91. (*_colRGB++)=max;
  92. break;
  93. case4:
  94. (*_colRGB++)=min+(int)(hsbH*temp);
  95. (*_colRGB++)=min;
  96. (*_colRGB++)=max;
  97. break;
  98. case5:
  99. (*_colRGB++)=max;
  100. (*_colRGB++)=min;
  101. (*_colRGB++)=max-(int)(hsbH*temp);
  102. break;
  103. default:
  104. break;
  105. }
  106. }
  107. }
  108. }
  109. else
  110. {
  111. pixelFormat=Texture2D::PixelFormat::RGB888;
  112. tempData=newunsignedchar[length*3];
  113. newDataLen=length*3;
  114. unsignedchar*out3=image->getData();
  115. unsignedchar*outPixel8=tempData;
  116. for(unsignedinti=0;i<length;++i)
  117. {
  118. unsignedchar_r=*out3++;
  119. unsignedchar_g=*out3++;
  120. unsignedchar_b=*out3++;
  121. //changeHSLForRgb(255,0);
  122. //unsignedchar*_nowRGB=changeHSLForRgb(_r,_g,_b,_fhue);
  123. //_r=*_nowRGB++;
  124. //_g=*_nowRGB++;
  125. //_b=*_nowRGB++;
  126. *outPixel8++=_r;//R
  127. *outPixel8++=_g;//G
  128. *outPixel8++=_b;//B
  129. }
  130. }
  131. Texture2D*_text2d=newTexture2D();
  132. _text2d->initWithData(tempData,newDataLen,pixelFormat,width,height,imageSize);
  133. delete[]tempData;
  134. //_text2d->_hasPremultipliedAlpha=image->hasPremultipliedAlpha();
  135. return_text2d;
  136. }</span>

利用Shader实现

Shader可以利用GPU提升渲染效率:

colorHSL.fsh

[cpp] view plain copy
  1. #ifdefGL_ES
  2. precisionmediumpfloat;
  3. #endif
  4. varyingvec2v_texCoord;
  5. uniformsampler2DCC_Texture0;
  6. uniformfloatu_dH;
  7. uniformfloatu_dS;
  8. uniformfloatu_dL;
  9. voidmain(){
  10. vec4texColor=texture2D(CC_Texture0,v_texCoord);
  11. floatr=texColor.r;
  12. floatg=texColor.g;
  13. floatb=texColor.b;
  14. floata=texColor.a;
  15. //convertrgbtohsl
  16. floath;
  17. floats;
  18. floatl;
  19. {
  20. floatmax=max(max(r,g),b);
  21. floatmin=min(min(r,b);
  22. //----h
  23. if(max==min){
  24. h=0.0;
  25. }elseif(max==r&&g>=b){
  26. h=60.0*(g-b)/(max-min)+0.0;
  27. }elseif(max==r&&g<b){
  28. h=60.0*(g-b)/(max-min)+360.0;
  29. }elseif(max==g){
  30. h=60.0*(b-r)/(max-min)+120.0;
  31. }elseif(max==b){
  32. h=60.0*(r-g)/(max-min)+240.0;
  33. }
  34. //----l
  35. l=0.5*(max+min);
  36. //----s
  37. if(l==0.0||max==min){
  38. s=0.0;
  39. }elseif(0.0<=l&&l<=0.5){
  40. s=(max-min)/(2.0*l);
  41. }elseif(l>0.5){
  42. s=(max-min)/(2.0-2.0*l);
  43. }
  44. }
  45. //(h,s,l)+(dH,dS,dL)->(h,l)
  46. h=h+u_dH;
  47. s=min(1.0,max(0.0,s+u_dS));
  48. l=l+u_dL;
  49. //convert(h,l)torgbandgotfinalcolor
  50. vec4finalColor;
  51. {
  52. floatq;
  53. if(l<0.5){
  54. q=l*(1.0+s);
  55. }elseif(l>=0.5){
  56. q=l+s-l*s;
  57. }
  58. floatp=2.0*l-q;
  59. floathk=h/360.0;
  60. floatt[3];
  61. t[0]=hk+1.0/3.0;t[1]=hk;t[2]=hk-1.0/3.0;
  62. for(inti=0;i<3;i++){
  63. if(t[i]<0.0)t[i]+=1.0;
  64. if(t[i]>1.0)t[i]-=1.0;
  65. }//gott[i]
  66. floatc[3];
  67. for(inti=0;i<3;i++){
  68. if(t[i]<1.0/6.0){
  69. c[i]=p+((q-p)*6.0*t[i]);
  70. }elseif(1.0/6.0<=t[i]&&t[i]<0.5){
  71. c[i]=q;
  72. }elseif(0.5<=t[i]&&t[i]<2.0/3.0){
  73. c[i]=p+((q-p)*6.0*(2.0/3.0-t[i]));
  74. }else{
  75. c[i]=p;
  76. }
  77. }
  78. finalColor=vec4(c[0],c[1],c[2],a);
  79. }
  80. finalColor+=vec4(u_dL,u_dL,0.0);
  81. gl_FragColor=finalColor;
  82. }

以下适用COCOS2.2版本

.H中增加以下代码

[cpp] view plain copy
  1. voidsetHSLMode();
  2. voidsetHSL(floath,floats,floatl);
  3. voidupdateHSL();
  4. floatm_dH;
  5. floatm_dS;
  6. floatm_dL;
  7. GLuintm_dHlocation;
  8. GLuintm_dSlocation;
  9. GLuintm_dLlocation;


具体实现

[cpp] view plain copy
  1. voidGameColorSprite::setHSLMode(){
  2. ccBlendFuncblendFunc={GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA};
  3. this->setBlendFunc(blendFunc);
  4. GLchar*fragSource=(GLchar*)CCString::createWithContentsOfFile(CCFileUtils::sharedFileUtils()->fullPathForFilename("colorHSL.fsh").c_str())->getCString();
  5. CGLProgramWithUnifos*pProgram=newCGLProgramWithUnifos();
  6. pProgram->initWithVertexShaderByteArray(ccPositionTextureColor_vert,fragSource);
  7. this->setShaderProgram(pProgram);
  8. pProgram->release();
  9. CHECK_GL_ERROR_DEBUG();
  10. this->getShaderProgram()->addAttribute(kCCAttributeNamePosition,kCCVertexAttrib_Position);
  11. this->getShaderProgram()->addAttribute(kCCAttributeNameColor,kCCVertexAttrib_Color);
  12. this->getShaderProgram()->addAttribute(kCCAttributeNameTexCoord,kCCVertexAttrib_TexCoords);
  13. CHECK_GL_ERROR_DEBUG();
  14. this->getShaderProgram()->link();
  15. CHECK_GL_ERROR_DEBUG();
  16. this->getShaderProgram()->updateUniforms();
  17. CHECK_GL_ERROR_DEBUG();
  18. m_dHlocation=glGetUniformLocation(getShaderProgram()->getProgram(),"u_dH");
  19. m_dSlocation=glGetUniformLocation(getShaderProgram()->getProgram(),"u_dS");
  20. m_dLlocation=glGetUniformLocation(getShaderProgram()->getProgram(),"u_dL");
  21. updateHSL();
  22. }

[cpp] view plain copy
  1. voidGameColorSprite::setHSL(floath,floatl){
  2. m_dH=h;
  3. m_dS=s;
  4. m_dL=l;
  5. updateHSL();
  6. }

[cpp] view plain copy
  1. voidGameColorSprite::updateHSL(){
  2. glUniform1f(m_dHlocation,m_dH);
  3. glUniform1f(m_dSlocation,m_dS);
  4. glUniform1f(m_dLlocation,m_dL);
  5. }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读