Your image can be interpreted a couple different ways so I will make a few assumptions up front:
- The "geometry" you are emulating is meant to look as if it has already been "projected" (if it was plane geometry and ran through MVP matrices it would produce similar output).
- The planes are flat and not angled.
- The planes are both 0.5 units away from the camera in the vertical z axis.
- Assume the viewport is perpendicular to both of the planes
- No scale, FOV, aspect ratio for the viewport is given. We assume some further down
These assumptions describe a simple version of your scene. We will look at breaking some of these assumptions throughout the answer but keep this in mind for now.
To demonstrate the different depth values, I made a similar image to your question.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
//To recreate your picture
vec2 screenUV = fragCoord.xy / iResolution.xy;
vec2 uv = screenUV.xy * 2.0 - 1.0;
vec2 texUV = vec2(uv.x / abs(uv.y), (1.0 / abs(uv.y)));
vec4 color = texture2D(iChannel0, texUV);
color = vec4(color.r, 0.0, color.ba);
color = mix(vec4(0.0,0.0,0.0,1.0), color, abs(uv.y));
fragColor = color;
/*To render depth values
fragColor = vec4(0.0, depth, 0.0, 1.0); //Just z
fragColor = vec4(fragColor.r, depth, fragColor.ba); //With original textures
will be shown in green!*/
}
You have texUV.y
calculated which is over the range [1, +Inf),(+Inf, 1]
. This is because 1.0/abs([-1.0,1.0]) == [1, +Inf),(+Inf, 1]
. This will be the basis for our depth value as it's what is used to create the planes that have the texture of unit length applied to them. To be a depth value we need to convert it to a [0,1] linear range. To do this we need to
- Get rid of infinities by clip the original range at a near and far plane.
- Apply a scale factor such that the planes are properly "projected" (one unit of texture is one unit of world space)
The near plane and far plane are based on your particular use case. I have chosen 0.001
and 100.0
for this example.
const float nearPlane = 0.001;//Depth of 0.0
const float farPlane = 100.0; //Depth of 1.0
The scale factor determines for every unit length of the the plane (which is delineated by one repetition of your texture), how many world space units should there exists. It would seem at first glance we could just choose a simple multiplier but remember we have a scene that's already been "projected". So, actual scale factor needs to reflect the "camera" that's viewing the scene.
If the planes were completely perpendicular to the camera before they were projected, the scale factor is based entirely on the slope of the bottom plane of the camera. We choose a fake FOV and aspect ratio for demonstration but you can use whatever values suit you for these.
const float PI = 3.141592;
const float camFOV = 80.0 * PI/180.0;
const float aspectRatio = 4.0/3.0;
const float camYSlope = tan(atan(aspectRatio * tan(camFOV/2.0))/2.0);
If the planes weren't completely perpendicular, a large value (for planes angled towards the camera) or a smaller value (for planes angled away from the camera couple be substituted for camYSlope. A different vertical z value adjustment would need to be used in the depth calculation as well (instead of the 0.5 assumtion)
The depth can then be calculated like so:
float depth = (clamp(
(texUV.y-1.0) //Shift by 1 backward ([0, +Inf) (+Inf, 0]
*camYSlope //Scale by some factor of world units / uv units, using fake camera values gives real output
+0.5 //Add 0.5 to assume that an extra vertical distance for top and bottom plane fragment depth is included
, nearPlane, farPlane) //Clamp to the near and far plane [nearPlane, farPlane]
- nearPlane) //Remove the shift [0.0, farPlane - nearPlane]
/ (farPlane-nearPlane) //Remove the scale [0.0, 1.0]
;
Putting it all together we get
const float nearPlane = 0.001;//Depth of 0.0
const float farPlane = 100.0; //Depth of 1.0
const float PI = 3.141592;
const float camFOV = 80.0 * PI/180.0;
const float aspectRatio = 4.0/3.0;
const float camYSlope = tan(atan(aspectRatio * tan(camFOV/2.0))/2.0);
float depth = (clamp((texUV.y-1.0)*camYSlope+0.5, nearPlane, farPlane) - nearPlane) / (farPlane-nearPlane);
All of the above code can be played with at this shader toy. Changing the nearPlane
, farPlane
, camFOV
, and aspectRatio
and hitting ALT + ENTER
will update the shader to show the various changes.
Using this final value equation and modulating the near and far plane we can easily change the desired depth values.
nearPlane = 0.001; farPlane = 15.0; //A closer farPlane
[-1,1]
from bottom-left to top-right? \$\endgroup\$