Can I use Gif animations on a cube or plane? Trying to do ad billboards

Hi everyone.
So basically I am trying to make one of those electronic advertisement billboards we see on the streets.
I think a Gif image as a map would solve the problem but I tried and it is not working.

What would be your advice for this?

You can’t directly use a GIF as a texture, but you can convert it to a sprite sheet by simply pasting the frames of the GIF beside each other and use a sprite sheet shader to animate it.

I used some code to make a shader that animates a GIF of cute bats on my avatar that fly around me as a particle system.



// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

/* Mattatz's TextureAnimation shader from https://gist.github.com/mattatz/f5b8e1b34035395013fe#file-textureanimation-shader */
Shader "Mattatz/TextureAnimation"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_Color("Color", Color) = (1, 1, 1, 1)

		_Cols("Cols Count", Int) = 5
		_Rows("Rows Count", Int) = 3
		_Frame("Per Frame Length", Float) = 0.5
	}

		SubShader
		{
			Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha
			Cull front
			LOD 100

			Pass
			{
				CGPROGRAM
				#pragma vertex vert alpha
				#pragma fragment frag alpha

				#include "UnityCG.cginc"

				struct appdata
				{
					float4 vertex : POSITION;
					float2 uv : TEXCOORD0;
				};

				struct v2f
				{
					float2 uv : TEXCOORD0;
					float4 vertex : SV_POSITION;
				};

				sampler2D _MainTex;
				float4 _MainTex_ST;

				fixed4 _Color;

				uint _Cols;
				uint _Rows;

				float _Frame;

				fixed4 shot(sampler2D tex, float2 uv, float dx, float dy, int frame) {
					return tex2D(tex, float2(
						(uv.x * dx) + fmod(frame, _Cols) * dx,
						1.0 - ((uv.y * dy) + (frame / _Cols) * dy)
					));
				}

				v2f vert(appdata v) {
					v2f o;
					o.vertex = UnityObjectToClipPos(v.vertex);
					o.uv = TRANSFORM_TEX(v.uv, _MainTex);
					return o;
				}

				fixed4 frag(v2f i) : SV_Target {
					int frames = _Rows * _Cols;
					float frame = fmod(_Time.y / _Frame, frames);
					int current = floor(frame);
					float dx = 1.0 / _Cols;
					float dy = 1.0 / _Rows;

					// not lerping to next frame
					// return shot(_MainTex, i.uv, dx, dy, current) * _Color;

					int next = floor(fmod(frame + 1, frames));
					return lerp(shot(_MainTex, i.uv, dx, dy, current), shot(_MainTex, i.uv, dx, dy, next), frame - current) * _Color;
				}

				ENDCG
			}
		}
}
`
1 Like

I wrote a shader to implement an animated gif as a sprite sheet.

Hope this helps.

You set up the frames as the image as one long image all beside each other, spaced evenly.

Works for the cute bats particle animation on my avatar.

`// Upgrade NOTE: replaced ‘mul(UNITY_MATRIX_MVP,)’ with 'UnityObjectToClipPos()’

/* Mattatz’s TextureAnimation shader from Texture animation shader for Unity. · GitHub */
Shader “Mattatz/TextureAnimation”
{
Properties
{
_MainTex(“Texture”, 2D) = “white” {}
_Color(“Color”, Color) = (1, 1, 1, 1)

	_Cols("Cols Count", Int) = 5
	_Rows("Rows Count", Int) = 3
	_Frame("Per Frame Length", Float) = 0.5
}

	SubShader
	{
		Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
		ZWrite Off
		Blend SrcAlpha OneMinusSrcAlpha
		Cull front
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert alpha
			#pragma fragment frag alpha

			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;

			fixed4 _Color;

			uint _Cols;
			uint _Rows;

			float _Frame;

			fixed4 shot(sampler2D tex, float2 uv, float dx, float dy, int frame) {
				return tex2D(tex, float2(
					(uv.x * dx) + fmod(frame, _Cols) * dx,
					1.0 - ((uv.y * dy) + (frame / _Cols) * dy)
				));
			}

			v2f vert(appdata v) {
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				return o;
			}

			fixed4 frag(v2f i) : SV_Target {
				int frames = _Rows * _Cols;
				float frame = fmod(_Time.y / _Frame, frames);
				int current = floor(frame);
				float dx = 1.0 / _Cols;
				float dy = 1.0 / _Rows;

				// not lerping to next frame
				// return shot(_MainTex, i.uv, dx, dy, current) * _Color;

				int next = floor(fmod(frame + 1, frames));
				return lerp(shot(_MainTex, i.uv, dx, dy, current), shot(_MainTex, i.uv, dx, dy, next), frame - current) * _Color;
			}

			ENDCG
		}
	}

}
`

1 Like

Thank you very much but isn´t a vrchat rule that we cannot add code to their SDK? Maybe I misunderstood something-

No you are 100% allowed to use your own shaders lol.

Shaders are merely little programs that run on your video card that tell it how to render things.

This site seems to kind-of suck for putting code into, at least on my phone. 1 sec…

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

/* Mattatz's TextureAnimation shader from https://gist.github.com/mattatz/f5b8e1b34035395013fe#file-textureanimation-shader */
Shader "Mattatz/TextureAnimation"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_Color("Color", Color) = (1, 1, 1, 1)

		_Cols("Cols Count", Int) = 5
		_Rows("Rows Count", Int) = 3
		_Frame("Per Frame Length", Float) = 0.5
	}

		SubShader
		{
			Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha
			Cull front
			LOD 100

			Pass
			{
				CGPROGRAM
				#pragma vertex vert alpha
				#pragma fragment frag alpha

				#include "UnityCG.cginc"

				struct appdata
				{
					float4 vertex : POSITION;
					float2 uv : TEXCOORD0;
				};

				struct v2f
				{
					float2 uv : TEXCOORD0;
					float4 vertex : SV_POSITION;
				};

				sampler2D _MainTex;
				float4 _MainTex_ST;

				fixed4 _Color;

				uint _Cols;
				uint _Rows;

				float _Frame;

				fixed4 shot(sampler2D tex, float2 uv, float dx, float dy, int frame) {
					return tex2D(tex, float2(
						(uv.x * dx) + fmod(frame, _Cols) * dx,
						1.0 - ((uv.y * dy) + (frame / _Cols) * dy)
					));
				}

				v2f vert(appdata v) {
					v2f o;
					o.vertex = UnityObjectToClipPos(v.vertex);
					o.uv = TRANSFORM_TEX(v.uv, _MainTex);
					return o;
				}

				fixed4 frag(v2f i) : SV_Target {
					int frames = _Rows * _Cols;
					float frame = fmod(_Time.y / _Frame, frames);
					int current = floor(frame);
					float dx = 1.0 / _Cols;
					float dy = 1.0 / _Rows;

					// not lerping to next frame
					// return shot(_MainTex, i.uv, dx, dy, current) * _Color;

					int next = floor(fmod(frame + 1, frames));
					return lerp(shot(_MainTex, i.uv, dx, dy, current), shot(_MainTex, i.uv, dx, dy, next), frame - current) * _Color;
				}

				ENDCG
			}
		}
}

1 Like

Instead of using a spritesheet, you can also look into using texture arrays. They tend to be more efficient than a giant spritesheet.

Poiyomi uses texture arrays for the flipbook feature. They’re relatively easy to use in a shader. There’s no native way to build them, weirdly. I use this editor script to build mine.

Thank you very much!
It’s been a painful learning curve full of stupid questions but my world is improving thanks to you guys in this helpful community.
So my next question is probably worst… what if I animate cubes or flat planes going backward and forward with different photos on them? Is it too expensive for the GPU and CPU?
Will try your shader anyway. Thanks again!

This sounds very interesting and I´’ve been squeezing my brain to understand it but unfortunately I am quite tide of time, are there any already done script for this?
Also, what do you think will take more GPU resources, the texture arrays, the sprite sheet or just manually animating planes or cubes?

Thank you so much!