Нарисуйте значение глубины в OpenGL с помощью шейдеров
Я хочу нарисовать буфер глубины во фрагментном шейдере, я делаю это:
Вершинный шейдер:
varying vec4 position_;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
position_ = gl_ModelViewProjectionMatrix * gl_Vertex;
Фрагмент шейдера:
float depth = ((position_.z / position_.w) + 1.0) * 0.5;
gl_FragColor = vec4(depth, depth, depth, 1.0);
Но я печатаю только белое, что я делаю не так?
2 ответа
В каком пространстве вы хотите нарисовать глубину? Если вы хотите нарисовать глубину пространства окна, вы можете сделать это:
gl_FragColor = vec4(gl_FragCoord.z);
Однако это не будет особенно полезно, так как большинство чисел будет очень близко к 1,0. Только очень близкие объекты будут видны. Это характер распределения значений глубины для буфера глубины с использованием стандартной перспективной проекции.
Или, другими словами, поэтому вы побелели.
Если вы хотите, чтобы эти значения были в линейном пространстве, вам нужно будет сделать что-то вроде следующего:
float ndcDepth = ndcPos.z =
(2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
(gl_DepthRange.far - gl_DepthRange.near);
float clipDepth = ndcDepth / gl_FragCoord.w;
gl_FragColor = vec4((clipDepth * 0.5) + 0.5);
Действительно, значение "глубины" фрагмента можно прочитать из его значения z в пространстве клипа (то есть после всех преобразований матрицы). Это правильно.
Однако ваша проблема в делении на w
, Деление на w
называется перспективным разделением. Да, это необходимо для правильной работы перспективной проекции.
Однако. Деление на w
в этом случае "связывает" все ваши значения (как вы видели), чтобы быть очень близким к 1,0. Для этого есть веская причина: в перспективеw= (some multiplier) *z
, То есть вы делите значение z (каким бы оно ни было вычисленным) на (некоторый фактор) исходного z. Не удивительно, что вы всегда получаете значения около 1,0. Вы почти делите Z на себя.
Как очень просто исправить это, попробуйте разделить z
просто на дальнем плане и отправьте это фрагментному шейдеру как глубину.
Вершинный шейдер
varying float DEPTH ;
uniform float FARPLANE ; // send this in as a uniform to the shader
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
DEPTH = gl_Position.z / FARPLANE ; // do not divide by w
Фрагмент шейдера:
varying float DEPTH ;
// far things appear white, near things black
gl_Color.rgb=vec3(DEPTH,DEPTH,DEPTH) ;
Результатом является неплохое, очень линейно выглядящее затухание.