HLSL Post Process Shader Fixing UV/Texcoord

Hey, I am trying to make a simple Wobble shader using HDRP and custom post processing in HLSL. However, I am getting black areas on the edges of the screen where texcoord’s x value is not within the range of 0-1 (my assumption).

Here’s the fragment:

float2 wobble(float2 uv, float amplitude, float frequence, float speed)
{
	float offset = amplitude * sin(uv.y * frequence + _Time * speed);
	return float2(uv.x + offset, uv.y);
}

float4 CustomPostProcess(Varyings input) : SV_Target
{
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

	float2 uv = input.texcoord;
	float amplitude = 0.0030;
	float frequence = 25.00;
	float speed = 10.0;
	uv = wobble(uv,_Amplitude, _Frequence, _Speed);
	float3 outColor = LOAD_TEXTURE2D_X(_InputTexture, uv * _ScreenSize.xy).xyz;
	return float4(outColor, 1);
}

And here is the result:

Of course the image is getting bent by the Wobble effect, but I need to fit the uv in such a way that these areas will not be black. If I clip the uv’s x like this:

if (uv.x < 0.0f)
	uv.x = 0.0;
	// OR
uv.x = frac(uv.x);

Then I get what I need for the left side of the screen, but I couldn’t find a way to handle the other side.

This issue also happens with some other tests I run with different effects, whenever I try to mess with the uv (texcoord). So I kinda need some explanation of how that works properly, and how to recalculate the uv to make the image fit into the screen space properly.

Uhm, of course clamping the UV coordinates would prevent the black areas from being black, but the result would just be the outermost texels streched across those regions. You can’t really fill those areas with meaningful data “properly” since there is no data in those regions.

You have several possibilities to “fix” those areas. Though not all might fit your requirements.

Of course the simplest solution is to just clamp the uv values between 0-1 after your wobble function:

uv = clamp(uv, 0, 1);

As mentioned above this would just stretch the outermost pixels sideways to fill the black areas. So the areas are not black anymore but doesn’t really look great. Another option is to just repeat the texture. This is done with the line you already mentioned

uv = frac(uv);

That essentially means that the area that is shifted out of the screen on one side comes back in on the other side. This should work for both sides. The last “simple” solution is to artificially “zoom in” a bit which would cut off parts of the image. That way you have enough room to do the wobble without actually leaving the image area. This might not be a valid solution depending on your needs. Especially in stereoscopic view this probably won’t work so I don’t go into details on this one. Finally if you’re just interested in a wobble of the image you could dynamically reduce the distortion and essentially fade it out the closer you get to the edges. This would essentially keep the edges in place and the wobble mainly takes place in the center region of the image. To pull that off you just need a scaling factor for your offset / amplitude that goes to 0 as closer you get to an edge. This can be done by using two clamps and appropriate scaling:

offset *= clamp(uv.x*10, 0, 1) * clamp((1-uv.x)*10, 0, 1);

Of course this would go into your wobble function between your two lines. The “10” inside the two clamps would linearly fade out the offset in the last 10% of the screen. So the wobble would take place in the middle 80% of the screen. A larger value would make the fading area smaller. However the fading area should be at least as large as your amplitude value.