【发布时间】:2020-03-30 16:17:19
【问题描述】:
有一个爆炸的粒子系统,类似于烟花:
顶点着色器代码:
#version 300 es
uniform float u_lastTimeExplosion; // time elapsed since the explosion
// explosion center (particle coordinates are set relative to this center
uniform vec3 u_centerPosition;
uniform float u_sizeSprite;
// particle lifetime in seconds
layout(location = 0) in float a_lifeTime;
// initial position of the particle at the time of the explosion
layout(location = 1) in vec3 a_startPosition;
layout(location = 2) in vec3 a_endPosition; // final position of the particle
out float v_lifeTime; // remaining particle lifetime
void main()
{
// calculate particle position (algorithm from the book of D.Ginsburg, B.Purnomo)
gl_Position.xyz = a_startPosition + (u_lastTimeExplosion * a_endPosition);
gl_Position.xyz += u_centerPosition;
gl_Position.w = 1.0;
// calculate the remaining particle lifetime
v_lifeTime = 1.0 - (u_lastTimeExplosion / a_lifeTime);
v_lifeTime = clamp(v_lifeTime, 0.0, 1.0);
// calculate sprite size based on remaining life time
gl_PointSize = pow(v_lifeTime, 5.0) * u_sizeSprite;
}
片段着色器代码:
#version 300 es
precision lowp float;
in float v_lifeTime;
uniform vec4 u_color;
out vec4 fragColor;
uniform sampler2D s_texture;
void main()
{
vec4 texColor = texture(s_texture, gl_PointCoord);
fragColor = u_color * texColor;
// increase sprite transparency
fragColor.a *= v_lifeTime;
}
使用了三个顶点缓冲区:用于具有粒子生命周期的数组;粒子的初始坐标数组;最终粒子坐标数组:
lifeTimeAsFloatBuffer.position(0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,
FLOAT_SIZE * numberParticles, lifeTimeAsFloatBuffer,
GLES30.GL_STATIC_DRAW);
startPositionAsFloatBuffer.position(0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[1]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,
FLOAT_SIZE * NUM_COORDINATES * numberParticles,
startPositionAsFloatBuffer, GLES30.GL_STATIC_DRAW);
endPositionAsFloatBuffer.position(0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[2]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,
FLOAT_SIZE * NUM_COORDINATES * numberParticles,
endPositionAsFloatBuffer, GLES30.GL_STATIC_DRAW);
生成顶点数据:
private final float[] lifeTimeData; // life time of particles
private final float[] startPositionData; // start coordinates of particles
private final float[] endPositionData; // end coordinates of particles
...
public void createDataVertex() {
float maxLifeTime = 3.0f;
for (int i = 0; i < numberParticles; i ++) {
// life time of particle, random value 0-3 second
lifeTimeData[i] = random.nextFloat() * maxLifeTime;
}
float[] xyz;
for (int i = 0; i < numberParticles * NUM_COORDINATES; i += NUM_COORDINATES) {
xyz = getPointForSphere(startRadius); // start position particle
startPositionData[i] = xyz[0] * aspect;
startPositionData[i + 1] = xyz[1];
startPositionData[i + 2] = xyz[2];
xyz = getPointForSphere(endRadius); // end position particle
endPositionData[i] = xyz[0] * aspect;
endPositionData[i + 1] = xyz[1];
endPositionData[i + 2] = xyz[2];
}
lifeTimeAsFloatBuffer = floatBuffer(lifeTimeData);
startPositionAsFloatBuffer = floatBuffer(startPositionData);
endPositionAsFloatBuffer = floatBuffer(endPositionData);
}
将数据传递给着色器:
public void onDrawFrame(GL10 glUnused) {
...
GLES30.glEnableVertexAttribArray(startPositionLink);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[1]);
GLES30.glVertexAttribPointer(startPositionLink, NUM_COORDINATES,
GLES30.GL_FLOAT, false, FLOAT_SIZE * NUM_COORDINATES, 0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
...
}
问题:在某些物理设备上渲染速度变慢(FPS 降低)。哪怕有几百个粒子。看了一个帖子:Improve Particle system OpenGL。 但这里的问题似乎有所不同。
问题:有没有办法进一步优化这个粒子系统?任何答案/评论都会非常有价值。
【问题讨论】:
-
那么,只有几百个粒子会导致减速?似乎令人惊讶,因为它相对微不足道。你能确认你是在一个draw call中发出它们吗?另外,您的纹理是否合理(即它要么很小,要么很大但有 mipmap)?
-
@Columbo 你好!谢谢!最有可能的是,所有这些都在一次绘制调用中 - 为问题添加了示例。纹理 - 黑色背景上的绿色圆圈,文件 *.png,4 KB。未使用 Mipmap。如果我需要使用mipmap,请写下你的答案,我会标记为正确答案。
-
@Columbo 也可以使用 VAO 吗?
-
@Columbo 减速通常发生在一次有几个爆炸时。
-
纹理的分辨率比 png 的文件大小更重要。如果纹理很大(例如 1024x1024),Mipmapping 可能会有很大帮助,如果纹理很小(例如 32x32),则可能没有区别。无论如何我都会打开它。
标签: java android opengl-es-3.0