【问题标题】:Point sprite size attenuation with modern OpenGL使用现代 OpenGL 衰减点精灵大小
【发布时间】:2021-05-28 18:55:27
【问题描述】:

我正在尝试使用 OpenGL 3+ 使用点精灵来渲染一些粒子。我刚刚意识到我的观点存在重大问题。它们的大小会根据相机距离自动增加。结果如下:

接近粒子发射器:

而当距离很远时,一切都显得模糊而臃肿:

在旧版本中,似乎可以使用glPointParameter 调整磅值。该函数在新的 3+ OpenGL 中仍然可用,但它只支持两个参数。 GL_POINT_FADE_THRESHOLD_SIZE 似乎是我需要的,但我已经尝试过了,但没有结果。我也在使用glEnable(GL_PROGRAM_POINT_SIZE);

还有其他方法可以避免根据相机距离自动缩放点吗?我宁愿不必更改代码来使用由三角形制成的标准广告牌。

目前不确定是否相关,但这是我正在使用的顶点着色器:

layout(location = 0) in vec4 a_position_size; // Point size in w coord
layout(location = 1) in vec4 a_color;         // RGBA color modulated with texture

layout(location = 0) out vec4 v_color;

uniform mat4 u_MVPMatrix;

void main()
{
    gl_Position  = u_MVPMatrix * vec4(a_position_size.xyz, 1.0);
    gl_PointSize = a_position_size.w;
    v_color      = a_color;
}

【问题讨论】:

  • 您必须将gl_PointSize 与远离相机的距离一起缩放。 OpenGL 不会(也不能合理地)为你做这件事。
  • @ColonelThirtyTwo,但 OpenGL 已经在缩放这些点。我不能以某种方式禁用它吗?取消 GL 所做的规模似乎有点 hack...
  • 不是缩放点。无论它们的z 坐标如何,它们在屏幕上始终是gl_PointSize 单位。它们只是在离开时看起来越来越大,因为其他一切都在变小。
  • @ColonelThirtyTwo,哦,我明白了,现在我意识到了。无论如何,文档中也很清楚:“gl_PointSize - 包含光栅化点的大小,以像素为单位”。谢谢。
  • 是的,gl_PointSize 在窗口空间中。换句话说,它的度量单位是 1 个像素。

标签: opengl glsl particle-system point-sprites


【解决方案1】:

原来我的问题是由于我对gl_PointSize的误解。正如 cmets 中所述并在文档中明确说明,gl_PointSize 包含光栅化点的大小,以像素为单位。因此,当我们远离点精灵时,它们看起来会更大,但这并不是因为它们被缩放了,而是因为它们仍然占据相同的屏幕空间,而 3D 场景的其余部分正在根据透视投影被缩小。

我通过对顶点着色器进行一些调整以根据与观察者的距离实际缩放点大小来解决问题:

uniform mat4 u_MVPMatrix;
uniform vec3 u_cameraPos;

// Constants (tweakable):
const float minPointScale = 0.1;
const float maxPointScale = 0.7;
const float maxDistance   = 100.0;

void main()
{
    // Calculate point scale based on distance from the viewer
    // to compensate for the fact that gl_PointSize is the point
    // size in rasterized points / pixels.
    float cameraDist = distance(a_position_size.xyz, u_cameraPos);
    float pointScale = 1.0 - (cameraDist / maxDistance);
    pointScale = max(pointScale, minPointScale);
    pointScale = min(pointScale, maxPointScale);

    // Set GL globals and forward the color:
    gl_Position  = u_MVPMatrix * vec4(a_position_size.xyz, 1.0);
    gl_PointSize = a_position_size.w * pointScale;
    v_color      = a_color;
}

【讨论】:

    【解决方案2】:

    在使用 GLSL 和 three.js 时遇到了同样的问题。根据glampert的回答解决了它,但首先three.js需要使用某些predefined variable names

    uniform vec4 origin;
    
    void main() {
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        float cameraDist = distance( mvPosition, origin );
        gl_PointSize = 200.0 / cameraDist;
        gl_Position = projectionMatrix * mvPosition;
    }
    

    其次要注意,modelViewMatrix首先应用于粒子位置,然后计算到该位置的距离。因为如果您对粒子系统对象应用变换,您的粒子位于不等于全局坐标的对象坐标中。所以我计算视图坐标中的距离(相机始终在原点)。

    【讨论】:

    • "预定义的变量名有点不同" gl_PointSizegl_Position 在 WebGLSL 和桌面 GLSL 中的命名相同。这些是您的答案或上一个答案使用的唯一预定义变量。
    • @nicol 我没有在任何地方定义cameraPospositionmodelViewMatrixprojectionMatrix,老实说,我对 GLSL 了解得不够多,不知道它们是在哪里定义的。当我尝试上一个答案中的代码时,我收到错误'a_position_size' : undeclared identifier。所以可访问变量的集合是不一样的。也许你能告诉我为什么?是因为我用的是three.js吗?
    • @nicol 我发现这些变量名确实是由 three.js 定义的,并在我的答案中添加了相关信息。
    猜你喜欢
    • 2015-03-21
    • 1970-01-01
    • 1970-01-01
    • 2014-04-04
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    相关资源
    最近更新 更多