opengl LWJGL顶点数据似乎已损坏

kdfy810k  于 2022-11-23  发布在  其他
关注(0)|答案(1)|浏览(140)

我尝试渲染一个三角形,看看LWJGL是如何工作的。每一帧,我重置顶点数据ByteBuffer,并直接向其中写入3个顶点。然后我调用buffer.flip(),准备将数据上传到GPU,并调用glBufferData(...),最后调用glDrawArrays(...)。但是没有三角形显示。使用调试程序RenderDoc,我可以查看应该上传的顶点数据,它看起来肯定不正确。

正如您所看到的,每个位置都非常小(就像.后面的41个零)。我没有看到任何错误,即使设置了GLFW错误回调和调试上下文。

所有Java代码:

import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLUtil;

import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class MinimalExample {

    private static void debugPrintErrors() {
        System.out.println("-> DEBUG PRINT ERRORS");
        int error;
        while ((error = GL30.glGetError()) != GL30.GL_NO_ERROR) {
            StringBuilder b = new StringBuilder(" ");
            switch (error) {
                case GL30.GL_INVALID_ENUM                  -> b.append("INVALID_ENUM");
                case GL30.GL_INVALID_VALUE                 -> b.append("INVALID_VALUE");
                case GL30.GL_INVALID_OPERATION             -> b.append("INVALID_OP");
                case GL30.GL_INVALID_FRAMEBUFFER_OPERATION -> b.append("INVALID_FB_OP");
            }

            System.out.println(b);
        }
    }

    private static String readResource(String res) {
        try {
            InputStream is = MinimalExample.class.getResourceAsStream(res);
            String s = new String(is.readAllBytes(), StandardCharsets.UTF_8);
            is.close();
            return s;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    // vertex data buffer
    private static final ByteBuffer buf = ByteBuffer.allocateDirect(4096);

    // shader program
    static int program;

    // render objects
    static int vao;
    static int vbo;

    public static void main(String[] args) {
        // set buffer limit
        buf.limit(4096).position(0);

        // init glfw and create window
        GLFW.glfwInit();
        long window = GLFW.glfwCreateWindow(500, 500, "Hello", 0, 0);

        // create GL
        GLFW.glfwMakeContextCurrent(window);
        GL.createCapabilities();
        GLUtil.setupDebugMessageCallback(System.out);
        GLFW.glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.out));

        // create vertex objects
        vao = GL30.glGenVertexArrays();
        vbo = GL30.glGenBuffers();
        GL30.glBindVertexArray(vao);
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo);
        GL30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 7 * 4, 0);
        GL30.glVertexAttribPointer(1, 4, GL30.GL_FLOAT, false, 7 * 4, 7 * 3);
        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);

        // compile and link shaders
        int vertexShader   = GL30.glCreateShader(GL30.GL_VERTEX_SHADER);
        int fragmentShader = GL30.glCreateShader(GL30.GL_FRAGMENT_SHADER);
        GL30.glShaderSource(vertexShader,   readResource("/test.vsh"));
        GL30.glShaderSource(fragmentShader, readResource("/test.fsh"));
        GL30.glCompileShader(vertexShader);
        GL30.glCompileShader(fragmentShader);
        program = GL30.glCreateProgram();
        GL30.glAttachShader(program, vertexShader);
        GL30.glAttachShader(program, fragmentShader);
        GL30.glLinkProgram(program);

        // render loop
        while (!GLFW.glfwWindowShouldClose(window)) {
            // poll events
            GLFW.glfwPollEvents();

            // clear screen
            GL30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
            GL30.glClear(GL30.GL_COLOR_BUFFER_BIT);

            // render
            render();

            // swap buffers
            GLFW.glfwSwapBuffers(window);
        }
    }

    static void render() {
        // put vertex data
        // manual to simulate graphics library
        putVec3(0.25f, 0.25f, 1f); putVec4(1.0f, 0.0f, 0.0f, 1.0f);
        putVec3(0.75f, 0.25f, 1f); putVec4(0.0f, 1.0f, 0.0f, 1.0f);
        putVec3(0.50f, 0.75f, 1f); putVec4(0.0f, 0.0f, 1.0f, 1.0f);

        buf.flip();

        // bind program
        GL30.glUseProgram(program);

        // bind vertex array
        GL30.glBindVertexArray(vao);
        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);

        // upload graphics data and draw
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo);
        GL30.glBufferData(GL30.GL_ARRAY_BUFFER, buf, GL30.GL_STATIC_DRAW);
        GL30.glDrawArrays(GL30.GL_TRIANGLES, 0, 3);

        // reset vertex data buffer
        buf.position(0);
        buf.limit(buf.capacity());
    }

    //////////////////////////////////////////

    static void putVec3(float x, float y, float z) {
        buf.putFloat(x);
        buf.putFloat(y);
        buf.putFloat(z);
    }

    static void putVec4(float x, float y, float z, float w) {
        buf.putFloat(x);
        buf.putFloat(y);
        buf.putFloat(z);
        buf.putFloat(w);
    }

}

所有着色器代码(为方便起见合并为一个块,实际上是两个文件):

/*
   test.vsh
*/

#version 330 core

in layout(location = 0) vec3 position;
in layout(location = 1) vec4 col;

out layout(location = 0) vec4 fColor;

void main() {
    gl_Position = vec4(position * 1000, 1);
    fColor      = col;
}

/*
   test.fsh
*/

#version 330 core

in layout(location = 0) vec4 fColor;

out vec4 outColor;

void main() {
    outColor = fColor;
}

**编辑:**我知道ByteBuffer的内容是正确的,检查每一帧会产生:

[ 0.25, 0.25, 1.0, 1.0, 0.0, 0.0, 1.0, 0.75, 0.25, 1.0, 0.0, 1.0, 0.0, 1.0, 0.5, 0.75, 1.0, 0.0, 0.0, 1.0, 1.0, ]
rqcrx0a6

rqcrx0a61#

有3个问题。
第一个问题是bufByteBuffer::allocateDirect分配了一个BIG_ENDIAN缓冲区,但OpenGL是一个C库,它是LITTLE_ENDIAN。因此它必须分配BufferUtils::createByteBufferMemoryUtil::memAlloc
第二个问题是glVertexAttribPointer的偏移量。对于3个浮点数,它应该是4 * 3
第三个问题是你的顶点着色器。输入位置被乘以1000,这是在视口之外。为了避免这个问题,你只需要删除乘法或使用投影矩阵。

gl_Position = vec4(position /* * 1000 */, 1);

顺便说一句,我建议使用ByteBuffer::clear来重置顶点数据缓冲区,因为它是一个内置的方法。
修复的Java代码:

import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLUtil;

import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

public class MinimalExample {

    private static void debugPrintErrors() {
        System.out.println("-> DEBUG PRINT ERRORS");
        int error;
        while ((error = GL30.glGetError()) != GL30.GL_NO_ERROR) {
            StringBuilder b = new StringBuilder(" ");
            switch (error) {
                case GL30.GL_INVALID_ENUM                  -> b.append("INVALID_ENUM");
                case GL30.GL_INVALID_VALUE                 -> b.append("INVALID_VALUE");
                case GL30.GL_INVALID_OPERATION             -> b.append("INVALID_OP");
                case GL30.GL_INVALID_FRAMEBUFFER_OPERATION -> b.append("INVALID_FB_OP");
            }

            System.out.println(b);
        }
    }

    private static String readResource(String res) {
        try {
            InputStream is = MinimalExample.class.getResourceAsStream(res);
            String s = new String(is.readAllBytes(), StandardCharsets.UTF_8);
            is.close();
            return s;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    // vertex data buffer
    private static final ByteBuffer buf = BufferUtils.createByteBuffer(4096);

    // shader program
    static int program;

    // render objects
    static int vao;
    static int vbo;

    public static void main(String[] args) {
        // set buffer limit
        buf.limit(4096).position(0);

        // init glfw and create window
        GLFW.glfwInit();
        long window = GLFW.glfwCreateWindow(500, 500, "Hello", 0, 0);

        // create GL
        GLFW.glfwMakeContextCurrent(window);
        GL.createCapabilities();
        GLUtil.setupDebugMessageCallback(System.out);
        GLFW.glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.out));

        // create vertex objects
        vao = GL30.glGenVertexArrays();
        vbo = GL30.glGenBuffers();
        GL30.glBindVertexArray(vao);
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo);
        GL30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 7 * 4, 0);
        GL30.glVertexAttribPointer(1, 4, GL30.GL_FLOAT, false, 7 * 4, 4 * 3);
        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);

        // compile and link shaders
        int vertexShader   = GL30.glCreateShader(GL30.GL_VERTEX_SHADER);
        int fragmentShader = GL30.glCreateShader(GL30.GL_FRAGMENT_SHADER);
        GL30.glShaderSource(vertexShader,   readResource("/test.vsh"));
        GL30.glShaderSource(fragmentShader, readResource("/test.fsh"));
        GL30.glCompileShader(vertexShader);
        GL30.glCompileShader(fragmentShader);
        program = GL30.glCreateProgram();
        GL30.glAttachShader(program, vertexShader);
        GL30.glAttachShader(program, fragmentShader);
        GL30.glLinkProgram(program);

        // render loop
        while (!GLFW.glfwWindowShouldClose(window)) {
            // poll events
            GLFW.glfwPollEvents();

            // clear screen
            GL30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
            GL30.glClear(GL30.GL_COLOR_BUFFER_BIT);

            // render
            render();

            // swap buffers
            GLFW.glfwSwapBuffers(window);
        }
    }

    static void render() {
        // put vertex data
        // manual to simulate graphics library
        putVec3(0.25f, 0.25f, 1f); putVec4(1.0f, 0.0f, 0.0f, 1.0f);
        putVec3(0.75f, 0.25f, 1f); putVec4(0.0f, 1.0f, 0.0f, 1.0f);
        putVec3(0.50f, 0.75f, 1f); putVec4(0.0f, 0.0f, 1.0f, 1.0f);

        buf.flip();

        // bind program
        GL30.glUseProgram(program);

        // bind vertex array
        GL30.glBindVertexArray(vao);
        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);

        // upload graphics data and draw
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo);
        GL30.glBufferData(GL30.GL_ARRAY_BUFFER, buf, GL30.GL_STATIC_DRAW);
        GL30.glDrawArrays(GL30.GL_TRIANGLES, 0, 3);

        // reset vertex data buffer
        buf.clear();
    }

    //////////////////////////////////////////

    static void putVec3(float x, float y, float z) {
        buf.putFloat(x);
        buf.putFloat(y);
        buf.putFloat(z);
    }

    static void putVec4(float x, float y, float z, float w) {
        buf.putFloat(x);
        buf.putFloat(y);
        buf.putFloat(z);
        buf.putFloat(w);
    }

}

相关问题