OpenGL開發(一)利用lwjgl類庫繪製一個三角形
阿新 • • 發佈:2018-12-17
在繪製三角形之前,需要建立一個OpenGL上下文(Context)和一個用於顯示的視窗。然而,這些操作在每個系統上都是不一樣的,OpenGL將這部分抽離了出去。
GLFW
GLFW是一個專門針對OpenGL的C語言庫,它提供了一些渲染物體所需的最低限度的介面。它允許使用者建立OpenGL上下文,定義視窗引數以及處理使用者輸入。
一、只繪製渲染視窗的程式碼如下
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
import static org.lwjgl.system.MemoryUtil.NULL;
public class Demo01_open_window {
public static void main(String[] args){
glfwInit();//初始化
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);//設定視窗的可見性為false
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);//設定視窗是否可以重新調整大小
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//OpenGL的主版本號
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);//OpenGL的副版本號
int width = 500;//視窗寬度
int height = 300;//視窗高度
long window = glfwCreateWindow(width, height, "Hello World!", NULL, NULL);//建立一個視窗,返回值是個long值。
glfwMakeContextCurrent(window);//通知GLFW將window的上下文設定為當前執行緒的主上下文
glfwShowWindow(window);//展示當前的視窗
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());//獲取當前裝置的一些屬性
glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);//設定視窗的位置在最中間
GL.createCapabilities();//建立opengl上下文
//不間斷的一直渲染視窗,如果沒有這步迴圈,視窗會一閃而過。
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除之前渲染的快取
glfwSwapBuffers(window); // 交換前後緩衝區
glfwPollEvents();//檢查是否有鍵盤或是滑鼠事件
}
glfwTerminate();//釋放之前分配的所有資源。
}
}
上面程式碼中的相關說明
- 如果不在一開始就呼叫
glfwInit();
函式,則後面的函式將都會失效。 - OpenGL的主版本號在繪製圖形時,一定要設定。
雙緩衝(Double Buffer)
:應用程式使用單緩衝繪圖時可能會存在影象閃爍的問題。 這是因為生成的影象不是一下子被繪製出來的,而是按照從左到右,由上而下逐畫素地繪製而成的。最終影象不是在瞬間顯示給使用者,而是通過一步一步生成的,這會導致渲染的結果很不真實。為了規避這些問題,我們應用雙緩衝渲染視窗應用程式。前緩衝儲存著最終輸出的影象,它會在螢幕上顯示;而所有的的渲染指令都會在後緩衝上繪製。當所有的渲染指令執行完畢後,我們glfwSwapBuffers()
函式就是用來交換(Swap)前緩衝和後緩衝的,這樣影象就立即呈顯出來,之前提到的不真實感就消除了。
在視窗上繪製三角形
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryUtil;
import java.nio.FloatBuffer;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import static org.lwjgl.system.MemoryUtil.NULL;
public class Demo02_draw_triangle {
public static void main(String[] args) throws Exception {
glfwInit();
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//OpenGL的主版本號
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);//OpenGL的副版本號
int width = 600;
int height = 400;
long window = glfwCreateWindow(width, height, "Hello World!", NULL, NULL);
glfwMakeContextCurrent(window);
glfwShowWindow(window);
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
GL.createCapabilities();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//一下的程式碼是繪製三角形的程式碼
int programId = 0;//宣告一個著色器程式ID
try {
//建立著色器程式
programId = glCreateProgram();
//建立並初始化頂點著色器
int vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderId, Utils.loadResource("/shader/demo02_vertex.vs"));
glCompileShader(vertexShaderId);
glAttachShader(programId, vertexShaderId);
//建立並初始化片元著色器
int fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShaderId, Utils.loadResource("/shader/demo02_fragment.fs"));
glCompileShader(fragmentShaderId);
glAttachShader(programId, fragmentShaderId);
glLinkProgram(programId);
//glValidateProgram(programId);
} catch (Exception e) {
e.printStackTrace();
}
int vaoId;
int vboId;
float[] vertices = new float[]{
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
FloatBuffer verticesBuffer = null;
try {
verticesBuffer = MemoryUtil.memAllocFloat(vertices.length);
verticesBuffer.put(vertices).flip();
// Create the VAO and bind to it
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
// Create the VBO and bint to it
vboId = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
// Define structure of the data
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
// Unbind the VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Unbind the VAO
glBindVertexArray(0);
} finally {
if (verticesBuffer != null) {
MemoryUtil.memFree(verticesBuffer);
}
}
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//呼叫著色器程式
glUseProgram(programId);
// Bind to the VAO
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
// Draw the vertices
glDrawArrays(GL_TRIANGLES, 0, 3);
// Restore state
glDisableVertexAttribArray(0);
glBindVertexArray(0);
glUseProgram(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
}
}