Hey!
I am trying to make a distortion effect vertex-fragment shader! I am pretty new to shaders in general, probably don't know what I am doing, and I am having some trouble with it.
The effect is: from a distortion texture, I get a vector xy of the direction of the distortion through the rg part of the color, and get the intensity of the distortion from the blue. Then I use _Time to scroll where I sample from it.I am extending the Unity's default Sprite shader.
Sprite without the shader, with it, and then it combined with the animation.
What I did is the distortion effect in the middle. It's been pretty hard to do something pixel perfect. What I'm trying to do is taking the uv coordinate, and using the width and height of the MainTexture to get a integer value that's gonna be the same for every pixel of the texture. I do that so everyone from the same pixel can sample from the same position of the distortion texture.
int pixelX = round(uv.x * _MainTex_TexelSize.z) % _MainTex_TexelSize.z;
int pixelY = round(uv.y * _MainTex_TexelSize.w) % _MainTex_TexelSize.w;
The effect is more or less what I want (I still need to tweak the distortion texture).
The problem is that as I use the uv for the position of distortion, when I animate it (as I use Unity's sprite atlas, all the sprites are on the same texture, and it just jumps the uv around), the image becomes all shaky because it loses the information of where the distortion is at every frame.(It kinda looks OK in the image above, but it can potentially look terrible.)
The displacement code:
//Get the color of the displacement
float4 displacementValue = tex2D(_Distortion, uvDisplacement);
float timeGrowth = asin(_CosTime[3]) / (M_PI) + 0.5;
float displacementMultiplier = lerp(_DisplacementMinimum, 1, timeGrowth * displacementValue.b);
//Calculating the displacement pixel with the value
pixelX += displacementMultiplier * (displacementValue.r - 0.5) * _MaxDisplacement;
pixelY += displacementMultiplier * (displacementValue.g - 0.5) * _MaxDisplacement;
//Getting the UV
uv.x = (float)pixelX * _MainTex_TexelSize.x;
uv.y = (float)pixelY * _MainTex_TexelSize.y;
fixed4 c = tex2D(_MainTex, uv) * IN.color;
return c;
What I really want to do is not use UV at all to calculate the pixel position, but instead
use screen position. Does anybody know how to do this? I don't need it to be pixel perfect and be purist pixel art or anything, I just need it to look acceptable.
I am using the position (the regular SV_POSITION from the default sprite fragment shader) as well with _Time to offset the position so two sprites next to each other have different distortions, but this caused some aberrations:
This is not pixel perfect AT ALL
Maybe because of precision in the float values?
int uvWhereX = round(pixelX + _Time[1] * _Speed.x + (IN.vertex.x / _PixelsByUnit));
int uvWhereY = round(pixelY + _Time[1] * _Speed.y + (IN.vertex.y / _PixelsByUnit));
This is kind of a copy of
this, but nobody is helping me over there.
Can anyone point me in a good direction to solve this?