我非常需要帮助。我正在libgdx上进行2D游戏。一切都运作良好,今天我决定制作一个小型的二维粒子系统来制作烟花。我记得我最近在 OpenGL ES 2.0 for Android:快速入门指南一书中使用3d中的着色器完成了这项任务。所以我复制了大部分代码并开始修改一些内容,以便它可以与Libgdx和2d一起使用。这个粒子编辑器的工作原理是有一个大浮点数组,每个粒子可以容纳8个东西:2个位置,x和y; 3种颜色,rgb; 2个方向,x和y; 1开始时间。现在重复阵列中允许的每个粒子。我将最大粒子设置为10,000,因此该阵列中有80,000个浮点数,意味着320,000个字节。无论如何,现在我拥有所有这些属性。现在我将这些属性放入着色器程序中。着色器程序使用它们按方向移动粒子,按时间淡化颜色,并应用重力。所以无论如何,它使用纯OpenGL,但我想使用LibGDX框架。我试图保留尽可能多的旧代码。我认为我所做的会起作用,但它不会显示任何东西。这是代码......
ParticleFirework.java:
public class ParticleFirework {
private final Vector2 position;
private final Vector2 direction;
private final int color;
private final float angleVariance;
private final float speedVariance;
private final Random random = new Random();
private float[] rotationMatrix = new float[16];
private float[] directionVector = new float[4];
private float[] resultVector = new float[4];
public ParticleFirework(Vector2 position, Vector2 direction, int color,
float angleVarianceInDegrees, float speedVariance) {
this.position = position;
this.direction = direction;
this.color = color;
this.angleVariance = angleVarianceInDegrees;
this.speedVariance = speedVariance;
directionVector[0] = direction.x;
directionVector[1] = direction.y;
directionVector[2] = 0;
}
public void addParticles(ParticleSystem particleSystem, float currentTime,
int count) {
for (int i = 0; i < count; i++) {
setRotateEulerM(rotationMatrix, 0, (random.nextFloat() - 0.5f)
* angleVariance, (random.nextFloat() - 0.5f)
* angleVariance, (random.nextFloat() - 0.5f)
* angleVariance);
multiplyMV(resultVector, 0, rotationMatrix, 0, directionVector, 0);
float speedAdjustment = 1f + random.nextFloat() * speedVariance;
Vector2 thisDirection = new Vector2(resultVector[0]
* speedAdjustment, resultVector[1] * speedAdjustment);
particleSystem.addParticle(position, color, thisDirection,
currentTime);
}
}
}
ParticleSystem.java:
public class ParticleSystem {
private static final int PARTICLE_POSITION_COUNT = 2;
private static final int PARTICLE_COLOR_COUNT = 3;
private static final int PARTICLE_DIRECTION_COUNT = 2;
private static final int PARTICLE_START_TIME_COUNT = 1;
private static final int BYTES_IN_A_FLOAT = 4;
private static final int TOTAL_COUNT = PARTICLE_POSITION_COUNT
+ PARTICLE_COLOR_COUNT + PARTICLE_DIRECTION_COUNT
+ PARTICLE_START_TIME_COUNT;
private static final int STRIDE = TOTAL_COUNT * BYTES_IN_A_FLOAT;
private final float[] particles;
private final int maxParticleCount;
private int currentParticleCount;
private int nextParticle;
private FloatBuffer particleFloatBuffer;
public ParticleSystem(int maxParticleCount) {
particles = new float[maxParticleCount * TOTAL_COUNT];
this.maxParticleCount = maxParticleCount;
particleFloatBuffer = ByteBuffer
.allocateDirect(particles.length * BYTES_IN_A_FLOAT)
.order(ByteOrder.nativeOrder()).asFloatBuffer().put(particles);
}
public void addParticle(Vector2 position, int color, Vector2 direction,
float particleStartTime) {
final int particleOffset = nextParticle * TOTAL_COUNT;
int currentOffset = particleOffset;
nextParticle++;
if (currentParticleCount < maxParticleCount) {
currentParticleCount++;
}
if (nextParticle == maxParticleCount) {
nextParticle = 0;
}
particles[currentOffset++] = position.x;
particles[currentOffset++] = position.y;
particles[currentOffset++] = Color.red(color) / 255f;
particles[currentOffset++] = Color.green(color) / 255f;
particles[currentOffset++] = Color.blue(color) / 255f;
particles[currentOffset++] = direction.x;
particles[currentOffset++] = direction.y;
particles[currentOffset++] = particleStartTime;
particleFloatBuffer.position(particleOffset);
particleFloatBuffer.put(particles, particleOffset, TOTAL_COUNT);
particleFloatBuffer.position(0);
}
public void bindData(ShaderProgram particleProgram) {
int dataOffset = 0;
particleProgram.setVertexAttribute("a_Position",
PARTICLE_POSITION_COUNT, GL20.GL_FLOAT, false, STRIDE,
dataOffset);
dataOffset += PARTICLE_POSITION_COUNT;
particleProgram.setVertexAttribute("a_Color",
PARTICLE_COLOR_COUNT, GL20.GL_FLOAT, false, STRIDE,
dataOffset);
dataOffset += PARTICLE_COLOR_COUNT;
particleProgram.setVertexAttribute("a_DirectionVector",
PARTICLE_DIRECTION_COUNT, GL20.GL_FLOAT, false, STRIDE,
dataOffset);
dataOffset += PARTICLE_DIRECTION_COUNT;
particleProgram.setVertexAttribute("a_ParticleStartTime",
PARTICLE_START_TIME_COUNT, GL20.GL_FLOAT, false, STRIDE,
dataOffset);
}
public void draw() {
glDrawArrays(GL_POINTS, 0, currentParticleCount);
}
}
ParticleGame.java:
public class ParticlesGame extends ApplicationAdapter {
SpriteBatch batch;
ShaderProgram particleProgram;
OrthographicCamera camera;
Texture img;
private ParticleSystem particleSystem;
private ParticleFirework firework;
private long globalStartTime;
@Override
public void create() {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
globalStartTime = System.nanoTime();
final Vector2 particleDirection = new Vector2(0f, 0.5f);
final float angleVarianceInDegrees = 5f;
final float speedVariance = 1f;
particleProgram = new ShaderProgram("shaders/particle_shader.vs",
"shaders/particle_shader.fs");
particleSystem = new ParticleSystem(10000);
firework = new ParticleFirework(new Vector2(0f, 0f), particleDirection,
Color.rgb(255, 50, 5), angleVarianceInDegrees, speedVariance);
}
@Override
public void render() {
float currentTime = (System.nanoTime() - globalStartTime) / 1000000000f;
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
firework.addParticles(particleSystem, currentTime, 5);
particleProgram.begin();
FloatBuffer matrixBuffer = ByteBuffer
.allocateDirect(camera.combined.getValues().length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(camera.combined.getValues());
/** Set the uniforms **/
particleProgram.setUniformMatrix4fv("u_matrix", matrixBuffer, 1, false);
particleProgram.setUniform1fv("u_Time", new float[] {currentTime}, 0, 1);
/** Bind data **/
particleSystem.bindData(particleProgram);
particleSystem.draw();
}
}
particle_shader.vs
uniform mat4 u_Matrix;
uniform float u_Time;
attribute vec3 a_Position;
attribute vec3 a_Color;
attribute vec3 a_DirectionVector;
attribute float a_ParticleStartTime;
varying vec3 v_Color;
varying float v_ElapsedTime;
void main()
{
v_Color = a_Color;
v_ElapsedTime = u_Time - a_ParticleStartTime;
float gravityFactor = v_ElapsedTime * v_ElapsedTime / 8.0;
vec3 currentPosition = a_Position + (a_DirectionVector * v_ElapsedTime);
currentPosition.y -= gravityFactor;
gl_Position = u_Matrix * vec4(currentPosition, 1.0);
gl_PointSize = 25.0;
}
我