【问题标题】:How to limit emitted vertices with Geometry shader using Transform feedback?如何使用变换反馈限制几何着色器发射的顶点?
【发布时间】:2014-02-22 22:11:12
【问题描述】:

我正在使用 OpenGL 开发一个简单的粒子系统,我需要在 GPU 上生成粒子。通常我将粒子表示为GL_POINTS,并且一开始只使用一个粒子生成点。 我所做的是创建两个顶点缓冲区对象 (VBO) 并根据 最大粒子数 在 GPU 上分配内存。然后创建两个变换反馈缓冲区 (TFB),每个都绑定到一个 VBO 的输出。第一个 TFB 代表第二个 VBO 的输入,反之亦然(交换缓冲区)。

然后我在几何着色器上生成新的顶点(= 点、粒子)。

几何着色器代码:

#version 330 compatibility

#extension GL_ARB_geometry_shader4 : enable

layout(points) in;
layout(points, max_vertices = 3) out;

in block{
  vec4 v_WorldPosition;

  vec3 f_Position;
  vec3 f_Color;  
} In[];

out block{
  vec4 v_WorldPosition;
  vec4 v_Color;
} Out;

out feedback{
  vec3 f_Position; 
  vec3 f_Color;  
} feedOut;


const int i = 0; // No need for loop (points. In.length() == 1)

void main()
{  
    feedOut.f_Position = In[i].f_Position; 
    feedOut.f_Color    = In[i].f_Color; 

    if(In[i].f_Color.g == 1){
        feedOut.f_Color.g = 0;
    }

    Out.v_Color = vec4(feedOut.f_Color, 1);
    gl_Position = In[i].v_WorldPosition; 

    EmitVertex();
    EndPrimitive();

    if(In[i].f_Color.g == 1){
        // create new particle
        feedOut.f_Position  = In[i].f_Position; 
        feedOut.f_Color     = vec3(1,0,0);

        Out.v_Color = vec4(feedOut.f_Color, 1);
        gl_Position = In[i].v_WorldPosition;

        EmitVertex();
        EndPrimitive();
    }
  }
}

暂时我使用绿色信息来确定粒子是否应该分成两个。根据某些计时器,此信息会定期添加到顶点着色器中。只有块 feedback 被存储到 TBF 中(从上面的代码中删除了不相关的属性变量)。

这很好用,但问题是当我发出比缓冲区大小更多的顶点时。我预计在这种情况下不会再创建顶点,但似乎新创建的顶点会覆盖旧的顶点

如何通过变换反馈存储额外发射的顶点?(我无法在任何规范中找到)。它似乎也以第一个粒子是唯一稳定的粒子而结束,所有其他粒子逐渐被推出缓冲区并被第一个粒子创建的粒子所取代。

在最终的程序中,我希望能够从管道中删除顶点并根据一些时间变量等添加新顶点 - 所以我没有任何指定的缓冲区数据结构。

有没有办法防止覆盖?我需要在缓冲区已满的情况下实际上不创建新粒子,并且仅当从缓冲区中删除(=未发射)粒子时 - 新粒子可以被创建。这是标准行为吗?

注意: 在 GeForce GT 630M 和 GeForce GTX 260 (Windows 7 x64) 上试用。

【问题讨论】:

  • 我不确定这是否回答了您的问题,但根据opengl.org/wiki/Transform_Feedback“如果您的绑定缓冲区范围不足以容纳记录的数据,则会导致未定义的行为。”
  • 谢谢,这很有帮助。

标签: c++ opengl


【解决方案1】:

我认为你应该首先阅读 gl Query Objects。 GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 有一个专门的查询对象。来自规范:记录几何着色器流写入到变换反馈对象的图元数量。

一旦你弄清楚是否有太多的基元(或者在一个点的情况下,单个顶点,可能是颜色和位置以及直到调用 EndPrimitive())被编写,你可以一种不同的变换反馈更新函数和相应的 glsl prog,其结构与添加原语的结构相同,除了这个只是更新您已经拥有的内容或删除当前的内容。确保您知道每个基元的大小(在本例中为一个点),以便您可以轻松查询您的大小,以确保您不会检查已分配的内容。此外,给每个人一个计时器也不是一个坏主意,这样您就可以轻松地决定一生。类似于您在顶点着色器中所做的以查看它们是否应该划分,但不同之处在于您将在几何着色器中检查它们的生命,并且如果它们已经死亡则不发射该顶点。

【讨论】:

  • 谢谢。正如你提到的,我已经使用了这些查询对象,它工作正常。我可以根据先前编写的粒子数量的知识来限制粒子 - 但我可以进一步限制粒子在一个几何着色器迭代(CPU 主循环迭代)中吗? 示例: MaxParticles = 100。在上一步中写入的粒子 = 80。然后每个粒子再创建 2 个粒子 -> 160。超过缓冲区并覆盖粒子。 我的解决方案: MaxParticles = 100。BufferSize = 300(3 倍大冗余)。总结一下:我正在寻找某种同步(?)有可能吗?
【解决方案2】:

您是否正在寻找类似的东西:

//read 
int temp;
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &temp);

//write
glProgramParameteriEXT(m_Program, GL_GEOMETRY_VERTICES_OUT_EXT, count);

【讨论】:

  • 我没有看到 GL_MAX_GEOMETRY_OUTPUT_VERTICES 的相关性。根据spec GL_GEOMETRY_VERTICES_OUT 确实是“程序中几何着色器将输出的最大顶点数”。但不知何故,它不起作用。我会尝试一下。
【解决方案3】:

最后发现忘记映射Transform Feedback Buffer的缓冲范围了。

glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, VBO_id, 0, nMaxParticleBound * sizeof(Particle));

因此,当在几何着色器上创建其他粒子时,它们不会写入变换反馈缓冲区。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    • 2020-03-10
    • 2018-07-28
    相关资源
    最近更新 更多