- Home /
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.
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 ;)
I don't think that's the correct way. I try to add a line i.uv = saturate(i.uv); But nothing's change. As I know TEXCOORD will be automatically saturated now, so probably not the right way. Thx for ur help.
Take care that saturate is only a clamp so it's indeed the same if you put it. What is exactly the effect/distortion you want to get ? And can you give the full shader (I can try to play with it, maybe I will get something ^^) ?
@AtGfx Just simply assign a material using Custom/DistortionEffect. Dun assign any _$$anonymous$$ainTex, it will simply grab from the camera, just change the Distortion map. And then recall this material in the camera attached with "DistortionEffect.cs". If you prefer to use the shader directly, simply write few lines of code to generate a material using that shader in the "DistortionEffect.cs".
I tried to put something in evidence but I cannot understand what happend exactly (I got the same results as you...).
$$anonymous$$aybe there are problem with the sampling because your texture is 512x512 and your res is 16:9 (I suppose), or there can be problem with the generation of the texture, etc.
Another possibility would be to calculate the distortion with some function and you apply it directly to your i.uv. If it works, it means that your texture is actually the problem.
I tried with a very simple texture which translate u and v to 0.1 and everything goes well. Troubles come when I try to put a linear gradient in the texture with Photoshop (this is why I think that the texture is the problem).
Yes, I agree, I think the problem comes from when we sampling the image captured by camera with texture, the image is not sampled pixel by pixel but slice by slice for better performance. Therefore, position translation is O$$anonymous$$, but re-scaling fails.
Answer by Eno-Khaon · Jun 20, 2017 at 08:06 PM
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:
(Note: Image is intentionally oversized for illustrative purposes)
When the pixels are interpolated and viewed up close, the texture would look something like this:
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
@$$anonymous$$o-$$anonymous$$haon I tried to use a 128x128 or 256x256 texture, the results are the same. And then I add the code you written, yes, the result is better when the scaleoffset becomes close to zero, but it just return to the origin. The problem of slice by slice gradient is still here. Thx a lot.
Ah, right. I knew I was forgetting something...
The other 90% of the problem is DXT texture compression on your distortion map.
Get rid of that and the 4x4 texture blocks will be gone. Despite how the compression is supposed to work functionally (take two color extremes and blend between them... should work perfectly well with a fixed gradient), it rarely succeeds at it.
Answer by MatrixTai · Jun 22, 2017 at 05:59 AM
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
No problem ;)
If it works you can try to set a green linear gradient from top to bottom (or set a different texture for x distortion and y distortion). Normally you should be able to distort your output in both directions !
Your answer
Follow this Question
Related Questions
Rendering different shader when camera get near object 1 Answer
2D and distortion shader 1 Answer
Camera horizontal distortion? 1 Answer
Vertex based screen deformation fx 0 Answers
Post Effect to certain objects? 1 Answer