📜 ⬆️ ⬇️

The effect of shirts on mobile shaders

Prologue


Good day! After publishing an article about rendering a quadratic tree (Quad-tree) , I was asked to write an article showing the work of the shader, which translates the image into a “sweater”.



So, let's consider this technique.

Implementation


To implement the algorithm, you will need a texture with sweater stitches. It looks like this.
')


The texture consists of 30 stitches of the same width of 30 pixels. As a result, we must display this texture on the screen, make me stitch color under the desired color on the screen, and shuffle the stitches themselves on the screen so that the image does not seem artificial.

Initially, you need to prepare the parameters for the shader, the language described in the article will be C # and GLSL, respectively.

override public void OnScaleUpdated(float scale) { Vector2 screenSize = ScreenTool.GetViewportSize (); Texture2D stitchTexture = textureLoader.texture; float resolutionH = Mathf.Clamp((Mathf.RoundToInt(screenSize.x/(float)itemWidth * scale) * 2), 1, 2048); float resolutionV = Mathf.Clamp((Mathf.RoundToInt(screenSize.y/(float)stitchTexture.height * scale) * 2), 1, 2048); resolution = new Vector4 (resolutionH, resolutionV, 0f, 0f); float amountH = (float)(resolutionH * itemWidth) / (2.0f * (float)stitchTexture.width); float amountV = (float)resolutionV / 2.0f; Vector4 amount = new Vector4 (amountH, amountV, 0f, 0f); material.SetTexture ("_ItemTex", stitchTexture); material.SetVector ("_Resolution", resolution); material.SetVector ("_ItemsAmount", amount); } 


The function is called when the scaling factor is updated, it calculates the number of textures with stitches.


The variable amountH is divided by 2, this is done in order to divide one stitch by sex and change the color of the half stitch.

Let us turn to the implementation of the shader.
A shorter image from the camera will be transferred to the shader in order to split the image into blocks, which will be converted into stitches next.



Initially, we need to determine in which block we are now. The blocks are formed by the fact that our thumbnail image is then stretched to full size, and each pixel forms a block of pixels of the same color.

 float2 colorBlock = floor(input.tex * _Resolution); 


The next stage for me turned out to be the most difficult, it is necessary for a certain block, to select a relatively random stitch from the texture.
 float2 stichUV = float2(frac(_ItemsAmount.x * (input.tex.x + pow(colorBlock.y, 2.0) / _Resolution.x*2)), frac(_ItemsAmount.y * input.tex.y)); 


Next, take the color of the block, the color of the stitch and the color of the previous block. The color of the previous block must be taken, as the stitches go beyond the limits of their blocks.
 fixed4 color = tex2D(_MainTex, input.tex); fixed4 newColor = tex2D(_ItemTex, stichUV); fixed4 prevColor = tex2D(_MainTex, float2(input.tex.x, input.tex.y + 1.0/_Resolution.y)); 




In the image, the current block is shown in red, and the next one is green, but a part of the stitch painted in green should have a red color, for this the color search of the previous block is used.

 if (stichUV.y > 0.5) { newColor *= color; float2 topStichUV = frac(float2(_ItemsAmount.x * (input.tex.x + pow(colorBlock.y + 1, 2) / _Resolution.x*2), _ItemsAmount.y*input.tex.y - 0.5)); fixed4 otherStich = tex2D(_ItemTex, topStichUV) * prevColor; if (otherStich.a > 0.05) { newColor = lerp(newColor, otherStich, 1 - newColor.a); } } 


Initially, we mix the color of the stitch with the color of the block, after which we find the stitch, which should be drawn over the red part and then we mix the two parts of the stitch.

The bottom part draws similarly (green):
 else { stichUV = float2(frac(_ItemsAmount.x * (input.tex.x + pow(colorBlock.y + 1, 2) / _Resolution.x*2)), frac(_ItemsAmount.y*input.tex.y)); newColor = tex2D(_ItemTex, stichUV); newColor *= prevColor; float2 bottomStichUV = float2(frac(_ItemsAmount.x * (input.tex.x + pow(colorBlock.y, 2) / _Resolution.x*2)), frac(_ItemsAmount.y*input.tex.y + 0.5)); fixed4 otherStich = tex2D(_ItemTex, bottomStichUV) * color; if (otherStich.a > 0.7) { newColor = lerp(otherStich, newColor, 1 - prevColor.a); } } 


Epilogue


As a result, we get a rather smart shader, which, if desired, can be made to work well on old Android (on iOS it will already work fine). You can use different textures to change the effect, say cross-stitch.

Thanks for attention!

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


All Articles