《捕鱼达人》教程2:鱼身上的波光处理

2015年03月16日 11:45 0 点赞 0 评论 更新于 2025-11-21 17:08

在上一节的学习中,我们初步掌握了如何使用Cocos2d - x加载鱼的模型并播放鱼的动画。在本节教程中,我们将深入学习如何为鱼的模型添加波光处理,以营造出波光粼粼的效果,让鱼看起来仿佛在海水中游动。

波光效果的实现原理

为模型添加波光效果是通过纹理动画来实现的。其核心原理是为模型增加一个纹理,并循环移动纹理贴图寻址的UV坐标。这样,贴在模型表面的纹理就会根据不断变化的UV值产生贴图运动的效果。接下来,我们将逐步实现这个效果。

所需资源

我们需要用到以下资源:

  1. Shader文件UVAnimation.vshUVAnimation.fsh,它们位于Resources\\3D目录中。其中,UVAnimation.vsh是一个用于模型骨骼动画计算的Shader,而UV动画的效果则在UVAnimation.fsh中进行处理。以下是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; }

2. **波光图**:`caustics.png`,这是一张黑白图,用于在模型上进行色值操作。黑色区域的色值为0,与鱼原来的纹理色值相加后保持不变;而白色区域的值大于0,与鱼原来的纹理色值相加后会产生增亮效果。这张图应放置在工程的`Resources\\3D`目录中。

## 代码实现步骤

### 1. 在FishLayer中添加变化的UV值
在`FishLayer`类中添加一个`Vec2`类型的变量`_lightani`,用于存储变化的UV值。

Vec2 _lightani;


### 2. 组合Shader并应用到鱼模型
在`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;


### 3. 重载FishLayer的draw函数
重载`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); }


## 编译运行
完成上述代码编写后,编译并运行程序,你将看到小海龟身上的波纹不断运动,仿佛在海里游泳一样。

通过以上步骤,我们成功完成了鱼身上的波光处理。你可以亲自尝试一下,看看鱼在添加波光效果后是否变得更加逼真了。

作者信息

boke

boke

共发布了 3994 篇文章