Search Unity

Wobble shader stretched sides

Discussion in 'Shaders' started by VascoCorreia, Jun 30, 2021.

  1. VascoCorreia

    VascoCorreia

    Joined:
    Dec 5, 2020
    Posts:
    23
    Hello, I am very new to shaders and I was trying to create a wobble effect for underwater (explains the blue tint).

    The problem is that the sides of the rendered image get stretched from what I suppose are the UV coordinates going above 1 or under 0.
    Can someone explain what is going on and why and if there is a fix for this?
    Below there is a video demonstrating the problem. And also my shader code.

    Code (CSharp):
    1. Shader "Custom/Underwater"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.         _Amplitude("Amplitude", Range(0,0.2)) = 0
    7.         _Frequency("Frequency", Range(0,1)) = 0
    8.     }
    9.         SubShader
    10.     {
    11.         // No culling or depth
    12.         Cull Off ZWrite Off ZTest Always
    13.  
    14.         Pass
    15.         {
    16.             CGPROGRAM
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.  
    20.             #include "UnityCG.cginc"
    21.  
    22.             sampler2D _MainTex;
    23.             float _Amplitude, _Frequency;
    24.  
    25.  
    26.             struct inputVertex
    27.             {
    28.                 float4 vertex : POSITION;
    29.                 float2 texCoord : TEXCOORD0;
    30.             };
    31.  
    32.             struct outputVertex
    33.             {
    34.                 float4 pos : SV_POSITION;
    35.                 float2 texCoord : TEXCOORD0;
    36.             };
    37.  
    38.             outputVertex vert (inputVertex i)
    39.             {
    40.                 outputVertex o;
    41.                 o.pos = UnityObjectToClipPos(i.vertex);
    42.  
    43.                 //i.texCoord.y *= sin(i.texCoord.y * 0.5 + _Time.y )*0.1;
    44.  
    45.                
    46.  
    47.                 o.texCoord = i.texCoord;
    48.                 return o;
    49.             }
    50.  
    51.            
    52.  
    53.             fixed4 frag (outputVertex i) : SV_Target
    54.             {
    55.                 fixed4 col = tex2D(_MainTex, i.texCoord);
    56.                 i.texCoord.x += _Amplitude * sin(i.texCoord.y + _Time.y * _Frequency);
    57.                 // just invert the colors
    58.             //col.rgb = 1 - float3(0.3f, 0.5f, 0.73f);
    59.                 col.r += 0.2f;
    60.                 col.g += 0.3f;
    61.                 col.b += 0.9f;
    62.                 return col;
    63.             }
    64.             ENDCG
    65.         }
    66.     }
    67. }
    68.  
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Image effects like this can only show what was already rendered in view of the camera before applying your shader. The camera renders to a texture that this shader then reads from. If you try to sample outside of the 0.0 to 1.0 range, you don’t get to see outside of the area rendered, you just see whatever the texture’s wrap mode is set to.

    There are three main types of texture wrapping. Repeat, Mirror, and Clamp. Repeat is the default for most textures you’ll import into Unity; the texture just repeats over and over like you might see if applied to a floor or wall. Mirrored is uncommon, but is otherwise like Repeat in that you see the texture over and over, but each repetition mirrors the texture rather than “looping” like Repeat does. Clamp is the last option, and is what the render textures (like the one the camera renders to for image effects) default to. Whatever the last color on the edge of the texture is repeats forever outside of the 0.0 to 1.0 UV range. Technically there’s also mirror once, which is equivalent to clamp but using abs(uv), and isn’t supported on some newer APIs because it’s so rarely used and easy to replicate in the shader.

    So what you’re seeing is the clamped render texture outside of the 0.0 to 1.0 range. The only fix to that is … don’t sample the texture outside of 0.0 to 1.0. For an effect like underwater you can scale up the texture so that it’s displayed wider than it would be normally, specifically as wide as how much you’re warping the texture UVs.

    Try something like this:
    Code (CSharp):
    1. i.texCoord.x /= 1 + _Amplitude * 2.0;
    2. i.texCoord.x += _Amplitude;
    3. // then your sine wave wobble which is going to move it back and forth by +/- _Amplitude
    If the change to the aspect ratio bothers you, you can either scale and offset
    i.texCoord.xy
    instead of just
    .x
    , which will keep the aspect ratio the same and zoom in the entire image, or you can modify the camera’s pixel aspect ratio so it renders slightly too wide.
     
    RafaelKuhn and VascoCorreia like this.
  3. VascoCorreia

    VascoCorreia

    Joined:
    Dec 5, 2020
    Posts:
    23
    What an amazing response! Everything that I could have asked for! When I arrive home I will explore your suggestion and give you feedback!
    Thank you so much!

    EDIT: Worked like a charm! Trying to visualize what exactly the calculations you provided are doing, since this is new to me, but it's perfect!
     
    Last edited: Jul 2, 2021
    RafaelKuhn likes this.