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();//释放之前分配的所有资源。
    }

}

运行结果:
OpenGL开发(一)利用lwjgl类库绘制一个三角形

上面代码中的相关说明

  • 如果不在一开始就调用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();

        }
    }

}

顶点着色器程序

#version 330

layout (location =0) in vec3 position;

void main()
{
	gl_Position = vec4(position, 1.0);
}

片段着色器程序

#version 330

out vec4 fragColor;

void main()
{
	fragColor = vec4(0.0, 0.5, 0.5, 1.0);
}

运行结果:

OpenGL开发(一)利用lwjgl类库绘制一个三角形