Java 渲染深度到纹理
我无法获得正确渲染的深度。没有抛出错误,glCheckFramebufferStatus也表示它已完成 下面是代码,屏幕总是显示为白色。深度值不是1,但非常接近: 编辑: 所以我尝试线性化深度片段着色器内部的深度,然后直接绘制到屏幕上,以确保值是正确的。他们是正确的。然而,即使我将线性化的深度发送到我的全屏四元着色器(下面的第二个),屏幕仍然是全白色的Java 渲染深度到纹理,java,opengl,glsl,lwjgl,framebuffer,Java,Opengl,Glsl,Lwjgl,Framebuffer,我无法获得正确渲染的深度。没有抛出错误,glCheckFramebufferStatus也表示它已完成 下面是代码,屏幕总是显示为白色。深度值不是1,但非常接近: 编辑: 所以我尝试线性化深度片段着色器内部的深度,然后直接绘制到屏幕上,以确保值是正确的。他们是正确的。然而,即使我将线性化的深度发送到我的全屏四元着色器(下面的第二个),屏幕仍然是全白色的 public void initFramebuffers() { glBindFramebuffer(GL_FRAMEBUFFER, d
public void initFramebuffers() {
glBindFramebuffer(GL_FRAMEBUFFER, depthShader.fbo);
depthShader.initTexture(width, height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthShader.tex, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
public void initTexture(int width, int height, int format, int internalFormat) {
tex = glGenTextures();
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_FLOAT, (ByteBuffer)null);
}
深度着色器:
#version 400
in vec3 pos;
in float radius;
uniform mat4 mView;
uniform mat4 projection;
uniform vec2 screenSize;
uniform vec3 lightPos;
out float depth;
float linearizeDepth(float depth) {
float n = 0.01;
float f = 100;
return (2.0 * n) / (f + n - depth * (f - n));
}
void main() {
//calculate normal
vec3 normal;
normal.xy = gl_PointCoord * 2.0 - 1.0;
float r2 = dot(normal.xy, normal.xy);
if (r2 > 1.0) {
discard;
}
normal.z = sqrt(1.0 - r2);
//calculate depth
vec4 pixelPos = vec4(pos + normal * radius, 1.0);
vec4 clipSpacePos = projection * pixelPos;
depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
depth = linearizeDepth(depth);
}
读取深度的着色器。线性化深度中的值是我的近距离和远距离:
#version 400
in vec2 coord;
uniform sampler2D depthMap;
uniform vec2 screenSize;
uniform mat4 projection;
out vec4 color;
float linearizeDepth(float depth) {
float n = 0.01;
float f = 100;
return (2.0 * n) / (f + n - depth * (f - n));
}
void main() {
float curDepth = texture2D(depthMap, coord).x;
//float d = linearizeDepth(curDepth);
color = vec4(d, d, d, 1.0f);
}
绘制所有内容的代码:
//--------------------Particle Depth-----------------------
{
glUseProgram(depthShader.program);
glBindFramebuffer(GL_FRAMEBUFFER, depthShader.fbo);
depthShader.particleDepthVAO(points);
//Sets uniforms
RenderUtility.addMatrix(depthShader, mView, "mView");
RenderUtility.addMatrix(depthShader, projection, "projection");
RenderUtility.addVector2(depthShader, screenSize, "screenSize");
RenderUtility.addVector3(depthShader, lightPosition, "lightPos");
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(depthShader.vao);
glDrawArrays(GL_POINTS, 0, points.size());
}
//Draw full screen
{
glUseProgram(blurShader.program);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
blurShader.blurDepthVAO();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthShader.tex);
glUniform1i(blurShader.depthMap, 0);
//Sets uniforms
RenderUtility.addMatrix(blurShader, mView, "mView");
RenderUtility.addMatrix(blurShader, projection, "projection");
RenderUtility.addVector2(blurShader, screenSize, "screenSize");
//glEnable(GL_DEPTH_TEST);
glBindVertexArray(blurShader.vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glViewport(0, 0, width, height);
}
问题最终是我的顶点着色器的out变量名与片段着色器的in变量名(doh)不匹配。上面发布的代码是100%正确的,以防将来有人看到。发布的代码有一些问题 渲染目标的使用不一致 在FBO的设置中,只有深度附件,没有颜色附件。颜色绘制缓冲区也被显式禁用:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthShader.tex, 0);
glDrawBuffer(GL_NONE);
但是,片段着色器会写入颜色输出:
out float depth;
...
depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
depth = linearizeDepth(depth);
要写入帧缓冲区的深度附件,必须设置预定义的gl_FragDepth
变量的值。仅仅因为out变量名为depth
,并不意味着它实际上被用作深度输出。如果要使用颜色输出,必须创建常规纹理,并将其附加到GL\u color\u ATTACHMENT0
。这看起来更容易
线性化深度()计算
处理clipSpacePos
的方式似乎是linarizeDepth()
的参数介于0.0和1.0之间。这些极值的函数内计算如下:
0.0 --> (2.0 * n) / (f + n)
1.0 --> 1.0
对于1.0来说,这看起来不错,但是对于0.0来说,这是有问题的。我相信做准备的步骤实际上更为正确:
depth = clipSpacePos.z / clipSpacePos.w;
然后将-1.0和1.0之间的参数传递给函数,该函数随后生成:
-1.0 --> n / f
1.0 --> 1.0
事实上,对我来说,将整个事情缩放到0.0到1.0之间会更有意义,但至少这个版本有直观的意义,可以产生到远平面的相对距离
计算过于复杂
以上这些在我看来是不必要的复杂。您正在应用投影矩阵,从结果中获取深度,然后有效地反转投影矩阵应用的深度计算
一开始不应用投影矩阵,只取原始距离似乎简单得多。如果需要相对距离,仍然可以除以“远距离”。至少只要您使用标准投影矩阵,我相信以下内容相当于上面更正的计算:
vec4 pixelPos = vec4(pos + normal * radius, 1.0);
float f = 100.0; // far plane
depth = -pixelPos.z / f;
减号之所以出现,是因为最常用的眼睛坐标系假设您向下看的是负z轴
如果希望结果介于0.0和1.0之间,还可以将其更改为:
float n = 0.01; // near plane
float f = 100.0; // far plane
depth = (-pixelPos.z - n) / (f - n);
深度片段着色器中的线性化不正确,已更正。根据我在网上读到的,线性化函数似乎是标准的。此外,着色器的实现基于请不要以使答案无效的方式编辑问题。这不是目的。其目的是反映我的代码的当前状态,即在我看到您的答案之前它所处的状态。让它保持这种状态对我来说只是一个错误,我忽略了更新它。它可能有点晚了,但在线性化深度值时仍然有一个错误。如果对你有用的话,你可能不会认为这一切都是错误的,但有另一种方法可以线性化深度(对我有用)。请看这个问题:在这个公式中,另一个f乘以linDepth()函数的返回值。
float n = 0.01; // near plane
float f = 100.0; // far plane
depth = (-pixelPos.z - n) / (f - n);