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

普通代码实现

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

<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)所遇到的程序开发问题。

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

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存