渲染中的 OpenGL 闪烁问题
OpenGL flickering issue in rendering
我有一个 OpenGL 渲染问题,我认为这是由于 Z-Buffer 的问题。
我有一个代码来渲染一组点,它们的大小取决于与相机的距离。因此,更大的点意味着更接近相机。此外,在以下快照中,颜色反映了片段的 z 缓冲区。
怎么看摄像头附近有个大点
然而,一些帧之后,相同的点被渲染在更远的点后面。
这些是我在渲染点之前调用的函数:
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
这是顶点着色器:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
// uniform variable
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform float pointSize;
out vec4 fragColor;
void main() {
gl_Position = projection * view * model * vec4(position, 1.0f);
vec3 posEye = vec3(view * model * vec4(position, 1.0f));
float Z = length(posEye);
gl_PointSize = pointSize / Z;
fragColor = color;
}
这是片段着色器
#version 330 core
in vec4 fragColor;
out vec4 outColor;
void main() {
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
float r = dot(cxy, cxy);
if(r > 1.0) discard;
// calculate lighting
vec3 pos = vec3(cxy.x,cxy.y,sqrt(1.0-r));
vec3 lightDir = vec3(0.577, 0.577, 0.577);
float diffuse = max(0.0, dot(lightDir, pos));
float alpha = 1.0;
float delta = fwidth(r);
alpha = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
outColor = fragColor * alpha * diffuse;
}
更新
看起来问题出在近平面和远平面的定义上。
我不明白哪些是我应该使用的最佳值。
这是我用来创建投影矩阵的函数
glm::perspective(glm::radians(fov), width/(float)height, zNear, zFar);
其中 winth=1600 height=1200 fov=45
当事情不起作用时,zNear 设置为零,zFar 设置为距点云重心的最远点的距离加倍,即在我的例子中为 1.844
如果我将近裁剪平面从 0 移动到 0.1,闪烁似乎得到了解决。然而,我之前看到的远处的物体消失了。所以我也将远平面更改为 10,一切似乎都有效。不幸的是,我不明白为什么我以前使用的值不好。
正如已经更新的那样,当在投影矩阵中选择错误的近距和远距窗格时,这个问题称为 Z 冲突。如果它们离您的对象太远,则只剩下非常离散的 z 值。然后绘图由着色器中的调用顺序和处理顺序确定,因为z没有区别。如果有人暗示需要先做什么,就那样画。一旦设置了渲染调用,就没有正确的方法来确定哪个处理器首先获取对象,并且您会看到闪烁。
所以请更新您建立投影矩阵的方式。最佳实践:查看需要渲染的对象并确定一个大致的边界框,将其设为边界球,center-radius 是近窗格中的一个点,center+radius 是远窗格中的一个点。完成!
更新
调查
glm::perspective(glm::radians(fov), width/(float)height, zNear, zFar);
给出了 z 的唯一影响:(归一化之前):
Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
除了zFar!=zNear之外的意思,也应该避免将zNear设置为零。这意味着 z 没有差异,所以它必须 Flicker。然后我会假设你没有对你的投影矩阵应用一些变换,最好不要。如果您的所有对象都位于坐标中心周围的 space 中,这意味着也位于投影的中心,请将它们移动到投影前面作为最后一步。因此,不要在 projection/view 矩阵上应用一些转换,而是在您的对象矩阵上应用一些转换,以避免出现这种格式错误的投影 space。例如。设置为接近 1,并在场景中移动该数量的所有对象。
我有一个 OpenGL 渲染问题,我认为这是由于 Z-Buffer 的问题。
我有一个代码来渲染一组点,它们的大小取决于与相机的距离。因此,更大的点意味着更接近相机。此外,在以下快照中,颜色反映了片段的 z 缓冲区。
怎么看摄像头附近有个大点
然而,一些帧之后,相同的点被渲染在更远的点后面。
这些是我在渲染点之前调用的函数:
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
这是顶点着色器:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
// uniform variable
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform float pointSize;
out vec4 fragColor;
void main() {
gl_Position = projection * view * model * vec4(position, 1.0f);
vec3 posEye = vec3(view * model * vec4(position, 1.0f));
float Z = length(posEye);
gl_PointSize = pointSize / Z;
fragColor = color;
}
这是片段着色器
#version 330 core
in vec4 fragColor;
out vec4 outColor;
void main() {
vec2 cxy = 2.0 * gl_PointCoord - 1.0;
float r = dot(cxy, cxy);
if(r > 1.0) discard;
// calculate lighting
vec3 pos = vec3(cxy.x,cxy.y,sqrt(1.0-r));
vec3 lightDir = vec3(0.577, 0.577, 0.577);
float diffuse = max(0.0, dot(lightDir, pos));
float alpha = 1.0;
float delta = fwidth(r);
alpha = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
outColor = fragColor * alpha * diffuse;
}
更新
看起来问题出在近平面和远平面的定义上。
我不明白哪些是我应该使用的最佳值。
这是我用来创建投影矩阵的函数
glm::perspective(glm::radians(fov), width/(float)height, zNear, zFar);
其中 winth=1600 height=1200 fov=45
当事情不起作用时,zNear 设置为零,zFar 设置为距点云重心的最远点的距离加倍,即在我的例子中为 1.844
如果我将近裁剪平面从 0 移动到 0.1,闪烁似乎得到了解决。然而,我之前看到的远处的物体消失了。所以我也将远平面更改为 10,一切似乎都有效。不幸的是,我不明白为什么我以前使用的值不好。
正如已经更新的那样,当在投影矩阵中选择错误的近距和远距窗格时,这个问题称为 Z 冲突。如果它们离您的对象太远,则只剩下非常离散的 z 值。然后绘图由着色器中的调用顺序和处理顺序确定,因为z没有区别。如果有人暗示需要先做什么,就那样画。一旦设置了渲染调用,就没有正确的方法来确定哪个处理器首先获取对象,并且您会看到闪烁。
所以请更新您建立投影矩阵的方式。最佳实践:查看需要渲染的对象并确定一个大致的边界框,将其设为边界球,center-radius 是近窗格中的一个点,center+radius 是远窗格中的一个点。完成!
更新
调查
glm::perspective(glm::radians(fov), width/(float)height, zNear, zFar);
给出了 z 的唯一影响:(归一化之前):
Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
除了zFar!=zNear之外的意思,也应该避免将zNear设置为零。这意味着 z 没有差异,所以它必须 Flicker。然后我会假设你没有对你的投影矩阵应用一些变换,最好不要。如果您的所有对象都位于坐标中心周围的 space 中,这意味着也位于投影的中心,请将它们移动到投影前面作为最后一步。因此,不要在 projection/view 矩阵上应用一些转换,而是在您的对象矩阵上应用一些转换,以避免出现这种格式错误的投影 space。例如。设置为接近 1,并在场景中移动该数量的所有对象。