背景

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


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

实现理论原理

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

Cocos2D-X shader(四) 利用shader改变图片色相Hue的更多相关文章

  1. ios – 由于未捕获的异常终止应用程序“Texture Atlas Not Found”

    我创建了一个使用SpriteKit的简单动画项目.它运行良好,没有问题.当我将工作副本中的文件合并时,会出现该错误.以下是控制台中的消息:2013-10-0910:52:14.777MyProject[1550:a0b]*Terminatingappduetouncaughtexception‘TextureAtlasNotFound’,reason:‘TextureAtlasNotFound’我

  2. ios – 在Swift中找不到Double类型的初始化程序

    我想将我从文本字段获取的String值转换为Double值并存储它,但是我继续收到错误,它找不到类型为Double的intializer,该类型接受参数列表类型.如何解决这个问题?解决方法如果你有一个名为temp的String,你应该可以使用转换为Double值.

  3. ios – 将CALayer设置为SCNMaterial的漫反射内容

    过去几天,我一直在互联网上搜索无效.不幸的是,关于这个具体问题的苹果文档是模糊的,没有示例代码可用.什么似乎是你可能会问的问题?我试过玩漫漫的内容变换矩阵,但没有任何修改.我也尝试将UIView的大小调整为256×256,但是并没有修复任何东西.这是图层的代码:编辑甚至更严厉的是,如果我使用以下方式捕获视图的UIImage:并使用它作为弥漫的内容…一切工作完全正常吗?这是真的很奇怪和令人沮丧,因为图像的大小是完全一样的uiview的…

  4. ios – GPUImage为每个RGB通道添加色调/颜色调整(调整红色以更加粉红色或橙色)

    试图调整特定频道的色调.看着色调过滤器,我想也许我可以通过评论绿色和蓝色修饰符,影响到只有红色通道的变化:但是,这张照片就是灰色/蓝色,被冲洗掉或是紫色的绿色.我在正确的轨道上吗?

  5. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  6. Swift基础篇——可选类型

    可选类型

  7. Swift OS X NSColectonView显示网络列表数据

    运行一下现在按照API返回的数量超过5个,实际上这是可以滚动的。所以解析的时候只对前五个赋值即可。

  8. (Swift+iOS)字符串轨迹转贝塞尔曲线,实现动态写字效果

    前两天下载了一个Swift的HUD提示效果,偶然发现其中的提示效果上面的文字是动态书写的。

  9. 早期Swift中Cocos2D初始化代码的重构

    但是遗憾的是Swift2.2中还是不支持Type的class属性关键字,只能用static,我们期待Swift3的改进吧!

  10. Swift 实现二叉搜索树 —— 创建,最大,最小,查找,插入,删除,前驱,后继,中序遍历

    了解了二叉堆之后,二叉搜索树就好说了,就是一个节点,左边的子节点是不可能比他大的,右边的子节点是一定大于它的,想了半天终于把创建给写好了。创建最大值和最小值查找插入删除删除好做,但是得找到那个能顶替它原来位置的节点,我这里只是打印出来,因为没有父节点,不好去找,所以就没做。。前驱后继中序遍历就酱,还是蛮有成就感的。要是不对,咱们一起讨论,当然里面的一些极端情况我没有做判断,只是想着熟悉下思路。

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部