Camera-facing UVs

I made a shader a while ago to do what I think you are asking in Unity:

So it moves in the object’s space and always faces the camera. It pretty much the same think Mike did, take Screen Space UVs and offset by the object position in screen space. I also added scaling of the texture based on distance from the camera so that it was stable for things that move in the z-direction.

Here’s the basic shader:

Shader "Custom/ScreenSpace" {
 Properties {
  _MainTex ("Color Texture", 2D) = "white" {}     
  _SSUVScale("UV Scale", Range(0,10)) = 1
}

CGINCLUDE
	sampler2D _MainTex;
	float _SSUVScale;

	struct appdata {
		float4 vertex : POSITION;
	};

	struct v2f {
		float4 pos : POSITION;
	};

	float2 GetScreenUV(float2 clipPos, float UVscaleFactor)
	{
		float4 SSobjectPosition = mul (UNITY_MATRIX_MVP, float4(0,0,0,1.0)) ;
		float2 screenUV = float2(clipPos.x/_ScreenParams.x,clipPos.y/_ScreenParams.y);
		float screenRatio = _ScreenParams.y/_ScreenParams.x;

		screenUV.y -=0.5;
		screenUV.x -=0.5;

		screenUV.x -= SSobjectPosition.x/(2*SSobjectPosition.w);
		screenUV.y += SSobjectPosition.y/(2*SSobjectPosition.w); //switch sign depending on camera
		screenUV.y *= screenRatio;

		screenUV *= 1/UVscaleFactor;
		screenUV *= SSobjectPosition.z;

		return screenUV;
	};


ENDCG

SubShader {
  	Tags { "RenderType" = "Opaque" }

  	Pass 
	{
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "UnityCG.cginc"

		v2f vert(appdata v) {				
			v2f o;
			o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

			return o;
		}		

		half4 frag(v2f i) :COLOR 
		{ 				
			float2 screenUV = GetScreenUV(i.pos.xy, _SSUVScale);
			half4 screenTexture = tex2D (_MainTex, screenUV);

			return screenTexture; 
		} 
		ENDCG				 
	}

} 
Fallback "Diffuse"

}

There’s some weird stuff in unity where the viewport camera has different camera constants than the in game cameras, and some of the camera properties are also not available if you’re doing surface shaders, so it can be tricky to tune this just right for all cases

7 Likes