GLSL 着色器未编译,没有错误消息

Posted

技术标签:

【中文标题】GLSL 着色器未编译,没有错误消息【英文标题】:GLSL Shader not Compiling, no Error Message 【发布时间】:2015-02-11 22:17:03 【问题描述】:

我正在尝试使用我从 LWJGL 编写的 GLSL 着色器。它只是一个简单的基于片段的 phong 着色器。着色器过去运行良好,即使在这台计算机上也是如此。前几天,突然间,它无缘无故地停止了编译。当我尝试编译它并检查信息日志时,我收到以下消息:

Exception in thread "Thread-1" org.lwjgl.opengl.OpenGLException: Invalid value (1281)
    at org.lwjgl.opengl.Util.checkGLError(Util.java:59)
    at org.lwjgl.opengl.GL20.glGetShaderi(GL20.java:542)
    at aspect.render.shader.ShaderProgram.getLogInfo(ShaderProgram.java:161)
    at aspect.render.shader.ShaderProgram.<init>(ShaderProgram.java:69)
    at aspect.render.shader.ShaderProgram.loadPrebuilt(ShaderProgram.java:168)
    at aspect.core.AspectLauncher$1.run(AspectLauncher.java:143)

我的 OpenGL 信息:

GL VENDOR: Intel
GL RENDERER: Intel(R) HD Graphics 3000
GL VERSION: 3.1.0 - Build 9.17.10.3347
GLSL VERSION: 1.40 - Intel Build 9.17.10.3347

这是着色器本身:

顶点:

#version 140

uniform int numLights;
uniform bool useLighting;

varying vec3 normal;
varying vec3 ambient;
varying vec3 color;

varying vec3 diffuse[8];
varying vec3 lightDir[8];
varying vec3 dist[8];

varying vec2 texCoord;

void main()  
    vec4 position = gl_ModelViewMatrix * gl_Vertex;
    gl_Position = gl_ProjectionMatrix * position;
    normal = normalize(gl_NormalMatrix * gl_Normal);
    texCoord = gl_MultiTexCoord0.st;
    color = gl_Color.rgb;

    ambient = gl_FrontMaterial.emission.rgb + gl_LightModel.ambient.rgb * gl_FrontMaterial.ambient.rgb;

    if (useLighting) 
        for (int i = 0; i < numLights; i++) 

            float diffuseIntensity;

            if (gl_LightSource[i].position.w != 0.0) 
                vec3 toLight = (gl_LightSource[i].position - position).xyz;

                dist[i] = toLight;
                lightDir[i] = normalize(toLight);

                diffuseIntensity = dot(normalize(toLight), normal);
             else 
                lightDir[i] = normalize(gl_LightSource[i].position.xyz);

                diffuseIntensity = dot(normalize(gl_LightSource[i].position.xyz), normal);
            

            diffuseIntensity = max(diffuseIntensity, 0.0);

            diffuse[i] = gl_FrontMaterial.diffuse.rgb * gl_LightSource[i].diffuse.rgb * diffuseIntensity;

        
    

片段:

#version 140

uniform bool useTexture;
uniform bool useLighting;
uniform sampler2D tex;
uniform int numLights;

varying vec3 normal;
varying vec3 ambient;
varying vec3 color;

varying vec3 diffuse[8];
varying vec3 lightDir[8];
varying vec3 dist[8];

varying vec2 texCoord;

void main() 


    vec4 texColor;

    if (useTexture) 
        texColor = texture2D(tex, texCoord);
     else 
        texColor = vec4(1.0);
    

    if (texColor.a == 0.0) 
        discard;
     else 
        texColor.a = 1.0;
    

    vec3 lightColor;

    if (useLighting) 
        lightColor = ambient;

        for (int i = 0; i < numLights; i++) 
            float specularIntensity;

            float att = 1.0;

            if (gl_LightSource[i].position.w != 0.0) 

                float dist = length(dist[i]);

                att = 1.0 / (gl_LightSource[i].constantAttenuation +
                             gl_LightSource[i].linearAttenuation * dist +
                             gl_LightSource[i].quadraticAttenuation * dist * dist);

                vec3 halfVector = normalize(lightDir[i]) + vec3(0.0, 0.0, 1.0);

                specularIntensity = dot(normalize(halfVector), normalize(normal));
             else 
                vec3 halfVector = normalize(lightDir[i]) + vec3(0.0, 0.0, 1.0);

                specularIntensity = dot(normalize(halfVector), normalize(normal));
            

            specularIntensity = max(specularIntensity, 0.0);

            lightColor += diffuse[i] * att;
            lightColor += gl_FrontMaterial.specular.rgb * gl_LightSource[i].specular.rgb * pow(specularIntensity, gl_FrontMaterial.shininess) * att;
        
     else 
        lightColor = color;
    

    gl_FragColor = texColor * vec4(lightColor, 1.0);

最后,我加载着色器的代码:

public class ShaderProgram 

    private final int programID;

    public ShaderProgram(int programID) 
        this.programID = programID;
    

    public ShaderProgram(Shader... shaders) 

        int id;

        try 
            id = glCreateProgram();
         catch (Exception ex) 
            Logger.getLogger(ShaderProgram.class.getName()).log(Level.SEVERE, null, ex);
            programID = 0;
            return;
        

        for (Shader shader : shaders) 
            glAttachShader(id, shader.id);
        

        glLinkProgram(id); 
        if (glGetProgrami(id, GL_LINK_STATUS) == GL_FALSE) 
            System.err.println(getLogInfo(id)); // This is the line that causes the error. It actually throws an exception (doesn't just print error info)
            programID = 0;
            return;
        

        glValidateProgram(id);
        if (glGetProgrami(id, GL_VALIDATE_STATUS) == GL_FALSE) 
            System.err.println(getLogInfo(id));
            programID = 0;
            return;
        

        programID = id;
    

    public static String getLogInfo(int obj) 
        return glGetShaderInfoLog(obj, glGetShaderi(obj, GL_INFO_LOG_LENGTH));
    

    public static ShaderProgram loadPrebuilt(String name) 
        Shader vert = Shader.loadPrebuilt(name + ".vert", Shader.Type.VERTEX);
        Shader frag = Shader.loadPrebuilt(name + ".frag", Shader.Type.FRAGMENT);

        return new ShaderProgram(vert, frag);
    

这是单个着色器文件(片段或顶点)的类

public class Shader 

    public final int id;

    public Shader(int id) 
        this.id = id;
    

    public Shader(File file, Shader.Type type) 
        int shader = 0;
        try 
            shader = create(readIntoString(new FileInputStream(file)), type);
         catch (IOException ex) 
            Logger.getLogger(Shader.class.getName()).log(Level.SEVERE, null, ex);
        
        id = shader;
    

    public Shader (String program, Shader.Type type) 
        id = create(program, type);
    


    public static Shader loadPrebuilt(String name, Shader.Type type) 
        try 
            return new Shader(readIntoString(name), type);
         catch (IOException | URISyntaxException ex) 
            Logger.getLogger(ShaderProgram.class.getName()).log(Level.SEVERE, null, ex);
            return new Shader(0);
        
    

    private int create(String program, Type type) 
        int shader = 0;
        try 
            shader = glCreateShader(type.glType);

            glShaderSource(shader, program);

            glCompileShader(shader);

            if (glGetShaderi(shader, GL_COMPILE_STATUS) == GL_FALSE) 
                System.err.println("Error creating shader (" + type.name() + "): " + getLogInfo(shader));
            

         catch (Exception ex) 
            glDeleteShader(shader);
            Logger.getLogger(ShaderProgram.class.getName()).log(Level.SEVERE, null, ex);
            shader = 0;
        

        return shader;
    

    private static String readIntoString(String filename) throws IOException, URISyntaxException 
        InputStream stream = Shader.class.getResourceAsStream(filename);

        return readIntoString(stream);
    

    private static String readIntoString(InputStream stream) throws IOException 

        String version = glGetString(GL_SHADING_LANGUAGE_VERSION);
        version = version.substring(0, version.indexOf(" ")).replaceFirst("\\.", "");

        return "#version " + version + "\n\n" + loadTextFile(stream);
    

失败的行是这样的:

ShaderProgram.loadPrebuilt("phong");

文件加载得很好。如果我打印它,它会打印出我想要的内容,并且在我尝试获取 ShaderProgram.java 中的日志信息之前它不会失败

【问题讨论】:

我敢打赌,问题不是与您的着色器有关,但这恰好是您下次检查 GL 错误时。 @immibis 如果我尝试更早地获取日志信息,那么无论如何它都会失败。我的其他着色器编译得很好,只是这个没有。此行仅在 glGetProgrami(id, GL_LINK_STATUS) == GL_FALSE 时运行,因此发生异常时程序已经编译失败。异常本身似乎是由于从无效着色器程序获取日志引起的,因为由于某种原因 glLinkProgram(id) 无法正常工作。 【参考方案1】:

ShaderProgram构造函数中的这段代码序列中:

if (glGetProgrami(id, GL_LINK_STATUS) == GL_FALSE) 
    System.err.println(getLogInfo(id));

id 是一个程序 id。你将它传递给getLogInfo() 方法:

public static String getLogInfo(int obj) 
    return glGetShaderInfoLog(obj, glGetShaderi(obj, GL_INFO_LOG_LENGTH));

glGetShaderInfoLog()glGetShaderi() 都期望 shader id 作为第一个参数。要获取有关程序的信息,您需要使用相应的程序调用:

public static String getLogInfo(int obj) 
    return glGetProgramInfoLog(obj, glGetProgrami(obj, GL_INFO_LOG_LENGTH));

【讨论】:

哇,有道理。就像你说的那样,我在 ShaderProgram 类中更改了我的 getLogInfo 方法(并为 Shader 创建了一个新方法)。现在我实际上可以看到我的着色器出了什么问题(它说没有足够的空间来定义变量)所以我想我现在会查一下。

以上是关于GLSL 着色器未编译,没有错误消息的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 运行 GLSL 着色器(尚未编译)的最快捷方式是啥?

Xcode 7 / iOS 9:在 SKNode 中使用 OpenGL 片段着色器未编译

为啥 OSX Mavericks 不能编译我的 GLSL 着色器?

GLSL-片段着色器不同部分的精度不同

GLSL 错误:无法预处理源。我该如何解决这个问题?

编译着色器 GLSL 3.30 时出错