Output of the vertex shader,

DX: SV_Position

The following transform is done after the vertex shader,

On both GL and DX

The following transform is done in hardware,

NDC.x * (W* 0.5 ) + (X + W*0.5),

NDC.y * (H*(-0.5)) + (Y + H*0.5),

NDC.z * (F-N) + N);

With parameters specified by

Y = D3D11_VIEWPORT.TopLeftY;

W = D3D11_VIEWPORT.Width;

H = D3D11_VIEWPORT.Height;

N = D3D11_VIEWPORT.MinDepth;

F = D3D11_VIEWPORT.MaxDepth;

Fractional viewport parameters for

The following transform is done in hardware,

NDC.x * (W*0.5) + (X + W*0.5),

NDC.y * (H*0.5) + (Y + H*0.5),

NDC.z * ((F-N)*0.5) + (N+F)*0.5);

These versions of GL have the following form to specify input parameters,

Note the inputs to

Which when computed with standard 32-bit floating point, I believe has in theory exactly only enough precision for 24-bit integer depth buffers.

These versions of OpenGL dropped the clamp type resulting in,

Both specs say,

Which results in no precision destroying floating point addition in the Window Coordinate transform,

However at least some vendor(s) still do the clamp anyway. To get around the clamp in GL one can use GL_NV_depth_buffer_float which provides

General form,

0 Y 0 0

0 0 A 1

0 0 B 0

The A=0 case provides the highest precision. Next highest precision from

float4 ConstX = ModelViewMatrixX * X;

float4 ConstY = ModelViewMatrixY * Y;

float4 ConstZ = ModelViewMatrixZ;

float2 ConstAB = float2(A, B);

// Vertex shader work

float3 View = float3(

dot(Vertex, ConstX) + ConstX.w,

dot(Vertex, ConstY) + ConstY.w,

dot(Vertex, ConstZ) + ConstZ.w);

float3 Projected = float3(

View.x,

View.y,

View.z * ConstA + ConstB,

View.z);

This is both the fastest and highest precision path. For DX, or GL using

0 Y 0 0

0 0 0 1

0 0 N 0

This can be optimized to the following,

float4 ConstX = ModelViewMatrixX * X;

float4 ConstY = ModelViewMatrixY * Y;

float4 ConstZ = ModelViewMatrixZ;

float ConstN = N; // Ideally N=1 and no constant is needed.

// Vertex shader work

float4 Projected = float4(

dot(Vertex, ConstX) + ConstX.w,

dot(Vertex, ConstY) + ConstY.w,

ConstN,

dot(Vertex, ConstZ) + ConstZ.w);

For GL without

0 Y 0__ 0

0 0 -1_ 1

0 0 2*N 0

Which can be optimized to the following,

vec4 ConstX = ModelViewMatrixX * X;

vec4 ConstY = ModelViewMatrixY * Y;

vec4 ConstZ = ModelViewMatrixZ;

float ConstN = 2.0 * N; // Ideally N=1 and no constant is needed.

// Vertex shader work

vec4 Projected;

Projected.w = dot(Vertex, ConstZ);

Projected.xyz = float3(

dot(Vertex, ConstX) + ConstX.w,

dot(Vertex, ConstY) + ConstY.w,

ConstN - Projected.w);

http://www.humus.name/Articles/Persson_CreatingVastGameWorlds.pdf

http://www.geometry.caltech.edu/pubs/UD12.pdf

http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html