1. 程式人生 > >OpenGL開發(一)利用lwjgl類庫繪製一個三角形

OpenGL開發(一)利用lwjgl類庫繪製一個三角形

在繪製三角形之前,需要建立一個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();

        }
    }

}