📜 ⬆️ ⬇️

Frame-by-frame animations and shaders in iOS

When developing 2D games, you often come across frame-by-frame animations, and the higher their quality, the more memory they consume. We encountered such a problem when rendering a character's hair animation - the artists draw half a hundred frames of remarkable graphics with a bunch of fine details and this very quickly takes up all the available memory. Collected, measured, it turned out 4 tekstruy on 16 megabytes each. Graphic detail is worth it, but a bit too much for one animation :)

It is necessary to pack it all ... They thought up and came to the aid of an old idea with a partial update of the picture - it is unlikely that the whole area will change during the animation. So you need to break the picture into nine parts, take eight from the base and replace the central one with the necessary modification. Like that:


')


We must now somehow implement it. Drawing the desired replacement on top disappeared immediately - the animation with transparencies, and translucent elements can not be layered. The second obvious implementation is with drawing using nine rectangles of roughness at the edges, especially if there is a scaling of the scene.

As a result, it turned out to be realized with the help of shaders - we draw one rectangle with two textures and with the help of a pixel shader we decide where to show. To implement such a shader, we need two samplers, two rectangular areas on the corresponding textures and four values ​​- minX, mixY, maxX, maxY, which will be used for switching textures.

I want to note that the coordinates of the rectangles on the textures are calculated under the full picture and will capture adjacent frames for the middle, this is not scary, the shader will cut the extra pixels.

Our four parameters can be transferred as one vector of four components according to the following scheme:



Next, following this scheme, we write a pixel shader to switch:

precision mediump float; uniform sampler2D u_texture; // base texture uniform sampler2D u_overlay; // overlay texture uniform vec4 u_overlayRect; // in texture coordinates (minX, minY, maxX, maxY) varying vec4 v_fragmentColor; varying vec2 v_texCoord; // base texture coordinates varying vec2 v_overlayTexCoord; // extrapolated overlay texture coordinates void main() { if (v_overlayTexCoord.x > u_overlayRect.x && v_overlayTexCoord.y > u_overlayRect.y && v_overlayTexCoord.x < u_overlayRect.z && v_overlayTexCoord.y < u_overlayRect.w) { gl_FragColor = v_fragmentColor * texture2D(u_overlay, v_overlayTexCoord); } else { gl_FragColor = v_fragmentColor * texture2D(u_texture, v_texCoord); } } 


After that, we reduce all the frames into one texture (instead of four!)



And enjoy the animation in response to the movement of a finger across the screen and without low memory warning!

Source: https://habr.com/ru/post/163775/


All Articles