【复习笔记】 cocos2d-x 2.x 渲染特效实现 八 流光效果

简单来说,流光效果就是在贴图上利用glowmap在原贴图上的移动做动态的发亮效果,来让贴图看起来有光亮在移动。为了让贴图上的亮斑的排布看起来更加贴近自然,我们利用柏林噪声来生成glowmap。事实上,二维或者三维的柏林噪声在图形学上有很多的应用,它可以用来描述很多自然的数学规律,使程序模拟出来的效果看起来更加像是自然生成的。比如墙上的斑点,起伏的海面的高度,熔岩中火焰的亮暗等等。柏林噪声需要振幅和频率两个参数,利用噪声函数生成需要的数据。这里不展开论述,网上有很多相关资料。

为了可以直接利用数据,提高程序效率,我们不使用噪声函数来计算,而是利用预先生成好的一组噪声数据:

unsigned char perm[256] = {151,160,137,91,90,15,
	131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
	190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
	88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,
	77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
	102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,
	135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,
	5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
	223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,
	129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,
	251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,
	49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,
	138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180};

这个数组就是一个二维的柏林噪声数据,可以直接拿这个数据来生成一张glowmap的灰度图~可以先渲染出这个噪声灰度图:

CCTexture2D *noise = new CCTexture2D();
	noise->initWithData(perm, kCCTexture2DPixelFormat_A8, 16, 16, CCSizeMake(16, 16));
	test->setTexture(noise);
	rect.setRect(0, 0, noise->getContentSize().width, noise->getContentSize().height);
    test->setTextureRect(rect);

图中的深色部分就是原贴图中发亮的区域了~同理,如果是用来模拟海面的话,深色的地方凸起,浅色的地方凹陷,就可以模拟出高低不平的海面了,其他用途亦同理~按照我们之前使图片发亮的混合方式,把灰度图和原图相加,额外处理原图透明像素依然透明,这时原图就按照灰度图上的斑点分布发亮了~

我们既然做的是动态的流光效果,那么静止的发亮显然是不够的~为了能让这些亮斑动起来,我们使用UV动画。shader中在读取texture数据的时候,使用的是texture的UV坐标,即图片左上角为(0, 0),右下角为(1, 1)。所以只需要在读取texture数据的时候,把对应的坐标做变化即可~为了控制贴图按时间移动,用cocos添加的一个uniform变量CC_Time进行控制,简单修改fragment shader代码即可实现:

uniform sampler2D CC_Texture0;
uniform sampler2D u_Texture1;
uniform vec2 u_BlurDis;

varying vec4 v_Color;
varying vec2 v_TexCoord;

void main()
{
    vec4 originColor = texture2D(CC_Texture0, v_TexCoord);
	float per = fract(CC_Time.y * 0.3);
	float x = v_TexCoord.x + per;
	if (x > 1 ) { x = x - 1; }
	float y = v_TexCoord.y + per;
	if (y > 1 ) { y = y - 1; }
	vec4 glowColor = texture2D(u_Texture1, vec2(x, y));
	
	originColor.r = (originColor.r + glowColor.a) * originColor.a;
	originColor.g = (originColor.g + glowColor.a) * originColor.a;
	originColor.b = (originColor.b + glowColor.a) * originColor.a;
	gl_FragColor = originColor;
}

为了可以在shader中读取噪声贴图,在C++代码中传入该贴图数据:

。。。
_uniforms[kUniformSampler1] = glGetUniformLocation(program->getProgram(), UniformSampler1);
。。。
glUniform1i(_uniforms[kUniformSampler1], 1);
。。。
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _texture1->getName());
代码中,fract函数是shader内置的函数,用于取小数点后面的部分。因为UV坐标区间为0~1,所以恰好利用时间的小数点后来做UV移动的动画效果~因为UV坐标的从水平和竖直方向上都有等量的增加,所以流光的移动也以45度方向进行。最终效如下:

【复习笔记】 cocos2d-x 2.x 渲染特效实现 八 流光效果_第1张图片

你可能感兴趣的:(cocos2d-x,OpenGL,ES,2.0,shader)