You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用LWJGL 3时OpenGL三角形无法渲染的问题排查

LWJGL 3 + OpenGL 3.3 三角形无法渲染的问题排查

使用LWJGL 3开发OpenGL 3.3程序时,编写的三角形无法显示。尝试将顶点着色器和片段着色器设为完全相同并移除链接错误检查后,三角形能显示为白色,但正常情况下无渲染结果。以下是完整代码:

package com.xicreations.infinimob;

import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryStack;

import java.nio.IntBuffer;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.NULL;

public class Infinimob 
{
    private final int WIDTH = 800, HEIGHT = 800;
    private final String TITLE = "Infinimob 0.0.1a";
    
    private static String vs = "#version 330 core\n" + 
    "layout (location = 0) in vec3 aPos;\n" + 
    "void main()\n" +
    "{\n" + 
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + 
    "}\0";
    
    private static String fs = "#version 330 core\n" + 
            "out vec4 fragColor;\n" + 
            "void main()\n" +
            "{\n" + 
            "   fragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n" + 
            "}\0";
    
    private long window;
    private int vao, vbo;
    private int vertexCount = 3;
    
    private void init()
    {
        if (!glfwInit()) 
        {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

        window = glfwCreateWindow(WIDTH, HEIGHT, TITLE, NULL, NULL);
        if (window == NULL) 
        {
            throw new RuntimeException("Failed to create the GLFW window");
        }

        try (MemoryStack stack = stackPush()) 
        {
            IntBuffer pWidth = stack.mallocInt(1);
            IntBuffer pHeight = stack.mallocInt(1);

            glfwGetWindowSize(window, pWidth, pHeight);

            GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            glfwSetWindowPos(
                    window,
                    (vidMode.width() - pWidth.get(0)) / 2,
                    (vidMode.height() - pHeight.get(0)) / 2
            );
        }

        glfwMakeContextCurrent(window);
        glfwSwapInterval(1);
        glfwShowWindow(window);
    }
    
    private int loadShader(String shaderSource, int shaderType) 
    {
        int shader = glCreateShader(shaderType);
        glShaderSource(shader, shaderSource);
        glCompileShader(shader);
        if (glGetShaderi(shader, GL_COMPILE_STATUS) == GL_FALSE) {
            throw new RuntimeException("Failed to compile shader: " + glGetShaderInfoLog(shader));
        }
        return shader;
    }

    private void initShaders() 
    {
        int vertexShader = loadShader(vs, GL_VERTEX_SHADER);
        int fragmentShader = loadShader(fs, GL_FRAGMENT_SHADER);

        int shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, fragmentShader);
        glAttachShader(shaderProgram, vertexShader);
        glLinkProgram(shaderProgram);
        if (glGetProgrami(shaderProgram, GL_LINK_STATUS) == GL_FALSE) {
            throw new RuntimeException("Failed to link shader program: " + glGetProgramInfoLog(shaderProgram));
        }
        glUseProgram(shaderProgram);
    }
    
    private void loop() 
    {
        GL.createCapabilities();
        initShaders();

        float[] vertices = 
        {
                -0.5f, -0.5f, 0.0f,
                0.5f, -0.5f, 0.0f,
                0.0f, 0.5f, 0.0f
        };

        vao = glGenVertexArrays();
        vbo = glGenBuffers();

        glBindVertexArray(vao);

        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * Float.BYTES, 0);
        glEnableVertexAttribArray(0);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);

        glViewport(0, 0, WIDTH, HEIGHT);
        
        while (!glfwWindowShouldClose(window)) 
        {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            
            glUseProgram(0);
            glBindVertexArray(vao);
            glDrawArrays(GL_TRIANGLES, 0, vertexCount);
            glBindVertexArray(0);

            glfwSwapBuffers(window);

            glfwPollEvents();
        }
    }

    private void cleanup() 
    {
        glDeleteBuffers(vbo);
        glDeleteVertexArrays(vao);
        glfwTerminate();
    }
    
    public static void main(String[] args) 
    {
        Infinimob app = new Infinimob();
        app.init();
        app.loop();
        app.cleanup();
    }
}

问题分析与修复

1. 渲染时未启用正确的着色器程序

在loop方法的渲染循环中,调用了glUseProgram(0),直接禁用了所有着色器程序。同时你创建的shaderProgram是initShaders方法的局部变量,仅在初始化时短暂启用,循环中无法复用,导致渲染时没有使用自定义着色器。

修复:

  • 将shaderProgram改为类的成员变量,确保全局可访问;
  • 渲染循环中调用glUseProgram(shaderProgram)启用自定义着色器。

2. 着色器源代码末尾的多余\0

顶点着色器和片段着色器的源代码末尾都添加了\0,但LWJGL的glShaderSource会自动处理字符串终止符,多余的\0会导致着色器解析异常,进而编译失败。

修复:
移除着色器字符串末尾的\0,示例:

private static String vs = "#version 330 core\n" + 
"layout (location = 0) in vec3 aPos;\n" + 
"void main()\n" +
"{\n" + 
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + 
"}";

private static String fs = "#version 330 core\n" + 
        "out vec4 fragColor;\n" + 
        "void main()\n" +
        "{\n" + 
        "   fragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n" + 
        "}";

修正后的关键代码片段

修改类成员变量与initShaders方法

private int shaderProgram; // 新增全局着色器程序变量

private void initShaders() 
{
    int vertexShader = loadShader(vs, GL_VERTEX_SHADER);
    int fragmentShader = loadShader(fs, GL_FRAGMENT_SHADER);

    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, fragmentShader);
    glAttachShader(shaderProgram, vertexShader);
    glLinkProgram(shaderProgram);
    if (glGetProgrami(shaderProgram, GL_LINK_STATUS) == GL_FALSE) {
        throw new RuntimeException("Failed to link shader program: " + glGetProgramInfoLog(shaderProgram));
    }
}

修改渲染循环

while (!glfwWindowShouldClose(window)) 
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    glUseProgram(shaderProgram); // 启用自定义着色器
    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, vertexCount);
    glBindVertexArray(0);
    glUseProgram(0); // 可选:渲染完成后关闭着色器

    glfwSwapBuffers(window);
    glfwPollEvents();
}

额外建议

保留着色器编译和链接的错误检查逻辑,这是定位问题的关键——之前移除检查后能显示白色三角形,本质是OpenGL在着色器编译失败时自动切换到了默认固定功能管线,并非你的代码逻辑正确。

内容的提问来源于stack exchange,提问作者XICreations

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:35:57