Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 通过渲染四边形更新粒子系统的速度和位置_C_Opengl_Gpu_Particle System - Fatal编程技术网

C 通过渲染四边形更新粒子系统的速度和位置

C 通过渲染四边形更新粒子系统的速度和位置,c,opengl,gpu,particle-system,C,Opengl,Gpu,Particle System,使用本文中的算法实现基于GPU的粒子系统: 有两件事我不明白: 为什么要使用堆栈或堆来存储可用的粒子索引? 如果一个粒子在时间t死亡,那么它将在时间t+1从零开始其生命。有一个参数N用于控制屏幕上的粒子数。如果我可以重用所有粒子,为什么我要关心可用粒子的所有索引,甚至使用堆来存储它 为了更新速度和位置,它说,“实际模拟是在片段着色器中实现的。通过渲染屏幕大小的四元体,为渲染目标的每个像素执行着色器…”如果我希望将粒子绘制为点,是否需要将四元体更改为点为什么是四边形?它如何绘制点 术语“par

使用本文中的算法实现基于GPU的粒子系统:

有两件事我不明白:

  • 为什么要使用堆栈或堆来存储可用的粒子索引? 如果一个粒子在时间t死亡,那么它将在时间t+1从零开始其生命。有一个参数N用于控制屏幕上的粒子数。如果我可以重用所有粒子,为什么我要关心可用粒子的所有索引,甚至使用堆来存储它
  • 为了更新速度和位置,它说,“实际模拟是在片段着色器中实现的。通过渲染屏幕大小的四元体,为渲染目标的每个像素执行着色器…”如果我希望将粒子绘制为点,是否需要将四元体更改为点为什么是四边形?它如何绘制点
  • 术语“particle is dead”是一个术语,它只描述了一个particle在语义上的dead。从GPU的角度来看,所有粒子始终处于活动状态,并且所有粒子都将在每个帧中计算。(或者至少会处理0到N的粒子,但即使是死粒子也会处理)。

    一旦CPU“检测到”某个粒子已死亡(例如,其年龄为5秒左右),则需要记住该粒子的索引,以便新粒子可以重用该粒子索引。这可以通过许多不同的方式实现,两种明显的方式是堆栈或堆。

    只有当粒子的最大年龄不同时,才需要一种特殊的数据结构来存储这些死粒子指数。如果它们没有区别,您可以实现一个环形缓冲区。但大多数情况下,您将对所有类型的粒子使用此粒子引擎,这些粒子可能具有可变的生存时间值。然后您需要这些数据结构

  • 该算法使用片段着色器进行速度计算。它从一个纹理(包含x/y/z坐标而不是r/g/b颜色信息)读取数据,并写入另一个纹理(也包含x/y/z坐标而不是r/g/b颜色信息),在源纹理和目标纹理之间使用1:1映射,并将整个源纹理渲染到目标纹理。这与稍后在步骤
    6中渲染的实际粒子无关。渲染粒子


    或者换句话说:“屏幕大小的四边形”在这里实际上是一个错误的术语,它应该读为“纹理大小的四边形”,因为在这一点上,没有任何东西被绘制到屏幕上。目标纹理(即,将保存新位置信息的纹理)是屏幕

  • /请再次编辑:

    好的,也许可以重新表述一下文档:

    您有一个
    结构

    struct color {
        float r, g, b;
    };
    
    还有一些定义:

    #define vector color
    #define x r
    #define y g
    #define z b
    
    还有一些粒子阵列:

    #define NP 1024 * 1024
    struct vector particle_pos[2][NP];
    struct vector particle_vel[2][NP];
    uint32_t particle_birth_tick[NP];
    
    // Double buffering - gonne have to remember, where
    // we read from and where we write to:
    struct vector * particle_pos_r = particle_pos[0];
    struct vector * particle_pos_w = particle_pos[1];
    struct vector * particle_vel_r = particle_vel[0];
    struct vector * particle_vel_w = particle_vel[1];
    
    现在:

  • 生与死的过程
  • 将纹理数据传输到顶点数据
  • 渲染粒子

  • 这里有趣的一点是,步骤2-5都只发生在GPU上(步骤1发生在GPU和CPU上)。因此,术语“呈现”。因为2和3中的循环只是将“纹理”
    particle\u-vel\r
    和/或
    particle\u-pos\r
    渲染到“帧缓冲区”
    particle\u-vel\u-w
    particle\u-pos\u-w
    中,用源纹理完全填充帧缓冲区“屏幕大小的四边形”,这是否意味着我们首先创建最大的纹理(例如1024*1024),如果我们只希望在一帧中有100个粒子出现在屏幕上,我们只需要操纵一个100大小的堆,弹出它们的索引,并只更新1024*1024纹理中这100个粒子的属性。对于问题2,我可以理解位置纹理用作片段着色器的输入,因为位置纹理包含所有粒子位置信息。我不明白的是为什么渲染屏幕大小的四边形可以进行计算!渲染四边形后,是否所有粒子都显示在屏幕上?片段着色器如何知道我希望将粒子绘制为点或广告牌?问题2:请参见编辑后的答案。问题1:我不知道你现在是什么意思。但我想,你现在是对的。或者,你可以让GPU从一开始就处理整个1k*1k纹理,或者你可以只处理其中的一部分,比如“前5行”,因为所有的“活动”粒子都适合在那里。问题2:渲染意味着在屏幕上绘制,对吗?碎片缓冲区将粒子的位置(x、y、z)作为输入,然后绘制一个四边形。你为什么在屏幕上画位置?我的意思是,通常我们使用glBegin(GL_点)绘制点,然后指定点的位置。渲染四边形时,GPU如何知道您正在渲染点?如果我想把每个粒子渲染成一个广告牌呢?再说一遍:他们滥用GPU进行数学计算。GPU可以从纹理中读取数据(通常为颜色数据)并将数据写入纹理(同样,通常为颜色数据)。但在这里,正如我所说,他们滥用GPU进行计算。因此,他们不是读取颜色数据,而是读取xyz坐标,对其进行数学运算,然后将其写入新纹理。这个过程也被称为渲染,因为它与移动颜色数据的操作相同。请记住:在该文档的第6步之前,实际包含用户可见图片的帧缓冲区不会发生任何变化。顺便说一句:刚刚阅读完毕:»粒子可以渲染为点精灵、三角形或四边形[…]。如果要为每个粒子生成多个顶点,[…]概念[…]要求在渲染之前手动复制粒子位置。在进一步的渲染步骤中,需要将位置渲染三到四次,使其成为纹理中彼此相邻的像素。[…]«和»由于上一节提到的原因,为了减少顶点单元的工作量,粒子当前渲染为点精灵。«
    #define TTL 5 * 25 // 5 seconds * 25 simulation steps per second.
    for (size_t i = 0; i < NP; ++i) {
        if (particle_birth_tick[i] + TTL == current_tick) {
            particle_pos_r[i].x = somewhere behind viewer;
            particle_pos_r[i].y = somewhere behind viewer;
            particle_pos_r[i].z = somewhere behind viewer;
            particle_vel_r[i].x = 0;
            particle_vel_r[i].y = 0;
            particle_vel_r[i].z = 0;
            free_list.add(i);
        }
    }
    void add_particle(struct vector p, struct vector v) {
        size_t i = free_list.pop_any();
        particle_pos_r[i] = p;
        particle_vel_r[i] = v;
    }
    
    for (size_t i = 0; i < 1024 * 1024; ++i) {
        particle_vel_w[i].x = do_calculations(particle_vel_r[i].x)
        particle_vel_w[i].y = do_calculations(particle_vel_r[i].y)
        particle_vel_w[i].z = do_calculations(particle_vel_r[i].z)
    }
    swap(particle_vel_r, particle_vel_w);
    
    for (size_t i = 0; i < 1024 * 1024; ++i) {
        particle_pos_w[i].x = particle_pos_r[i].x + particle_vel_r[i].x;
        particle_pos_w[i].y = particle_pos_r[i].y + particle_vel_r[i].y;
        particle_pos_w[i].z = particle_pos_r[i].z + particle_vel_r[i].z;
    }
    swap(particle_pos_r, particle_pos_w);
    
    sort a bit...
    
    copy the pos texture into a vbo
    
    actually draw particles