Pickable Objects Shader

Pickable Objects Shader

Here's how to create a simple effect to communicate to the players which objects are pickable, interactive etc.

A lot of games implemented this effect in clever ways; today I'm showing a simple version that relies on the object's vertices coordinates (like a gradient) and passing of time. The shader itself is just a handful of nodes in Shader Graph (or about 20 lines of HLSL), so it's easy to adapt to your project.

0:00
/0:05

How it works

The effect reads the vertex's X position (passed from the vertex shader to the fragment shader) and combines it with _Time.y inside a cos() call. That gives you an animated gradient that travels across the object. The result is clamped to [0, 1] and used as the lerp factor between the base object color and the highlight color. Because the effect uses object-space vertex coordinates rather than world-space, it moves with the object naturally without any extra setup. The whole shader is about 20 lines of HLSL including the property block.

HLSL

Here's an example, written in HLSL. Even if this tutorial example is targeted for Unity the mechanics and logic apply to all other engines as well.

  1. Pass the vertex X position from the vertex function to Input.vertexPos.
  2. In the surface function, compute cos(_Time.y * 4 - vertexPos) and clamp it to [0,1].
  3. Use that value as the lerp factor between _ObjectColor and _HighlightColor on both Albedo and Emission.
//@febucci, https://www.febucci.com/tutorials/
//Support my work here: https://www.patreon.com/febucci

Shader "Custom/PickableObjects" {
	Properties{
		_HighlightColor("Highlight Color", Color) = (1,1,1,1)
		_ObjectColor("Object Color", Color) = (1,1,1,1) // you can use a Texture instead of a Tint
	}

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

		CGPROGRAM
		#pragma surface surf Standard vertex:vert

		#include "UnityShaderVariables.cginc" //to use _Time

		float4 _ObjectColor;
		float4 _HighlightColor;

		struct Input {
			float vertexPos;
		};

		void vert(inout appdata_full v, out Input o) {

			UNITY_INITIALIZE_OUTPUT(Input, o);
			o.vertexPos = v.vertex.x; // passes the vertex data to pixel shader, you can change it to a different axis or scale it (divide or multiply the value)
		}

		void surf(Input IN, inout SurfaceOutputStandard o) {

			float highlight_value = clamp( //clamps the value between 0 and 1 (since "cos" can go from -1 to 1)
							cos(
								_Time.y * 4 - //4 is the effect speed
								IN.vertexPos),
							0,
							1);

			o.Albedo = lerp(_ObjectColor, _HighlightColor, highlight_value);
			o.Emission = lerp((0,0,0), _HighlightColor.xyz, highlight_value);
		}
		ENDCG
	}

FallBack "Diffuse"
}

Shader Graph

Here's the same effect created in Unity Shader Graph.
To use it you must enable one Scriptable Render Pipeline in the Package manager, for example the Lightweight RP or the High Definition one.

💡
P.S. (now Unity has included both package under the name of "Universal Render Pipeline")

Amplify Shader Editor

Here's the same effect created using the plugin Amplify Shader Editor.

Frequently asked questions

Can I change which axis the highlight travels along?

Yes. In the vertex function, replace v.vertex.x with v.vertex.y or v.vertex.z to change the direction. You can also multiply or divide the value to scale the speed of the travel.

How do I control the animation speed?

Change the multiplier on _Time.y in the fragment shader. The example uses 4; higher values make the highlight travel faster.

Does this work in the Universal Render Pipeline?

The HLSL version uses the built-in surface shader syntax, which only works in the Built-in Render Pipeline. For URP, use the Shader Graph version shown above or convert the logic to an HLSL shader with URP's Lit shader as a base.

Can I use a texture for the object color instead of a tint?

Yes, just replace the _ObjectColor property with a 2D sampler and sample it in the surface function the usual way.

Comments

Want game-ready tools or need specific solutions?

Work with us