在OpenGL中使用点精灵进行深度测试

时间:2017-01-09 15:14:46

标签: c++ opengl particles

我正在尝试使用点精灵来使用OpenGL 3进行粒子系统。

我使用带有GL_STREAM_DRAW的VBO,其中我放置了每个粒子的坐标。 在每个帧期间,我用新的粒子坐标更新VBO。使用GL_VERTEX_PROGRAM_POINT_SIZE简单地使用GL_POINTS渲染粒子。

我注意到有些颗粒被其他颗粒覆盖,尽管它们应该更靠近相机。

点精灵实际上是按绘制调用的顺序而不是深度绘制的,这会产生如下情况:

The farthest particle is drawn first, the closes particle is drawn second.

这里首先绘制最远的粒子,然后绘制闭粒子。正如预期的那样,衣柜颗粒完全覆盖了它背后的那个。

This time the order is reversed.

此处,绘制顺序相反,导致最远的粒子可见。

我尝试使用

进行OpenGL深度测试
getInstance

但这只会导致没有被吸引。

据我所知,解决这个问题的一种方法是按深度重新排序粒子,但是对于许多粒子来说这个解决方案在CPU上会非常昂贵,所以有没有办法对GPU上的点精灵进行适当的深度测试?

用于绘制粒子的顶点着色器如下:

glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);
    glDepthFunc(GL_LEQUAL);
    glDepthRange(0.f, 1.f);
glEnable(GL_DEPTH_CLAMP);

片段着色器:

#version 330

layout(location = 0) in vec4 position;

uniform float time;
uniform mat4 camera;

smooth out float dist;

void main()
{
    vec4 cameraPos = position + vec4(0.0, 0.0, -1.0, 0.0);
    gl_Position = camera * cameraPos;
    dist = sqrt(dot(camera * cameraPos, position));
    gl_PointSize = 15.0/dist;
}

完整代码(减去一些样板代码):

#version 330

out vec4 colour;
uniform float time;

smooth in float dist;

float map(float value, float inMin, float inMax, float outMin, float outMax) {
  return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

void main()
{
//  colour = vec4(pos.x, pos.y, 1.0, 1.0);
    if(dot(gl_PointCoord-0.5,gl_PointCoord-0.5)>0.25)
        discard;
    else {
        float g = (dot(gl_PointCoord-0.5,gl_PointCoord-0.5) > 0.22 ? 0.6 : map(dot(gl_PointCoord-0.5,gl_PointCoord-0.5), 0.0, 0.21, 0.0, 0.6));
        colour = vec4(g, g*sin(time)*sin(time)*cos(time), sin(dist), 1.0);
    }
}

1 个答案:

答案 0 :(得分:0)

这个问题实际上与2个问题有关:

1 - 深度缓冲区从未被清除,因为评论中提到了用户derhass

2 - 顶点缓冲区中的点大小以错误的方式计算。透视矩阵仅应用于摄像机位置,而不应用于顶点位置。它应该是dist = distance(cameraPos, position));而不是dist = sqrt(dot(camera * cameraPos, position));