Using cocos2d-x to implement UV Animation

Source: Internet
Author: User
Tags emscripten

Using cocos2d-x to implement UV Animation
UV animation with cocos2d-x -- Implement UVSprite

Uv animation is a texture animation that dynamically changes the texture coordinates when the program is running to achieve dynamic effects. uv animation can be used to achieve water flow, flame burning, and other effects.

It is an animated effect implemented by UVSprite.

 

 

 

1. Analysis

What we need is a sprite with uv animation. The simplest and most reasonable way is to let your UVSprite directly inherit from CCSprite, in addition, we also need two variables to control whether the U or V needs to be animated, and the other two variables to control the animation speed in the U and V directions. Therefore, the UVSprite class declaration is as follows:

 

Class UVSprite: public cocos2d: CCSprite {// specifies whether to animation bool _ AutoScrollU = true in the U direction; // specifies the animation speed (0 ~~ 1) float _ AutoScrollSpeedU = 0; // specifies whether the animation bool _ AutoScrollV = false is required in the V direction; // The animation speed in the V direction (0 ~~ 1) float _ AutoScrollSpeedV = 0; // Save the currently moved uv value float _ AutoScrollCountU = 0; float _ AutoScrollCountV = 0 ;};
In addition, we also need two interfaces to create the consistent UVSprite and CCSprite:

 

 

// Create static UVSprite * createWithSpriteFrameName (const char * pszSpriteFrameName) from the frame in plist; // create static UVSprite * create (const char * pszFileName) directly from the texture file );


 

In addition, we also need an update to update the uv offset value:

 

Void UVSprite: update (float dt) {CCSprite: update (dt); // update u if (_ AutoScrollU) {_ AutoScrollCountU + = dt * _ AutoScrollSpeedU ;} // update v if (_ AutoScrollV) {_ AutoScrollCountV + = dt * _ AutoScrollSpeedV ;} // if the range is exceeded, start from 0. if (_ AutoScrollCountU> 1 | _ AutoScrollCountU <-1) {_ AutoScrollCountU = 0 ;} if (_ AutoScrollCountV> 1 | _ AutoScrollCountV <-1) {_ AutoScrollCountV = 0 ;}}

We mentioned in the previous article that the uv value is (0 ~~ 1) The offset is within the range (-).

 

2. shader

A. We can write the shader with the updated uv. The vertex shader uses the ccPositionTextureColor_vert provided by cocos2d. The Code is as follows:

 

attribute vec4 a_position;attribute vec2 a_texCoord;attribute vec4 a_color;#ifdef GL_ESvarying lowp vec4 v_fragmentColor;varying mediump vec2 v_texCoord;#elsevarying vec4 v_fragmentColor;varying vec2 v_texCoord;#endifvoid main(){    gl_Position = CC_MVPMatrix * a_position;v_fragmentColor = a_color;v_texCoord = a_texCoord;}

B. The segment element shader. In the segment element shader, We need to update the uv coordinates and set a variable texOffset to indicate the uv offset. The Code is as follows:

 

 

#ifdef GL_ESprecision lowp float;#endifvarying vec4 v_fragmentColor;varying vec2 v_texCoord;uniform vec2 texOffset;                 uniform sampler2D CC_Texture0;void main(){vec2 texcoord = mod(texOffset+v_texCoord,1.0);   gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, texcoord);}

In the slice Shader, we add the default v_texCoord to the uploaded texOffset and modulo the result with 1 to ensure that the texture coordinates return to a reasonable position after going out of bounds.

 

 

3. Load the shader, add a member function for UVSprite, and reference the uniform of texOffset in a shader. The Code is as follows:

 

void UVSprite::loadShaderVertex(const char *vert, const char *frag){    CCGLProgram *shader = new CCGLProgram();    shader->initWithVertexShaderByteArray(vert, frag);        shader->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);    shader->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);    shader->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);        shader->link();        shader->updateUniforms();        _uniformOffset = glGetUniformLocation(shader->getProgram(), texOffset);        this->setShaderProgram(shader);        shader->release();}
In this function, first load the sahder and add cocos2dx to provide three default attributes: vertex coordinate, vertex color, and vertex uv coordinate. Then, obtain the uniform reference of texOffset in shahder.

 

4. Rendering: rewrite the draw function of CCSprite. In addition to implementing the draw rendering function of CCSprite, it also binds texOffset. The Code is as follows:

 

Void UVSprite: draw () {CC_PROFILER_START_CATEGORY (kCCProfilerCategorySprite, CCSprite-draw); CCAssert (! M_pobBatchNode, If CCSprite is being rendered by CCSpriteBatchNode, CCSprite # draw shocould NOT be called); getShaderProgram ()-> use (); getShaderProgram ()-> explain (); ccGLBlendFunc (m_sBlendFunc.src, m_sBlendFunc.dst); // binds texOffset getShaderProgram ()-> setUniformLocationWith2f (_ uniformOffset, _ AutoScrollCountU, _ AutoScrollCountV ); // bind the texture map watermark (m_pobTexture-> getName (); ccglablevertexattribs (attributes); # define kQuadSize sizeof (m_sQuad.bl) # ifdef EMSCRIPTEN long offset = 0; setGLBufferData (& m_sQuad, 4 * kQuadSize, 0); # else long offset = (long) & m_sQuad; # endif // EMSCRIPTEN // sets the rendering coordinate (x, y) int diff = offsetof (ccV3F_C4B_T2F, vertices); glVertexAttribPointer (kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void *) (offset + diff); // you can specify the texture coordinates (u, v) diff = offsetof (ccV3F_C4B_T2F, texCoords); glVertexAttribPointer (kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void *) (offset + diff )); // set the vertex color diff = offsetof (vertex, colors); glVertexAttribPointer (kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void *) (offset + diff )); // render the rectangle glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG (); # if vertex = 1 // draw bounding box CCPoint vertices [4] = {ccp (trim, ccp, ccp (m_sQuad.bl.vertices.x, m_sQuad.bl.vertices.y), ccp (m_sQuad.br.vertices.x, ccp), ccp (cursor, cursor),}; ccDrawPoly (vertices, 4, true ); # elif CC_SPRITE_DEBUG_DRAW = 2 // draw texture box CCSize s = this-> getTextureRect (). size; CCPoint offsetPix = this-> getOffsetPosition (); CCPoint vertices [4] = {ccp (offsetPix. x, offsetPix. y), ccp (offsetPix. x + s. width, offsetPix. y), ccp (offsetPix. x + s. width, offsetPix. y + s. height), ccp (offsetPix. x, offsetPix. y + s. height)}; ccDrawPoly (vertices, 4, true); # endif // specify CC_INCREMENT_GL_DRAWS (1); CC_PROFILER_STOP_CATEGORY (kCCProfilerCategorySprite, CCSprite-draw );}

The function of the Code is basically the same as that of the draw of CCSprite. The only difference is as follows:

 

 

// Bind texOffset getShaderProgram ()-> setUniformLocationWith2f (_ uniformOffset, _ AutoScrollCountU, _ AutoScrollCountV );

 

This line of code associates the texOffset In the shader with the uv of the real-time update in the update.

Source code: http://download.csdn.net/detail/liangneo/8348147

Instructions for use: Put the cocos2d-x samples/Cpp/directory to replace the original file can be

 

BugFix, because the spriteFrame of the cocos2d-x may only use a part of the texture, uv of the object created using UVSprite: createWithSpriteFrameName is only part of the 0-1 range, using the shader above can cause errors. Make the following corrections:

1. frag Shader

 

#ifdef GL_ES                                                            precision lowp float;                                                   #endif                                                                  varying vec4 v_fragmentColor;                                           varying vec2 v_texCoord;                                                uniform vec2 texOffset;                                                 uniform sampler2D CC_Texture0;                                          uniform vec2 uRange;                                                    uniform vec2 vRange;                                                    void main()                                                             {                                                                           vec2 texcoord = texOffset+v_texCoord;                                   texcoord.x = mod(texcoord.x - uRange.x,uRange.y-uRange.x) + uRange.x;       texcoord.y = mod(texcoord.y - vRange.x,vRange.y-vRange.x) + vRange.x;       gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, texcoord);}    

Two variables are added, uRange and vRange, respectively, to record the uv range and ensure that the texture in the Sprite is within this range.

 

2. shader Load

 

void UVSprite::loadShaderVertex(const char *vert, const char *frag){    CCGLProgram *shader = new CCGLProgram();    shader->initWithVertexShaderByteArray(vert, frag);        shader->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);    shader->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);    shader->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);        shader->link();        shader->updateUniforms();        _uniformOffset = glGetUniformLocation(shader->getProgram(), texOffset);    _uniformURange = glGetUniformLocation(shader->getProgram(), uRange);    _uniformVRange = glGetUniformLocation(shader->getProgram(), vRange);    this->setShaderProgram(shader);        shader->release();}

When loading, bind the uRange and vRange In the shader

 

3. Rendering

 

Void UVSprite: draw () {CC_PROFILER_START_CATEGORY (kCCProfilerCategorySprite, CCSprite-draw); CCAssert (! M_pobBatchNode, If CCSprite is being rendered by CCSpriteBatchNode, CCSprite # draw shocould NOT be called); getShaderProgram ()-> use (); getShaderProgram ()-> explain (); ccGLBlendFunc (parser, m_sBlendFunc.dst); // bug fix with sprite frame getShaderProgram ()-> trim (_ uniformURange, iterator, iterator); getShaderProgram ()-> trim (_ uniformVRange, response, response); float offsetU = (response-interval) * _ AutoScrollCountU; float offsetV = (response-interval) * _ AutoScrollCountV; getShaderProgram ()-> setUniformLocationWith2f (_ uniformOffset, offsetU, offsetV); // bind the texture map watermark (m_pobTexture-> getName (); ccglablevertexattribs (attributes); # define kQuadSize sizeof (m_sQuad.bl) # ifdef EMSCRIPTEN long offset = 0; setGLBufferData (& m_sQuad, 4 * kQuadSize, 0); # else long offset = (long) & m_sQuad; # endif // EMSCRIPTEN // set the rendering coordinate (x, y) int diff = offsetof (ccV3F_C4B_T2F, vertices); glVertexAttribPointer (kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void *) (offset + diff )); // set the texture coordinate (u, v) diff = offsetof (ccV3F_C4B_T2F, texCoords); glVertexAttribPointer (vertex, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void *) (offset + diff); // sets the vertex color diff = offsetof (vertex, colors); glVertexAttribPointer (kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void *) (offset + diff); // render the rectangle glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG (); # if CC_SPRITE_DEBUG_DRAW = 1 // draw bounding box CCPoint vertices [4] = {ccp (disabled, disabled), ccp (disabled, m_sQuad.bl.vertices.y), ccp (disabled, disabled ), ccp (halted, halted),}; ccDrawPoly (vertices, 4, true); # elif CC_SPRITE_DEBUG_DRAW = 2 // draw texture box CCSize s = this-> getTextureRect (). size; CCPoint offsetPix = this-> getOffsetPosition (); CCPoint vertices [4] = {ccp (offsetPix. x, offsetPix. y), ccp (offsetPix. x + s. width, offsetPix. y), ccp (offsetPix. x + s. width, offsetPix. y + s. height), ccp (offsetPix. x, offsetPix. y + s. height)}; ccDrawPoly (vertices, 4, true); # endif // specify CC_INCREMENT_GL_DRAWS (1); CC_PROFILER_STOP_CATEGORY (kCCProfilerCategorySprite, CCSprite-draw );}


 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.