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

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

概述背景 美术给出一套资源后,可以通过改变图片色相,复用同一套资源产生出多套资源的效果: 上图中蓝色是原始图片,利用代码改变图片色相后,可以产生效果差异明显的资源出来。像一些传统的游戏,如星际争霸等,都是通过这种技术实现了同一兵种,不同颜色种族的特效。 实现理论原理 看上去非常神奇的转换,实际上是利用了HSV格式图像处理的技术: 传统RGB模型:RGB是一种加色模式 将不同比例的RED/GREEN/B 背景

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


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

实现理论原理

看上去非常神奇的转换,实际上是利用了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 <spanstyle="Font-family:Simsun;Font-size:14px;">Texture2D*HelloWorld::initTextureWithImage(Image*image,float_fhue) { unsignedchar*tempData=NulL; boolhasAlpha=image->hasAlpha(); SizeimageSize=Size((float)(image->getWIDth()),(float)(image->getHeight())); Texture2D::PixelFormatpixelFormat; unsignedintwIDth=image->getWIDth(); unsignedintheight=image->getHeight(); //Repackthepixeldataintotherightformat unsignedintlength=wIDth*height; unsignedintnewDataLen=0; //Convert"RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"to"RRRRRRRRGGGGGGGGBBBBBBBB" float_f=_fhue/60;//节省运算 if(hasAlpha) { //computepixelformat pixelFormat=Texture2D::PixelFormat::RGBA8888; tempData=newunsignedchar[length*4]; newDataLen=length*4; unsignedchar*outPixel8=tempData; unsignedint*inPixel32=(unsignedint*)image->getData(); for(unsignedinti=0;i<length;++i,++inPixel32) { unsignedchar*_colRGB=outPixel8; *outPixel8++=(*inPixel32>>0)&0xFF;//R *outPixel8++=(*inPixel32>>8)&0xFF;//G *outPixel8++=(*inPixel32>>16)&0xFF;//B *outPixel8=(*inPixel32>>24)&0xFF;//A //透明图层不做处理 if(*outPixel8++) { unsignedchar_r=*_colRGB; unsignedchar_g=*(_colRGB+1); unsignedchar_b=*(_colRGB+2); unsignedcharmin=(_r<_g)?_r:_g; min=(min<_b)?min:_b; unsignedcharmax=(_r>_g)?_r:_g; max=(max>_b)?max:_b; unsignedchartemp=(max-min); floathsbH=0;//temp if(temp) { if(max==_r){ if(_g>=_b) { hsbH=(float)(_g-_b)/(float)temp; } else { hsbH=((float)(_g-_b)/(float)temp)+6; } } elseif(max==_g){ hsbH=((float)(_b-_r)/(float)temp)+2; } elseif(max==_b){ hsbH=((float)(_r-_g)/(float)temp)+4; } } else { hsbH=0; } hsbH+=_f; if(hsbH<0) hsbH+=6; elseif(hsbH>6) hsbH-=6; chari=(int)hsbH; hsbH=hsbH-i; switch(i){ case6: case0: (*_colRGB++)=max; (*_colRGB++)=min+(int)(hsbH*temp); (*_colRGB++)=min; break; case1: (*_colRGB++)=max-(int)(hsbH*temp); (*_colRGB++)=max; (*_colRGB++)=min; break; case2: (*_colRGB++)=min; (*_colRGB++)=max; (*_colRGB++)=min+(int)(hsbH*temp); break; case3: (*_colRGB++)=min; (*_colRGB++)=max-(int)(hsbH*temp); (*_colRGB++)=max; break; case4: (*_colRGB++)=min+(int)(hsbH*temp); (*_colRGB++)=min; (*_colRGB++)=max; break; case5: (*_colRGB++)=max; (*_colRGB++)=min; (*_colRGB++)=max-(int)(hsbH*temp); break; default: break; } } } } else { pixelFormat=Texture2D::PixelFormat::RGB888; tempData=newunsignedchar[length*3]; newDataLen=length*3; unsignedchar*out3=image->getData(); unsignedchar*outPixel8=tempData; for(unsignedinti=0;i<length;++i) { unsignedchar_r=*out3++; unsignedchar_g=*out3++; unsignedchar_b=*out3++; //changeHSLForRgb(255,0); //unsignedchar*_NowRGB=changeHSLForRgb(_r,_g,_b,_fhue); //_r=*_NowRGB++; //_g=*_NowRGB++; //_b=*_NowRGB++; *outPixel8++=_r;//R *outPixel8++=_g;//G *outPixel8++=_b;//B } } Texture2D*_text2d=newTexture2D(); _text2d->initWithData(tempData,newDataLen,pixelFormat,wIDth,height,imageSize); delete[]tempData; //_text2d->_hasPremultiplIEdAlpha=image->hasPremultiplIEdAlpha(); return_text2d; }</span>
利用Shader实现

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

colorHSL.fsh

[cpp] view plain copy #ifdefGL_ES precisionmediumpfloat; #endif varyingvec2v_texCoord; uniformsampler2DCC_Texture0; uniformfloatu_dH; uniformfloatu_dS; uniformfloatu_dL; voIDmain(){ vec4texcolor=texture2D(CC_Texture0,v_texCoord); floatr=texcolor.r; floatg=texcolor.g; floatb=texcolor.b; floata=texcolor.a; //convertrgbtohsl floath; floats; floatl; { floatmax=max(max(r,g),b); floatmin=min(min(r,b); //----h if(max==min){ h=0.0; }elseif(max==r&&g>=b){ h=60.0*(g-b)/(max-min)+0.0; }elseif(max==r&&g<b){ h=60.0*(g-b)/(max-min)+360.0; }elseif(max==g){ h=60.0*(b-r)/(max-min)+120.0; }elseif(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; }elseif(0.0<=l&&l<=0.5){ s=(max-min)/(2.0*l); }elseif(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)torgbandgotfinalcolor vec4finalcolor; { floatq; if(l<0.5){ q=l*(1.0+s); }elseif(l>=0.5){ q=l+s-l*s; } floatp=2.0*l-q; floathk=h/360.0; floatt[3]; t[0]=hk+1.0/3.0;t[1]=hk;t[2]=hk-1.0/3.0; for(inti=0;i<3;i++){ if(t[i]<0.0)t[i]+=1.0; if(t[i]>1.0)t[i]-=1.0; }//gott[i] floatc[3]; for(inti=0;i<3;i++){ if(t[i]<1.0/6.0){ c[i]=p+((q-p)*6.0*t[i]); }elseif(1.0/6.0<=t[i]&&t[i]<0.5){ c[i]=q; }elseif(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中增加以下代码

[cpp] view plain copy voIDsetHSLMode(); voIDsetHSL(floath,floats,floatl); voIDupdateHSL(); floatm_dH; floatm_dS; floatm_dL; gluintm_dhlocation; gluintm_dSlocation; gluintm_dLlocation;

具体实现

[cpp] view plain copy voIDGamecolorSprite::setHSLMode(){ ccBlendFuncblendFunc={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=newCGLProgramWithUnifos(); 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(); }
[cpp] view plain copy voIDGamecolorSprite::setHSL(floath,floatl){ m_dH=h; m_dS=s; m_dL=l; updateHSL(); }
[cpp] view plain copy voIDGamecolorSprite::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)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1083655.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-27
下一篇 2022-05-27

发表评论

登录后才能评论

评论列表(0条)

保存