从零开始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. 结束。

源码下载

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

欢迎大家关注我的公众号【OpenGL编程】,定期分享OpenGL相关的3D编程教程、算法、小项目。欢迎大家一起交流。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值