- Home /
Curved Screen Post Processing Effect
I am working on a 2D side scroller, and I want it to appear as though the screen is wrapped around a cylinder (meaning the closer things are to the sides of the screen, the thinner they get). Is there a post processing effect or shader that could accomplish this effect?
I mean, the lens distortion effect on the post processing stack does give nice results, but i dont think its reeeeaaly what youre looking for. I may be wrong but try it out.
Answer by BastianUrbach · Aug 19, 2020 at 02:57 PM
This as an image effect should work.
Shader "CylinderImageEffect" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Cull Off ZWrite Off ZTest Always
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert (float4 p : POSITION, float2 t : TEXCOORD0) {
v2f o;
o.vertex = UnityObjectToClipPos(p);
o.uv = t;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target {
i.uv.x = 1 - acos(i.uv.x * 2 - 1) / 3.14159265;
return tex2D(_MainTex, i.uv);
}
ENDCG
}
}
}
@BastianUrbach I copied this code and pasted it into an image shader file. If I want to apply this to a canvas Image, how should I proceed from here?
Well, image effects are always applied to an entire camera. I'm not sure if there is an easy way to apply it just to a canvas. If you apply it to a camera, it will affect the canvas if it is set to either Render Mode: Screen Space - Camera or Render Mode: World Space. Do it like this:
Write an image effect script using the shader (example below) by implementing the OnRenderImage method
Put the script on the camera
On the canvas, select "Screen Space - Camera" or "World Space" as the render mode
Assign the correct camera to the canvas
Simple image effect script (assign a material with the right shader in the inspector):
using UnityEngine;
[ExecuteAlways]
public class BasicImageEffect : MonoBehaviour {
public Material material;
void OnRenderImage(RenderTexture src, RenderTexture dst) {
Graphics.Blit(src, dst, material);
}
}
Note that you might run into issues with the render resolution. The effect wraps the image rendered at screen resolution around the visible half of a cylinder, which means that it's compressed at the left and right edge of the screen but stretched in the middle by a factor of pi/2. In theory you would have to render at pi/2 times the screen width. Not sure what the easiest way to do that is. I suppose you'd have to render into a render texture of that size and then draw that to another camera with the image effect.