在上一节的学习中,我们已经掌握了如何使用Cocos2d-x加载鱼的模型和播放鱼的动画,这一节我们来学习一下如何为鱼的模型增加波光处理,以使它看起来像在海水中游动。
在模型的身上加入波光的感觉,是通过纹理动画来实现的,其原理是给模型增加一个纹理,并循环的移动纹理贴图寻址的UV坐标,这样贴在模型表面的纹理就会按照不断变化的UV值来产生出贴图运动的效果。下面我们来实际做一下这个效果。
我们需要用到Shader文件UVAnimation.vsh和UVAnimation.fsh,它们在Resources\3D目录中。 UVAnimation.vsh是一个模型骨骼动画的计算Shader,而UV动画的效果在UVAnimation.fsh中进行处理:
- uniform sampler2D u_texture1;
- uniform sampler2D u_lightTexture;
- uniform vec4 v_LightColor; //颜色色彩
- uniform vec2 v_animLight; //UV动画纹理偏移
- varying vec2 v_texCoord; //模型的纹理UV值
- void main(void)
- {
- //通过UV值的移动形成UV动画
- vec4 lightcolor = texture2D(u_lightTexture, v_texCoord + v_animLight.xy) * v_LightColor;
- gl_FragColor = texture2D(u_texture1, v_texCoord) + lightcolor;
- }
然后我们需要一张波光图caustics.png,它是黑白图,用于在模型上增加色值操作,这样的话,黑色的区域色值为0,与鱼原来的纹理色值相加不变,而白色区域的值大于0,与鱼原来的纹理色值相加后会有增亮效果。这张图我们放在工程的Resources\3D目录中。
我们在FishLayer中增加一个变化的UV值:
- Vec2 _lightani;
在FishLayer::init函数中,我们将上面所写的vsh,fsh等组合成鱼模型可以使用的Shader并使用它:
- // 取得文件管理器
- auto fileUtiles = FileUtils::getInstance();
- // 加载相应的Shader文件
- // 加载UVAnimation.vsh并取得文件内容字符串
- auto vertexFilePath = fileUtiles->fullPathForFilename("UVAnimation.vsh");
- auto vertSource = fileUtiles->getStringFromFile(vertexFilePath);
- // 加载UVAnimation.fsh并取得文件内容字符串
- auto fragmentFilePath = fileUtiles->fullPathForFilename("UVAnimation.fsh");
- auto fragSource = fileUtiles->getStringFromFile(fragmentFilePath);
- // 将vsh与fsh装配成一个完整的Shader文件。
- auto glprogram = GLProgram::createWithByteArrays(vertSource.c_str(), fragSource.c_str());
- // 由Shader文件创建这个Shader
- auto glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram);
- // 给精灵设置所用的Shader
- _sprite->setGLProgramState(glprogramstate);
- //创建海龟所用的贴图。
- auto textrue1 = Director::getInstance()->getTextureCache()->addImage("tortoise.png");
- //将贴图设置给Shader中的变量值u_texture1
- glprogramstate->setUniformTexture("u_texture1", textrue1);
- //创建波光贴图。
- auto textrue2 = Director::getInstance()->getTextureCache()->addImage("caustics.png");
- //将贴图设置给Shader中的变量值u_lightTexture
- glprogramstate->setUniformTexture("u_lightTexture", textrue2);
- //注意,对于波光贴图,我们希望它在进行UV动画时能产生四方连续效果,必须设置它的纹理UV寻址方式为GL_REPEAT。
- Texture2D::TexParams tRepeatParams;
- tRepeatParams.magFilter = GL_LINEAR_MIPMAP_LINEAR;
- tRepeatParams.minFilter = GL_LINEAR;
- tRepeatParams.wrapS = GL_REPEAT;
- tRepeatParams.wrapT = GL_REPEAT;
- textrue2->setTexParameters(tRepeatParams);
- //在这里,我们设置一个波光的颜色,这里设置为白色。
- Vec4 tLightColor(1.0,1.0,1.0,1.0);
- glprogramstate->setUniformVec4("v_LightColor",tLightColor);
- //下面这一段,是为了将我们自定义的Shader与我们的模型顶点组织方式进行匹配。模型的顶点数据一般包括位置,法线,色彩,纹理,以及骨骼绑定信息。而Shader需要将内部相应的顶点属性通道与模型相应的顶点属性数据进行绑定才能正确显示出顶点。
- long offset = 0;
- auto attributeCount = _sprite->getMesh()->getMeshVertexAttribCount();
- for (auto k = 0; k < attributeCount; k++) {
- auto meshattribute = _sprite->getMesh()->getMeshVertexAttribute(k);
- glprogramstate->setVertexAttribPointer(s_attributeNames[meshattribute.vertexAttrib],
- meshattribute.size,
- meshattribute.type,
- GL_FALSE,
- _sprite->getMesh()->getVertexSizeInBytes(),
- (GLvoid*)offset);
- offset += meshattribute.attribSizeBytes;
- }
- //uv滚动初始值设为0
- _lightani.x = _lightani.y = 0;
之后我们重载一下FishLayer的draw函数,加入UV值的变化处理和设置。
- void FishLayer::draw(Renderer* renderer, const Mat4 &transform, uint32_t flags)
- {
- if(_sprite)
- {
- auto glprogramstate = _sprite->getGLProgramState();
- if(glprogramstate)
- {
- _lightani.x += 0.01;
- if(_lightani.x > 1.0)
- {
- _lightani.x-= 1.0;
- }
- _lightani.y += 0.01;
- if(_lightani.y > 1.0)
- {
- _lightani.y-= 1.0;
- }
- glprogramstate->setUniformVec2("v_animLight",_lightani);
- }
- }
- Node::draw(renderer,transform,flags);
- }
这样,我们就完成了鱼身上的波光处理。