【LWJGL2 WIKI】【现代OpenGL篇】用DrawArrays画方形
来源:互联网 发布:临沂知豆租赁电话 400 编辑:程序博客网 时间:2024/04/30 20:48
原文:http://wiki.lwjgl.org/wiki/The_Quad_with_DrawArrays
Introduction 介绍
随着3.0发布,“弃用”机制被引入。所有被标记为弃用的函数,在未来的版本会被移除。因此开发者应避免使用它们并把已经用到的尽量重构出去。许多辅助类被移除,比如matrix/stack操作和默认光照。但是更重要的是,定义了基元,无需再用glVertex了,取而代之使用顶点数组对象VAO(Vertex Array Object)和顶点缓冲对象VBO(Vertex Buffer Object)。可以用它们来在屏幕上画方形。
“Vertex Array Object” and “Vertex Buffer Object”
一种渲染提速算法是把数据放在GPU里而不是每次都从CPU往GPU发,这就是VAO和VBO做的事情,你将可以使用一定量的显存。
把VAO想象成一个完整的对象定义,它由VBO组成。每个VBO可以保存特殊的定义的数据(混合或交插保存都是可行的),VBO可以用来保存:顶点位置、颜色、法线、纹理坐标……。VAO保存各种各样的VBO在它的属性列表里,默认将在一个VAO里有从0到15共16个属性可用。
设置VAO或者其他对象,都要按下面的规则:
- 请求一个内存空间(返回一个整数,作为对象的ID)
- 用ID绑定对象
- 操作对象(此对象是指OpenGL目前绑定上的对象)
- 用ID解绑对象
如果是VAO,用代码写出来就是:
int vaoId = GL30.glGenVertexArrays();GL30.glBindVertexArray(vaoId);// Do something with itGL30.glBindVertexArray(0);
如果是VBO,用代码写出来就是:
int vboId = GL15.glGenBuffers();GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);// Do something with itGL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
Setting up the quad VBO and VAO 用VBO和VAO设置方形
在把VBO放进VAO的属性列表之前,应该先调用glVertextAttributePointer绑定VAO,此举需要列表ID(默认是从0到15)。在本例中,我们要用VAO和VBO设置一个方形。VBO含有顶点坐标数据,VAO将作为主物体(即方形)定义而活动。
首先需声明顶点,OpenGL以三角形的方式画所有的东西。三角形顶点默认是按逆时针方向描画的。这意味着,既然你要按逆时针顺序指定顶点,需要先定义哪边是前哪边是后。这很有用,OpenGL可以由此在渲染管线中以最优方式剔除那些看不到的面。你可以改掉这种默认的行为,但是那通常是自找麻烦,所以这里我们不再深入讨论。
回到顶点定义,一个方形不是一个三角形而是两个三角形,因此定义方形实际需要的是6个顶点而不是4个(这种低效的方式下次我们再解决):
我们默认的OpenGL坐标系所有轴都是从-1到1,这与我们整个屏幕是相对应的,像这样:
我们会用三个数字定义顶点,每坐标轴一个数字(X, Y, Z)。实际上OpenGL用的是4个数字,(X, Y, Z, W)。先不管W,把它设成1。数字是浮点型,在将它们用在OpenGL方法前,需要在bytebuffer(或者FloatBuffer)里交换它们。
// OpenGL expects vertices to be defined counter clockwise by defaultfloat[] vertices = { // Left bottom triangle -0.5f, 0.5f, 0f, -0.5f, -0.5f, 0f, 0.5f, -0.5f, 0f, // Right top triangle 0.5f, -0.5f, 0f, 0.5f, 0.5f, 0f, -0.5f, 0.5f, 0f};// Sending data to OpenGL requires the usage of (flipped) byte buffersFloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);verticesBuffer.put(vertices);verticesBuffer.flip();vertexCount = 6;
需要记录顶点数目,因此我们需要让OpenGL稍候用glDrawArrays画图时知道有多少个顶点需要画。
现在我们的顶点是可用格式,可以开始定义VAO和VBO了。在VBO里放位置数据,在VAO里把VBO放在属性列表的0位置上。连接VBO和VAO的属性列表很容易(当不需要使用交叉数据的时候)。只需要用glVertextAttribPointer即可,它的参数如下:
- 属性列表序号(在本例中,就是0)
- 一个数据定义里含了几个值(在本例中,3个浮点数算是一个位置数据定义)
- 值的数据类型(在本例中,是浮点数)
- 步进和偏移量(暂时还不需要用,在交叉数据里才用)
用glBufferData将数据放入VBO中,这方法的参数如下:
- 类型(我们用的是GL_ARRAY_BUFFER, 默认就是这个)
- 缓冲区(我们的那个带有顶点数据的FloatBuffer)
- 用途(我们的顶点不动也不变,所以就用简单的GL_STATIC_DRAW)
别忘了解绑我们的对象,因为不需要再操作它们了。综合以上所有步骤,代码如下:
// Create a new Vertex Array Object in memory and select it (bind)// A VAO can have up to 16 attributes (VBO's) assigned to it by defaultvaoId = GL30.glGenVertexArrays();GL30.glBindVertexArray(vaoId);// Create a new Vertex Buffer Object in memory and select it (bind)// A VBO is a collection of Vectors which in this case resemble the location of each vertex.vboId = GL15.glGenBuffers();GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesBuffer, GL15.GL_STATIC_DRAW);// Put the VBO in the attributes list at index 0GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);// Deselect (bind to 0) the VBOGL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);// Deselect (bind to 0) the VAOGL30.glBindVertexArray(0);
vaoID和vboId(还有vertexCount)是全局定义的整数值。
Rendering with glDrawArrays 用glDrawArrays渲染
为了实际画出方形,前面提过,用glDrawArrays方法,它的参数:
- 怎样画顶点(我们用简单的GL_TRIANGLES)
- 第一个序号(我们从头开始,就是0)
- 顶点数目(这值我们存在vertextCount变量里)
OpenGL还必须有VAO(连着VBO的那一个)激活在内存中,因此必须在画前绑定好它们。VBO已经和VAO属性列表0号位连好了,因此只需要启用此列表。当画完后,我们要解绑并禁用一切。渲染代码如下:
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);// Bind to the VAO that has all the information about the quad verticesGL30.glBindVertexArray(vaoId);GL20.glEnableVertexAttribArray(0);// Draw the verticesGL11.glDrawArrays(GL11.GL_TRIANGLES, 0, vertexCount);// Put everything back to default (deselect)GL20.glDisableVertexAttribArray(0);GL30.glBindVertexArray(0);
Cleaning up our memory 清除内存
最后,退出程序之前,需要做内存管理:
// Disable the VBO index from the VAO attributes listGL20.glDisableVertexAttribArray(0);// Delete the VBOGL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);GL15.glDeleteBuffers(vboId);// Delete the VAOGL30.glBindVertexArray(0);GL30.glDeleteVertexArrays(vaoId);
The result 结果
最后画出我们的方形:
Complete source code 完整代码
import java.nio.FloatBuffer;import org.lwjgl.BufferUtils;import org.lwjgl.LWJGLException;import org.lwjgl.opengl.ContextAttribs;import org.lwjgl.opengl.Display;import org.lwjgl.opengl.DisplayMode;import org.lwjgl.opengl.GL11;import org.lwjgl.opengl.GL15;import org.lwjgl.opengl.GL20;import org.lwjgl.opengl.GL30;import org.lwjgl.opengl.PixelFormat;import org.lwjgl.util.glu.GLU;public class TheQuadExampleDrawArrays { // Entry point for the application public static void main(String[] args) { new TheQuadExampleDrawArrays(); } // Setup variables private final String WINDOW_TITLE = "The Quad: glDrawArrays"; private final int WIDTH = 320; private final int HEIGHT = 240; // Quad variables private int vaoId = 0; private int vboId = 0; private int vertexCount = 0; public TheQuadExampleDrawArrays() { // Initialize OpenGL (Display) this.setupOpenGL(); this.setupQuad(); while (!Display.isCloseRequested()) { // Do a single loop (logic/render) this.loopCycle(); // Force a maximum FPS of about 60 Display.sync(60); // Let the CPU synchronize with the GPU if GPU is tagging behind Display.update(); } // Destroy OpenGL (Display) this.destroyOpenGL(); } public void setupOpenGL() { // Setup an OpenGL context with API version 3.2 try { PixelFormat pixelFormat = new PixelFormat(); ContextAttribs contextAtrributes = new ContextAttribs(3, 2) .withForwardCompatible(true) .withProfileCore(true); Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT)); Display.setTitle(WINDOW_TITLE); Display.create(pixelFormat, contextAtrributes); GL11.glViewport(0, 0, WIDTH, HEIGHT); } catch (LWJGLException e) { e.printStackTrace(); System.exit(-1); } // Setup an XNA like background color GL11.glClearColor(0.4f, 0.6f, 0.9f, 0f); // Map the internal OpenGL coordinate system to the entire screen GL11.glViewport(0, 0, WIDTH, HEIGHT); this.exitOnGLError("Error in setupOpenGL"); } public void setupQuad() { // OpenGL expects vertices to be defined counter clockwise by default float[] vertices = { // Left bottom triangle -0.5f, 0.5f, 0f, -0.5f, -0.5f, 0f, 0.5f, -0.5f, 0f, // Right top triangle 0.5f, -0.5f, 0f, 0.5f, 0.5f, 0f, -0.5f, 0.5f, 0f }; // Sending data to OpenGL requires the usage of (flipped) byte buffers FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length); verticesBuffer.put(vertices); verticesBuffer.flip(); vertexCount = 6; // Create a new Vertex Array Object in memory and select it (bind) // A VAO can have up to 16 attributes (VBO's) assigned to it by default vaoId = GL30.glGenVertexArrays(); GL30.glBindVertexArray(vaoId); // Create a new Vertex Buffer Object in memory and select it (bind) // A VBO is a collection of Vectors which in this case resemble the location of each vertex. vboId = GL15.glGenBuffers(); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesBuffer, GL15.GL_STATIC_DRAW); // Put the VBO in the attributes list at index 0 GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0); // Deselect (bind to 0) the VBO GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); // Deselect (bind to 0) the VAO GL30.glBindVertexArray(0); this.exitOnGLError("Error in setupQuad"); } public void loopCycle() { GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); // Bind to the VAO that has all the information about the quad vertices GL30.glBindVertexArray(vaoId); GL20.glEnableVertexAttribArray(0); // Draw the vertices GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, vertexCount); // Put everything back to default (deselect) GL20.glDisableVertexAttribArray(0); GL30.glBindVertexArray(0); this.exitOnGLError("Error in loopCycle"); } public void destroyOpenGL() { // Disable the VBO index from the VAO attributes list GL20.glDisableVertexAttribArray(0); // Delete the VBO GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); GL15.glDeleteBuffers(vboId); // Delete the VAO GL30.glBindVertexArray(0); GL30.glDeleteVertexArrays(vaoId); Display.destroy(); } public void exitOnGLError(String errorMessage) { int errorValue = GL11.glGetError(); if (errorValue != GL11.GL_NO_ERROR) { String errorString = GLU.gluErrorString(errorValue); System.err.println("ERROR - " + errorMessage + ": " + errorString); if (Display.isCreated()) Display.destroy(); System.exit(-1); } }}
Credit
Mathias Verboven (moci)
- 【LWJGL2 WIKI】【现代OpenGL篇】用DrawArrays画方形
- 【LWJGL2 WIKI】【现代OpenGL篇】用DrawElements画方形
- 【LWJGL2 WIKI】【现代OpenGL篇】用纹理画方形
- 【LWJGL2 WIKI】【现代OpenGL篇】画颜色方形
- 【LWJGL2 WIKI】【现代OpenGL篇】交叉数据画方形
- 【LWJGL2 WIKI】【现代OpenGL篇】用BufferSubData更新VBO方形
- 【LWJGL2 WIKI】【现代OpenGL篇】用投影、视图、模型矩阵画方形
- 【LWJGL2 WIKI】【现代OpenGL篇】版本选择
- 【LWJGL2 WIKI】【基础篇】基础3:方形
- 【LWJGL2 WIKI】【基础篇】基础1:显示
- 【LWJGL2 WIKI】【基础篇】基础2:输入
- 【LWJGL2 WIKI】【基础篇】基础4:计时
- 【LWJGL2 WIKI】【基础篇】基础5:全屏
- 【LWJGL2 WIKI】【辅助库篇】Slick-Util库:介绍
- 【LWJGL2 WIKI】翻译文章目录
- 【LWJGL2 WIKI】【辅助库篇】Slick-Util库:第一部分-读取图片
- 【LWJGL2 WIKI】【辅助库篇】Slick-Util库:第二部分-读取声音
- 【LWJGL2 WIKI】【辅助库篇】Slick-Util库:第三部分-读取TrueType字体
- 最新版 CocoaPods 的安装流程
- struck有关与集合有关
- 【机器学习】支持向量机SVM学习(2)
- Android Studio——Message
- 苹果电脑下开启PHP功能
- 【LWJGL2 WIKI】【现代OpenGL篇】用DrawArrays画方形
- hihoCoder 1260 String Problem I
- cf#336-C - Chain Reaction-二分
- go语言学习-程序结构
- 移动web应用开发——Sencha Touch篇(1)
- 第三章 主机规划与磁盘分区
- 电池
- MotionEvent.getX /Y 与 getRamX/Y 区别。
- 剑指offer-合并排序链表