我尝试使用VBO和着色器在现代OpenGL中渲染2048个四边形。但表现太可怕了。通过使用以下代码,我只有大约50 FPS。我想,我每一帧都会调用一些东西,这会减慢应用程序的速度,但我不知道它是什么。
另外我认为,如果仅更改了对象的位置,那么将每个帧的位置,视图和投影矩阵发送到着色器的速度非常慢。
如何才能更快地获取此代码?
型号代码:
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Arrays;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
public abstract class Model
{
private TexturedVertex[] vertices;
private byte[] indices;
private FloatBuffer verticesBuffer;
private ByteBuffer indicesBuffer;
private Vector3f position;
private Vector3f angle;
private Vector3f scale;
int shaderProgram;
int indicesCount;
private int projectionMatrixLocation;
private int viewMatrixLocation;
private int modelMatrixLocation;
int vaoID;
int vboID;
int vboiID;
public void load (TexturedVertex[] vertices, byte[] indices, Shader shader)
{
this.position = new Vector3f(0, 0, -1);
this.angle = new Vector3f(0, 0, 0);
this.scale = new Vector3f(1, 1, 1);
this.vertices = vertices;
this.indices = indices;
this.shaderProgram = shader.getProgramID();
this.generateBuffer();
this.generateArrayBufferObjects();
this.configureShader();
}
private void generateBuffer()
{
// === Vertices Buffer === //
this.verticesBuffer = BufferUtils.createFloatBuffer(vertices.length * TexturedVertex.elementCount);
for (int i = 0; i < vertices.length; i++)
{
verticesBuffer.put(vertices[i].getElements());
System.out.print ("XYZW: " + Arrays.toString(vertices[i].getXYZW()));
System.out.print (" RGBA: " + Arrays.toString(vertices[i].getRGBA()));
System.out.println (" ST: " + Arrays.toString(vertices[i].getST()));
}
verticesBuffer.flip();
// === Generate Indices Buffer === //
this.indicesCount = indices.length;
this.indicesBuffer = BufferUtils.createByteBuffer(indicesCount);
indicesBuffer.put(indices);
indicesBuffer.flip();
}
private void generateArrayBufferObjects()
{
// === Generate VAO & VBO === //
this.vaoID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoID);
this.vboID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesBuffer, GL15.GL_STATIC_DRAW);
this.vboiID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboiID);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL15.GL_STATIC_DRAW);
System.out.println ();
System.out.println ("VAO-ID: #" + vaoID);
System.out.println ("VBO-ID: #" + vboID);
System.out.println ("VBOI-ID: #" + vboiID);
// === Put informations to shader === //
GL20.glVertexAttribPointer(0, TexturedVertex.positionElementCount, GL11.GL_FLOAT, false, TexturedVertex.stride, TexturedVertex.positionByteOffset);
GL20.glVertexAttribPointer(1, TexturedVertex.colorElementCount, GL11.GL_FLOAT, false, TexturedVertex.stride, TexturedVertex.colorByteOffset);
GL20.glVertexAttribPointer(2, TexturedVertex.textureElementCount, GL11.GL_FLOAT, false, TexturedVertex.stride, TexturedVertex.textureByteOffset);
// === Unbind Buffers === //
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
}
private void configureShader()
{
// === Bind shader === //
GL20.glUseProgram(shaderProgram);
// === Get matrix location === //
this.projectionMatrixLocation = GL20.glGetUniformLocation(shaderProgram, "projectionMatrix");
this.viewMatrixLocation = GL20.glGetUniformLocation(shaderProgram, "viewMatrix");
this.modelMatrixLocation = GL20.glGetUniformLocation(shaderProgram, "modelMatrix");
// === Update the matrix === //
this.updateMatrix();
// === Unbind shader === //
GL20.glUseProgram(0);
}
void updateMatrix()
{
// === Bind shader === //
GL20.glUseProgram(shaderProgram);
// === Load matrix === //
Matrix4f projectionMatrix = GameManager.camera.getProjectionMatrix();
Matrix4f viewMatrix = GameManager.camera.getViewMatrix();
Matrix4f modelMatrix = new Matrix4f();
// === Scale, translate and rotate matrix === //
Matrix4f.scale(scale, modelMatrix, modelMatrix);
Matrix4f.translate(position, modelMatrix, modelMatrix);
Matrix4f.rotate(Util.degreesToRadians(angle.z), new Vector3f(0, 0, 1), modelMatrix, modelMatrix);
Matrix4f.rotate(Util.degreesToRadians(angle.y), new Vector3f(0, 1, 0), modelMatrix, modelMatrix);
Matrix4f.rotate(Util.degreesToRadians(angle.x), new Vector3f(1, 0, 0), modelMatrix, modelMatrix);
// === Apply uniform matrix to shader === //
FloatBuffer matrixBuffer = BufferUtils.createFloatBuffer(16);
projectionMatrix.store(matrixBuffer);
matrixBuffer.flip();
GL20.glUniformMatrix4(projectionMatrixLocation, false, matrixBuffer);
viewMatrix.store(matrixBuffer);
matrixBuffer.flip();
GL20.glUniformMatrix4(viewMatrixLocation, false, matrixBuffer);
modelMatrix.store(matrixBuffer);
matrixBuffer.flip();
GL20.glUniformMatrix4(modelMatrixLocation, false, matrixBuffer);
// === Unbind shader === //
GL20.glUseProgram(0);
}
public void setPosition (Vector3f newPosition)
{
this.position = newPosition;
this.updateMatrix();
}
public void setAngle (Vector3f newAngle)
{
this.angle = newAngle;
this.updateMatrix();
}
public void setScale (Vector3f newAngle)
{
this.scale = newAngle;
this.updateMatrix();
}
}
呈现代码:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.util.vector.Vector3f;
import de.matthiasmann.twl.utils.PNGDecoder;
import de.matthiasmann.twl.utils.PNGDecoder.Format;
public class GameManager
{
private Logger logger;
private Profiler profiler;
private Window window;
public static Camera camera;
public GameManager()
{
init();
ModelChest[] chests = new ModelChest[2048];
for (int i = 0; i < 2048; i++)
{
chests[i] = new ModelChest();
}
ModelChest chest = new ModelChest();
ModelChest chestB = new ModelChest();
int textureID = loadPNGTexture ("Getigerte-Katze-Baby-Decke.png", GL13.GL_TEXTURE0);
while (!window.isCloseRequested())
{
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
{
chest.setPosition(new Vector3f(1, 0, -0.5F));
GL20.glUseProgram(chest.shaderProgram);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL30.glBindVertexArray(chest.vaoID);
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, chest.vboiID);
{
GL11.glDrawElements(GL11.GL_TRIANGLES, chest.indicesCount, GL11.GL_UNSIGNED_BYTE, 0);
}
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL20.glDisableVertexAttribArray(2);
GL30.glBindVertexArray(0);
//GL20.glUseProgram(0);
for (float i = 0; i < 2048; i++)
{
chests[(int)i].setPosition(new Vector3f(-1F + ((float)i / 30F), 0, -0.5F));
GL20.glUseProgram(chests[(int)i].shaderProgram);
GL30.glBindVertexArray(chests[(int)i].vaoID);
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, chests[(int)i].vboiID);
{
GL11.glDrawElements(GL11.GL_TRIANGLE_STRIP , chests[(int)i].indicesCount, GL11.GL_UNSIGNED_BYTE, 0);
}
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL20.glDisableVertexAttribArray(2);
GL30.glBindVertexArray(0);
GL20.glUseProgram(0);
}
}
Display.update();
}
destroy();
}
public void init()
{
logger = new Logger();
logger.init();
profiler = new Profiler();
profiler.init();
window = new Window();
window.init();
camera = new Camera();
camera.init();
}
public void destroy()
{
logger.destroy();
profiler.destroy();
window.destroy();
camera.destroy();
System.exit(0);
}
private int loadPNGTexture(String filename, int textureUnit) {
ByteBuffer buf = null;
int tWidth = 0;
int tHeight = 0;
try {
// Open the PNG file as an InputStream
InputStream in = new FileInputStream(filename);
// Link the PNG decoder to this stream
PNGDecoder decoder = new PNGDecoder(in);
// Get the width and height of the texture
tWidth = decoder.getWidth();
tHeight = decoder.getHeight();
// Decode the PNG file in a ByteBuffer
buf = ByteBuffer.allocateDirect(
4 * decoder.getWidth() * decoder.getHeight());
decoder.decode(buf, decoder.getWidth() * 4, Format.RGBA);
buf.flip();
in.close();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
// Create a new texture object in memory and bind it
int texId = GL11.glGenTextures();
GL13.glActiveTexture(textureUnit);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
// All RGB bytes are aligned to each other and each component is 1 byte
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
// Upload the texture data and generate mip maps (for scaling)
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, tWidth, tHeight, 0,
GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
// Setup the ST coordinate system
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
// Setup what to do when the texture has to be scaled
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
GL11.GL_LINEAR_MIPMAP_LINEAR);
return texId;
}
}
照相机:
import org.lwjgl.opengl.Display;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
public class Camera extends Worker
{
private Matrix4f projectionMatrix;
private Matrix4f viewMatrix;
private Vector3f position;
private Vector3f angle;
private float fieldOfView;
private float aspectRatio;
private float nearPlane;
private float farPlane;
private float xScale;
private float yScale;
private float frustumLength;
@Override
protected void onInitialize()
{
// Apply default settings
this.fieldOfView = 60f;
this.aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
this.nearPlane = 0.1f;
this.farPlane = 100f;
this.position = new Vector3f(0, 0, -1);
this.angle = new Vector3f(0, 0, 0);
// Calculate scale and furstum length
this.yScale = Util.coTangent(Util.degreesToRadians(fieldOfView / 2f));
this.xScale = yScale / aspectRatio;
this.frustumLength = farPlane - nearPlane;
// Projection Matrix
projectionMatrix = new Matrix4f();
projectionMatrix.m00 = xScale;
projectionMatrix.m11 = yScale;
projectionMatrix.m22 = -((farPlane + nearPlane) / frustumLength);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * nearPlane * farPlane) / frustumLength);
projectionMatrix.m33 = 0;
// View Matrix
viewMatrix = new Matrix4f();
Matrix4f.translate(position, viewMatrix, viewMatrix);
Matrix4f.rotate(Util.degreesToRadians(angle.z), new Vector3f(0, 0, 1),
viewMatrix, viewMatrix);
Matrix4f.rotate(Util.degreesToRadians(angle.y), new Vector3f(0, 1, 0),
viewMatrix, viewMatrix);
Matrix4f.rotate(Util.degreesToRadians(angle.x), new Vector3f(1, 0, 0),
viewMatrix, viewMatrix);
}
public Matrix4f getProjectionMatrix()
{
return this.projectionMatrix;
}
public Matrix4f getViewMatrix()
{
return this.viewMatrix;
}
public void setPosition (Vector3f newPosition)
{
Matrix4f.translate(newPosition, viewMatrix, viewMatrix);
}
public void setPosition (float x, float y, float z)
{
setPosition(new Vector3f (x, y, z));
}
public void setAngle (Vector3f newAngle)
{
Matrix4f.rotate(Util.degreesToRadians(newAngle.z), new Vector3f(0, 0, 1),
viewMatrix, viewMatrix);
Matrix4f.rotate(Util.degreesToRadians(newAngle.y), new Vector3f(0, 1, 0),
viewMatrix, viewMatrix);
Matrix4f.rotate(Util.degreesToRadians(newAngle.x), new Vector3f(1, 0, 0),
viewMatrix, viewMatrix);
}
public void setAngle (float x, float y, float z)
{
setAngle(new Vector3f (x, y, z));
}
@Override
protected void onDestroy()
{
;
}
@Override
protected void onTick()
{
;
}
}
着色器:
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec4 in_Position;
in vec4 in_Color;
in vec2 in_TextureCoord;
out vec4 pass_Color;
out vec2 pass_TextureCoord;
void main(void) {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_Position;
pass_Color = in_Color;
pass_TextureCoord = in_TextureCoord;
}