Camera Distortion effect needed improve (SOLVED)

I write my own camera distortion effect like following:

			sampler2D _MainTex, _DistortionMap;

			struct VertexData {
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct Interpolators {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			Interpolators VertexProgram (VertexData v) {
				Interpolators i;
				i.pos = UnityObjectToClipPos(v.vertex);
				i.uv = v.uv;
				return i;
			}

			float4 FragmentProgram (Interpolators i) : SV_Target {
				float2 distort = tex2D(_DistortionMap, i.uv).rg;
				distort = distort * 2 - 1;
				i.uv += distort;
				float3 sourceColor = tex2D(_MainTex, i.uv).rgb;
				return float4(sourceColor, 1);
			}

			ENDCG

While this is attached to the camera by

	void OnRenderImage(RenderTexture src, RenderTexture dest)
	{
		Graphics.Blit(src, dest, material);
	}

As you can notice I use a texture map which contain the red and green channel to change the x,y position. The map I used is this, which will squeeze everything a little bit to the middle.

However, the result comes out to be

It looks like the image is distorted slice by slice but not pixel by pixel, how to improve it?
Thank you.

The problem may actually be simpler than it seems.

After taking a quick look at it, your distortion texture appears to be TOO BIG!

What you’re looking for is interpolation between pixels to smooth out the effect across the screen. However, with a 512x512 texture, most adjacent pixels are the same color. As an example, say you have a simple, 4 pixel, black-white-white-black texture:

96313-colorsunblended.png
(Note: Image is intentionally oversized for illustrative purposes)

When the pixels are interpolated and viewed up close, the texture would look something like this:

96314-colorsblended.png
Note that the two inside white pixels result in a large, white field which doesn’t blend with the neighboring black pixels. That’s because they’re not supposed to blend with anything but their immediate neighbors.

This is the problem you’re experiencing with your distortion texture. Most pixels are actually the same color as their neighbors, so blending them results in no change of color.

So, there are two main ways you can look at solving this:

  1. Change your distortion texture to be no more than 256 pixels wide (and/or tall), using a different value for every pixel to allow interpolation at any point. For reference, a 2x2 texture could functionally provide a linear curve across the entire screen, by letting the texture rendering (linearly) interpolate all the way from one extreme to the other

  2. Programmatically distort the screen instead, based on the uv coordinates of the base render. This cuts out the potential to distort the image in specific, directed ways, but will allow you to create single-purpose variations with (near-) infinite precision.

Regardless of which you choose, you may also want to add a scale to your shader, to increase or decrease the level of distortion.

Properties
{
	// ...
	_ScaleOffset("Scale and Offset", Vector) = (0.25, 0, 0, 0) // scaleX, scaleY, offsetX, offsetY
}

float4 _ScaleOffset;
// ...

float4 FragmentProgram (Interpolators i) : SV_Target
{
	// ...
	// Texture-based example
	float2 distort = tex2D(_DistortionMap, i.uv).rg;
	distort = distort * 2 - 1;
	distort = distort * _ScaleOffset.xy + _ScaleOffset.zw;
	// ...
}

Edit: Added note about a 2x2 texture’s potential use

Hi !

I think that there is a problem with your distortion and you do not make what you think.

In your FragmentProgram the value of distort lies in the range [-1,1] (because it comes from distort = distort ([0,1]) * 2 - 1 then you make i.uv += distort so i.uv lies in range [-1, 2] wich is not acceptable for a uv texture that should be in the range [0,1]. You can try to rerange it such that your uv fit in a correct space (if I’m correct, add 1 to your uv then divide by 3).

According to your map, your mistake can lead to sample the texture over the range [0,1] and as your map is kind of smooth, it can explain why you see some stripes on your image.

Hope it helps :wink:

Oh, I get it. This is indeed not a big problem… I change the texture to this, then everything correct. My original one is mistakenly transferring both x-axis and y-axis.


it is just the error of texture. Sorry for bothering you guys time. @Eno-Khano and @AtGfx