首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >粒子系统的点精灵

粒子系统的点精灵
EN

Stack Overflow用户
提问于 2013-07-01 13:03:48
回答 1查看 20.9K关注 0票数 34

点精灵是构建粒子系统的最佳选择吗?

点精灵是否存在于最新版本的OpenGL和最新显卡的驱动程序中?或者我应该使用vbo和glsl来实现?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-07-01 16:32:36

点精灵确实非常适合粒子系统。但它们与VBO和GLSL没有任何关系,这意味着它们是一个完全正交的特性。无论您是否使用点精灵,您始终必须使用VBO来上载几何体,无论它们只是点、预制精灵还是其他任何东西,并且您始终必须将此几何体通过一组着色器(当然是在现代OpenGL中)。

也就是说,点精灵在现代OpenGL中得到了很好的支持,只是不像旧的固定函数方法那样自动。不支持的是点衰减功能,该功能允许您根据点到相机的距离来缩放点的大小,您必须在顶点着色器中手动执行此操作。以同样的方式,您必须使用特殊输入变量gl_PointCoord (表示当前片段在整个点的0,1平方中的位置)在适当的片段着色器中手动对点进行纹理处理。例如,一个基本点sprite管道可能是这样的:

代码语言:javascript
运行
复制
...
glPointSize(whatever);              //specify size of points in pixels
glDrawArrays(GL_POINTS, 0, count);  //draw the points

顶点着色器:

代码语言:javascript
运行
复制
uniform mat4 mvp;

layout(location = 0) in vec4 position;

void main()
{
    gl_Position = mvp * position;
}

片段着色器:

代码语言:javascript
运行
复制
uniform sampler2D tex;

layout(location = 0) out vec4 color;

void main()
{
    color = texture(tex, gl_PointCoord);
}

仅此而已。当然,这些着色器只执行最基本的纹理精灵绘制,但它们是进一步功能的起点。例如,要根据精灵到摄影机的距离计算精灵的大小(可能是为了给它一个固定的世界空间大小),你必须对顶点着色器中的特殊输出变量gl_PointSize进行glEnable(GL_PROGRAM_POINT_SIZE)和写入:

代码语言:javascript
运行
复制
uniform mat4 modelview;
uniform mat4 projection;
uniform vec2 screenSize;
uniform float spriteSize;

layout(location = 0) in vec4 position;

void main()
{
    vec4 eyePos = modelview * position;
    vec4 projVoxel = projection * vec4(spriteSize,spriteSize,eyePos.z,eyePos.w);
    vec2 projSize = screenSize * projVoxel.xy / projVoxel.w;
    gl_PointSize = 0.25 * (projSize.x+projSize.y);
    gl_Position = projection * eyePos;
}

这将使所有的点精灵具有相同的世界空间大小(因此以像素为单位的不同屏幕空间大小)。

但是,点精灵虽然在现代OpenGL中仍然得到了完美的支持,但也有其缺点。最大的缺点之一是它们的裁剪行为。点在它们的中心坐标上被裁剪(因为裁剪是在光栅化之前完成的,因此在点被“放大”之前)。因此,如果点的中心在屏幕之外,则可能仍然到达查看区域的其余部分将不会显示,因此,在最坏的情况下,一旦点离开屏幕的一半,它将突然消失。然而,只有在点精灵太大的情况下,这才是值得注意的(或不明显的)。如果它们是非常小的粒子,每个粒子覆盖的像素不会超过几个像素,那么这不会是一个大问题,我仍然认为粒子系统是点精灵的典型用例,只是不要将它们用于大型广告牌。

但如果这是一个问题,那么现代OpenGL提供了许多其他方法来实现点精灵,除了在CPU上将所有精灵预先构建为单独的四元组的天真方法。您仍然可以将它们渲染为充满点的缓冲区(因此,它们可能会从基于GPU的粒子引擎中出来)。要实际生成四边形几何体,可以使用几何体着色器,该着色器允许您从单个点生成四边形。首先,仅在顶点着色器内执行模型视图变换:

代码语言:javascript
运行
复制
uniform mat4 modelview;

layout(location = 0) in vec4 position;

void main()
{
    gl_Position = modelview * position;
}

然后,几何体着色器完成其余工作。它将点位置与通用0,1-quad的4个角组合在一起,并完成到剪辑空间的转换:

代码语言:javascript
运行
复制
const vec2 corners[4] = { 
    vec2(0.0, 1.0), vec2(0.0, 0.0), vec2(1.0, 1.0), vec2(1.0, 0.0) };

layout(points) in;
layout(triangle_strip, max_vertices = 4) out;

uniform mat4 projection;
uniform float spriteSize;

out vec2 texCoord;

void main()
{
    for(int i=0; i<4; ++i)
    {
        vec4 eyePos = gl_in[0].gl_Position;           //start with point position
        eyePos.xy += spriteSize * (corners[i] - vec2(0.5)); //add corner position
        gl_Position = projection * eyePos;             //complete transformation
        texCoord = corners[i];                         //use corner as texCoord
        EmitVertex();
    }
}

在片段着色器中,你当然会使用自定义的texCoord varying而不是gl_PointCoord来制作纹理,因为我们不再绘制实际的点。

或者另一种可能性(也许更快,因为我记得几何体着色器有慢的名声)是使用实例化渲染。这样,你就有了一个额外的VBO,它只包含一个通用二维四边形(即0,1正方形)的顶点,而你的旧VBO只包含点的位置。然后,您要做的就是多次绘制这个四边形(实例化),同时从VBO点获取各个实例的位置:

代码语言:javascript
运行
复制
glVertexAttribPointer(0, ...points...);
glVertexAttribPointer(1, ...quad...);
glVertexAttribDivisor(0, 1);            //advance only once per instance
...
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, count);  //draw #count quads

然后在顶点着色器中,将逐点位置与实际的角/四边形位置(也是该顶点的纹理坐标)组合在一起:

代码语言:javascript
运行
复制
uniform mat4 modelview;
uniform mat4 projection;
uniform float spriteSize;

layout(location = 0) in vec4 position;
layout(location = 1) in vec2 corner;

out vec2 texCoord;

void main()
{
    vec4 eyePos = modelview * position;            //transform to eye-space
    eyePos.xy += spriteSize * (corner - vec2(0.5)); //add corner position
    gl_Position = projection * eyePos;             //complete transformation
    texCoord = corner;
}

这实现了与基于几何体着色器的方法相同,正确剪裁的点精灵具有一致的世界空间大小。如果您实际上想要模拟实际点子画面的屏幕空间像素大小,则需要在其中投入更多的计算工作。但这只是一个练习,相当于从点精灵着色器到屏幕转换的最佳选择。

票数 107
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17397724

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档