從零開始Java遊戲引擎[LWJGL](3)-使用VAO和VBO繪製圖形
阿新 • • 發佈:2019-02-10
本節介紹如何使用VAO和VBO進行圖形繪製。
先看效果:
本系列文章關注的重點是遊戲引擎的開發,關於OpenGL的基礎知識,這裡就不再詳細講了,否則篇幅篇幅就太長了。這裡的相關概念我只簡單講下我自己的理解,如果各位不瞭解話,請查閱相關的OpenGL書籍。
VBO:頂點快取物件,其中儲存著頂點的相關資訊(包括:頂點座標、頂點顏色、頂點法線、紋理座標等,這些也就是常說的頂點屬性)。每個VBO只能儲存一個頂點屬性,如:儲存頂點位置的VBO,儲存頂點顏色的VBO…
VAO:頂點陣列物件,內部維護多個頂點屬性列表,而頂點屬性儲存在VBO中,即VAO中儲存著VBO中有關頂點屬性配置的資訊。
程式碼部分:
建立RawModel類,儲存實體資料
建立Loader類,載入實體資料
建立ShaderProgram類,編譯、連結著色器
建立Render類,渲染實體
// RawModel.java
// 主要準備要繪製的實體對應的VAO和頂點數目,用來繪製。VAO中儲存著各頂點屬性的配置。讓opengl可以按照VAO的配置解析傳遞的頂點資料。
package models;
public class RawModel {
private int vaoID;
private int vertexCount;
public RawModel(int vaoID,int vertexCount){
this.vaoID = vaoID;
this.vertexCount = vertexCount;
}
public int getVaoID() {
return vaoID;
}
public void setVaoID(int vaoID) {
this.vaoID = vaoID;
}
public int getVertexCount() {
return vertexCount;
}
}
// Loader.java
// 主要用來載入實體資料到VAO,即主要對實體資料進行相關配置, 最有返回一個RawModel物件,儲存著配置好的VAO用於繪製。
package renderEngine;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
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 models.RawModel;
/**
* 載入VBO
*/
public class Loader {
private List<Integer> vaos = new ArrayList<Integer>();
private List<Integer> vbos = new ArrayList<Integer>();
public RawModel loadToVAO(float[] positions){
int vaoID = createVAO();
//配置vao
storeDataInAttributesList(0, 3,positions);
unbindVAO();
return new RawModel(vaoID, positions.length/3);
}
public void cleanUp(){
for(int vao:vaos){
GL30.glDeleteVertexArrays(vao);
}
for(int vbo:vbos){
GL15.glDeleteBuffers(vbo);
}
}
private int createVAO(){
int vaoID = GL30.glGenVertexArrays();
vaos.add(vaoID);
GL30.glBindVertexArray(vaoID);
return vaoID;
}
private void storeDataInAttributesList(int attributeNumber,int coordinateSize,float[] data){
int vboID = GL15.glGenBuffers();
vbos.add(vboID);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
FloatBuffer buffer = storeDataInFloatBuffer(data);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(attributeNumber, coordinateSize, GL11.GL_FLOAT, false,0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
private void unbindVAO(){
GL30.glBindVertexArray(0);
}
//將int[]轉換為IntBuffer
private IntBuffer storeDataInIntBuffer(int[] data){
IntBuffer buffer = BufferUtils.createIntBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
//將float[]轉換為FloatBuffer
private FloatBuffer storeDataInFloatBuffer(float[]data){
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
}
// Renderer.java
// 根據配置好的VAO進行繪製。
package renderEngine;
import models.RawModel;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
public class Renderer {
public void prepare(){
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
}
public void render(RawModel model){
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getVertexCount());
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
}
// MainGameLoop.java
// 測試程式碼
package engineTester;
import models.RawModel;
import org.lwjgl.opengl.Display;
import renderEngine.DisplayManager;
import renderEngine.Loader;
import renderEngine.Renderer;
public class MainGameLoop {
public static void main(String[] args) {
DisplayManager.createDisplay();
Loader loader = new Loader();
float[] positions = {
-0.5f,0.5f,0.0f,
-0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
0.5f,0.5f,0.0f,
-0.5f,0.5f,0.0f,
};
RawModel model = loader.loadToVAO(positions);
Renderer render = new Renderer();
render.render(model);
while(!Display.isCloseRequested()){
render.prepare();
// game logic
// render
render.render(model);
DisplayManager.updateDisplay();
}
loader.cleanUp();
DisplayManager.closeDisplay();
}
}
ok. 結束。
下篇預告:使用索引快取。