Shader bits: World and screen space position

Debuting a new post series that will hopefully feature more posts in the future, tonight I just wanted to mention some quick tips that could be really useful for lots of use cases! This time, we’ll see how to get an object’s position in world and screen space, for both vertex-fragment and surface shaders. So let’s-a go!

Vertex-fragment shader

In order to get our object’s position in world and screen space for this type of shaders, we need to use some of the built-in values and functions provided by Unity.

World space position

For an object’s world space position, all we need is to add these lines to our shader’s v2f struct and vert function:

struct v2f
{
	float2 uv : TEXCOORD0;
	UNITY_FOG_COORDS(1)
	float4 vertex : SV_POSITION;
	float4 worldPos : TEXCOORD2;
};
v2f vert (appdata v)
{
	v2f o;
	o.vertex = UnityObjectToClipPos(v.vertex);
	o.uv = TRANSFORM_TEX(v.uv, _MainTex);
	o.worldPos = mul(unity_ObjectToWorld, v.vertex);
	UNITY_TRANSFER_FOG(o,o.vertex);
	return o;
}

After we declare our variable in the v2f struct, we just have to multiply the built-in matrix “unity_ObjectToWorld” with our object’s vertex position in order to map it to the object’s position in world space. After that, we can take it in either the vertex or fragment shader and use it as we please!

Screen space position

To get our object’s position in screen space, the process is similar, though a bit more straightforward. Again, these are the changes that are needed to be done in the v2f struct and the vertex shader:

struct v2f
{
	float2 uv : TEXCOORD0;
	UNITY_FOG_COORDS(1)
	float4 vertex : SV_POSITION;
	float4 scrPos : TEXCOORD2;
};
v2f vert (appdata v)
{
	v2f o;
	o.vertex = UnityObjectToClipPos(v.vertex);
	o.uv = TRANSFORM_TEX(v.uv, _MainTex);
	o.scrPos = ComputeScreenPos(o.vertex);
	UNITY_TRANSFER_FOG(o,o.vertex);
	return o;
}

In this case there’s a function that takes the object’s clip space position and gives us it’s screen space position.

Surface shader

As you probably already know, surface shaders are a bit more straightforward than vertex-fragment shaders, as they abstract some of the nitty gritty of the shader’s functionality. That makes them great to iterate on some effects quickly, but because of all the abstraction, they can be a bit hard to customize. Nevertheless, in this case, their straightfowardness is really helpful, as they make the task of getting the world and screen space coordinates of our object a matter of 2 words.

You also can check Unity’s manual on the different built-in stuff for surface shaders.

World space position

In the case of surface shaders, there is no need to add a vertex segment for our task. Unity provides a bunch of built-in parameters for the “Input” struct which can help us with what we want. Specifically, all we need to get the world space of our object is this small change:

struct Input {
	float2 uv_MainTex;
	float3 worldPos;
};

Seriously, that’s it. You can then take the worldPos in the surface segment and just go nuts.

Screen space position

Prepare to have your mind blown:

struct Input {
	float2 uv_MainTex;
	float3 screenPos;
};

Job’s done.

Conclusion

You can tell, there’s nothing too fancy going on here; and that’s ok! My purpose for this series is to have small useful bits in one place for somebody (myself included) to find. I have more bits like that, which I hope that I’ll post soon. So, see you in the next one!




Disclaimer

The code in the shader tutorials is under the CC0 license, so you can freely use it in your commercial or non-commercial projects without the need for any attribution/credits.

These posts will never go behind a paywall. But if you really really super enjoyed this post, consider buying me a coffee, or becoming my patron to get exciting benefits!

Become a Patron!

Or don't, I'm not the boss of you.