How to pass world positions to a shader

Is this even technically possible?

I wanted to pass xyz as a colour to my image to use as world positions but that is obviously clamped between 0 and 1, and i also don’t get negative numbers in the image so i can’t use them as world positions.

Is it even possible?

What exactly is the use case you’re asking about?

If you’re rendering a mesh in the scene, then the world position is always calculated in the vertex shader as part of the UnityObjectToClipPos() function. There’s no need to output to a texture since the the world position is already known in this case, so there’s no issue with the value being clamped.

float3 worldPos = mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0)).xyz;

It’s just a matter of passing that value from the vertex to the fragment. If you’re using a surface shader it’s just a matter of adding float3 worldPos; to the Input struct.

If you’re doing this as a post process image effect, then the usual solution is to reconstruct the world position from the camera depth texture. See this for an example:
https://github.com/keijiro/DepthInverseProjection

A similar technique is how several of Unity’s post process effects work.

If you’re really stuck on outputting the world position to a texture, then you’ll want to use a float texture format as your render texture instead of the usual default ARGB32. Specifically ARGBFloat. That has a full 32bit float per component, so isn’t limited to a “0 to 1” range, and can hold negative values.

2 Likes