《捕魚達(dá)人3》講解Cocos引擎3D:魚身波光處理
在上一節(jié)的學(xué)習(xí)中,我們已經(jīng)掌握了如何使用Cocos2d-x加載魚的模型和播放魚的動(dòng)畫,這一節(jié)我們來(lái)學(xué)習(xí)一下如何為魚的模型增加波光處理,以使它看起來(lái)像在海水中游動(dòng)。
在模型的身上加入波光的感覺(jué),是通過(guò)紋理動(dòng)畫來(lái)實(shí)現(xiàn)的,其原理是給模型增加一個(gè)紋理,并循環(huán)的移動(dòng)紋理貼圖尋址的UV坐標(biāo),這樣貼在模型表面的紋理就會(huì)按照不斷變化的UV值來(lái)產(chǎn)生出貼圖運(yùn)動(dòng)的效果。下面我們來(lái)實(shí)際做一下這個(gè)效果。
我們需要用到Shader文件UVAnimation.vsh和UVAnimation.fsh,它們?cè)赗esources\3D目錄中。 UVAnimation.vsh是一個(gè)模型骨骼動(dòng)畫的計(jì)算Shader,而UV動(dòng)畫的效果在UVAnimation.fsh中進(jìn)行處理:
- uniform sampler2D u_texture1;
- uniform sampler2D u_lightTexture;
- uniform vec4 v_LightColor; //顏色色彩
- uniform vec2 v_animLight; //UV動(dòng)畫紋理偏移
- varying vec2 v_texCoord; //模型的紋理UV值
- void main(void)
- {
- //通過(guò)UV值的移動(dòng)形成UV動(dòng)畫
- vec4 lightcolor = texture2D(u_lightTexture, v_texCoord + v_animLight.xy) * v_LightColor;
- gl_FragColor = texture2D(u_texture1, v_texCoord) + lightcolor;
- }
然后我們需要一張波光圖caustics.png,它是黑白圖,用于在模型上增加色值操作,這樣的話,黑色的區(qū)域色值為0,與魚原來(lái)的紋理色值相加不變,而白色區(qū)域的值大于0,與魚原來(lái)的紋理色值相加后會(huì)有增亮效果。這張圖我們放在工程的Resources\3D目錄中。
我們?cè)贔ishLayer中增加一個(gè)變化的UV值:
- Vec2 _lightani;
在FishLayer::init函數(shù)中,我們將上面所寫的vsh,fsh等組合成魚模型可以使用的Shader并使用它:
- // 取得文件管理器
- auto fileUtiles = FileUtils::getInstance();
- // 加載相應(yīng)的Shader文件
- // 加載UVAnimation.vsh并取得文件內(nèi)容字符串
- auto vertexFilePath = fileUtiles->fullPathForFilename("UVAnimation.vsh");
- auto vertSource = fileUtiles->getStringFromFile(vertexFilePath);
- // 加載UVAnimation.fsh并取得文件內(nèi)容字符串
- auto fragmentFilePath = fileUtiles->fullPathForFilename("UVAnimation.fsh");
- auto fragSource = fileUtiles->getStringFromFile(fragmentFilePath);
- // 將vsh與fsh裝配成一個(gè)完整的Shader文件。
- auto glprogram = GLProgram::createWithByteArrays(vertSource.c_str(), fragSource.c_str());
- // 由Shader文件創(chuàng)建這個(gè)Shader
- auto glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram);
- // 給精靈設(shè)置所用的Shader
- _sprite->setGLProgramState(glprogramstate);
- //創(chuàng)建海龜所用的貼圖。
- auto textrue1 = Director::getInstance()->getTextureCache()->addImage("tortoise.png");
- //將貼圖設(shè)置給Shader中的變量值u_texture1
- glprogramstate->setUniformTexture("u_texture1", textrue1);
- //創(chuàng)建波光貼圖。
- auto textrue2 = Director::getInstance()->getTextureCache()->addImage("caustics.png");
- //將貼圖設(shè)置給Shader中的變量值u_lightTexture
- glprogramstate->setUniformTexture("u_lightTexture", textrue2);
- //注意,對(duì)于波光貼圖,我們希望它在進(jìn)行UV動(dòng)畫時(shí)能產(chǎn)生四方連續(xù)效果,必須設(shè)置它的紋理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);
- //在這里,我們?cè)O(shè)置一個(gè)波光的顏色,這里設(shè)置為白色。
- Vec4 tLightColor(1.0,1.0,1.0,1.0);
- glprogramstate->setUniformVec4("v_LightColor",tLightColor);
- //下面這一段,是為了將我們自定義的Shader與我們的模型頂點(diǎn)組織方式進(jìn)行匹配。模型的頂點(diǎn)數(shù)據(jù)一般包括位置,法線,色彩,紋理,以及骨骼綁定信息。而Shader需要將內(nèi)部相應(yīng)的頂點(diǎn)屬性通道與模型相應(yīng)的頂點(diǎn)屬性數(shù)據(jù)進(jìn)行綁定才能正確顯示出頂點(diǎn)。
- 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滾動(dòng)初始值設(shè)為0
- _lightani.x = _lightani.y = 0;
之后我們重載一下FishLayer的draw函數(shù),加入U(xiǎn)V值的變化處理和設(shè)置。
- 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);
- }
這樣,我們就完成了魚身上的波光處理。