Last active
January 9, 2024 00:28
-
-
Save aras-p/3d8218ef5d96d5984019 to your computer and use it in GitHub Desktop.
Unity flat skybox picture shader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Skybox shader that just draws flat texture in the background | |
Shader "Skybox/Background Texture" | |
{ | |
Properties | |
{ | |
_MainTex ("Texture", 2D) = "white" {} | |
} | |
SubShader | |
{ | |
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" } | |
Cull Off ZWrite Off | |
Pass | |
{ | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#include "UnityCG.cginc" | |
void vert (float4 pos : POSITION, out float4 outUV : TEXCOORD0, out float4 outPos : SV_POSITION) | |
{ | |
outPos = mul(UNITY_MATRIX_MVP, pos); | |
outUV = ComputeScreenPos(outPos); | |
} | |
sampler2D _MainTex; | |
fixed4 frag (float4 uv : TEXCOORD0) : SV_Target | |
{ | |
fixed4 col = tex2Dproj(_MainTex, uv); | |
return col; | |
} | |
ENDCG | |
} | |
} | |
} |
Thank you, here is variant that maintains aspect of an image:
//Helps to display a flat 2D image that always remains on screen,
//regardless of where the camera is looking.
//from https://gist.github.com/aras-p/3d8218ef5d96d5984019
// Maintains aspect of the image (outter-envelops the viewport)
Shader "Skybox/Background Texture Aspect"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
Cull Off ZWrite Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
void vert (float4 pos : POSITION, out float4 outUV : TEXCOORD0, out float4 outPos : SV_POSITION)
{
outPos = UnityObjectToClipPos(pos);
outUV = ComputeScreenPos(outPos);
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
fixed4 frag (float4 uv : TEXCOORD0) : SV_Target{
// Compute aspect ratio of the texture and the screen
float textureAspect = _MainTex_TexelSize.z / _MainTex_TexelSize.w; // Use z and w for texture width and height
float screenAspect = _ScreenParams.x / _ScreenParams.y;
uv /= uv.w;
// Calculate scale and offset for UVs to keep the image centered
float scale, offset;
if (screenAspect < textureAspect){
// Screen is narrower than texture - adjust UV.x
scale = screenAspect / textureAspect;
offset = (1.0f - scale) * 0.5f;
uv.x = uv.x * scale + offset;
} else {// Screen is less tall than texture - adjust UV.y
scale = textureAspect / screenAspect;
offset = (1.0f - scale) * 0.5f;
uv.y = uv.y * scale + offset;
}
fixed4 col = tex2D(_MainTex, uv);
return col;
}
ENDCG
}
}
}
Here is a more advanced variant.
Needed if you want to toggle between envelope/fitInsideViewport.
Or if you want to ensure there is "empty" space when squeezing the image into viewport.
Notice, to make this variant work you need to feed it the size of your image. For example:
void Update(){
if (_envelopeTheViewport){ _skyboxMaterial.EnableKeyword("ENVELOPE_THE_VIEWPORT"); }
else { _skyboxMaterial.DisableKeyword("ENVELOPE_THE_VIEWPORT"); }
if (_colorNothing) { _skyboxMaterial.EnableKeyword("NOTHING_IF_OUTSIDE_UV"); }
else { _skyboxMaterial.DisableKeyword("NOTHING_IF_OUTSIDE_UV"); }
Vector2 wh = new Vector2(1024,512);//<---you can dynamically change this.
_skyboxMaterial.SetVector("_Inner_WidthHeight", new Vector4(wh.x, wh.y, 0,0));
}
//Helps to display a flat 2D image that always remains on screen,
//regardless of where the camera is looking.
//from https://gist.github.com/aras-p/3d8218ef5d96d5984019
Shader "Skybox/Background Texture (Advanced)"
{
Properties
{
_MainTex ("Texture", 2D) = "black" {}//Background(skybox)
//size of whatever is to be squeezed into viewport.
//only used if ENVELOPE_THE_VIEWPORT is off
_Inner_WidthHeight("Inner WidthHeight", Vector) = (512,512,0,0)
//only used if keyword NOTHING_IF_OUTSIDE_UV is ON
//typically, you also want to have ENVELOPE_THE_VIEWPORT as OFF
_ColorNothing("Color of 'Nothing'", Color) = (0.1,0.1,0.1,1)
}
SubShader
{
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
Cull Off ZWrite Off
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ ENVELOPE_THE_VIEWPORT NOTHING_IF_OUTSIDE_UV
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 _Inner_WidthHeight;
float4 _ColorNothing;
void vert (float4 pos : POSITION, out float4 outUV : TEXCOORD0, out float4 outPos : SV_POSITION){
outPos = UnityObjectToClipPos(pos);
outUV = ComputeScreenPos(outPos);
}
#include "ShaderEffects.cginc"
fixed4 frag (float4 uv : TEXCOORD0) : SV_Target{
uv /= uv.w;
//'width/height' of the image squeezed inside (into) the viewport:
float inner_aspect = _Inner_WidthHeight.x / _Inner_WidthHeight.y;
float screenRealAspect = _ScreenParams.x / _ScreenParams.y;
float ratios = inner_aspect/screenRealAspect;
#ifdef NOTHING_IF_OUTSIDE_UV
float2 uv_fromCenter = uv-0.5f;
float2 uv_adjusted = uv_fromCenter;
if(ratios>1){
uv_adjusted.y*= ratios;
}else{
uv_adjusted.x/= ratios;
}
float2 isInside01 = 1-step(0.5f, abs(uv_adjusted)); //[0,1] --> [-0.5, 0.5] and then checking if absolute val is more than 0.5
float isFullyInside = isInside01.x*isInside01.y;
#endif
// Compute aspect ratio of the texture and the screen
float textureAspect = _MainTex_TexelSize.z / _MainTex_TexelSize.w; // Use z and w for texture width and height
// Calculate scale and offset for UVs to keep the image centered
float scale, offset;
#ifdef ENVELOPE_THE_VIEWPORT
bool is_adjust_horizontal = screenRealAspect < textureAspect;
#else//fully fit inside the viewport:
bool is_adjust_horizontal = screenRealAspect > textureAspect;
#endif
if (is_adjust_horizontal){
// Screen is narrower than texture - adjust UV.x
scale = screenRealAspect / textureAspect;
offset = (1.0f - scale) * 0.5f;
uv.x = uv.x * scale + offset;
} else {// Screen is less tall than texture - adjust UV.y
scale = textureAspect / screenRealAspect;
offset = (1.0f - scale) * 0.5f;
uv.y = uv.y * scale + offset;
}
fixed4 col = tex2D(_MainTex, uv);
#ifdef NOTHING_IF_OUTSIDE_UV
col = lerp(col, _ColorNothing, 1-isFullyInside);
#endif
return col;
}
ENDCG
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I definitely plan to check this out when I get home. If it works, is there any benefit of using this method over any of the other traditional method of creating 2D backgrounds, like quads or RawImage, in Unity?