自制Java游戏引擎[LWJGL](3)-使用VAO和VBO绘制图形

本节介绍如何使用VAO和VBO进行图形绘制。

先看效果:

本系列文章关注的重点是游戏引擎的开发,关于OpenGL的基础知识,这里就不再详细讲了,否则篇幅篇幅就太长了。这里的相关概念我只简单讲下我自己的理解,如果各位不了解话,请查阅相关的OpenGL书籍。

VBO:顶点缓存对象,其中存储着顶点的相关信息(包括:顶点坐标、顶点颜色、顶点法线、纹理坐标等,这些也就是常说的顶点属性)。每个VBO只能储存一个顶点属性,如:保存顶点位置的VBO,保存顶点颜色的VBO…

VAO:顶点数组对象,内部维护多个顶点属性列表,而顶点属性存储在VBO中,即VAO中存储着VBO中有关顶点属性配置的信息。

代码部分:

  1. 创建RawModel类,存储实体数据

  2. 创建Loader类,加载实体数据

  3. 创建ShaderProgram类,编译、链接着色器

  4. 创建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. 结束。

源码下载

下篇预告:使用索引缓存。

猜你喜欢

转载自blog.csdn.net/birdflyto206/article/details/81233917