为啥在使用 OpenGL 编译顶点着色器时会出现着色器编译器错误 #143、#160 和 #216?

Posted

技术标签:

【中文标题】为啥在使用 OpenGL 编译顶点着色器时会出现着色器编译器错误 #143、#160 和 #216?【英文标题】:Why am I getting a Shader Compiler Error #143, #160 and #216 when comiling a vertex Shader using OpenGL?为什么在使用 OpenGL 编译顶点着色器时会出现着色器编译器错误 #143、#160 和 #216? 【发布时间】:2018-12-08 09:00:39 【问题描述】:

我刚开始学习 C++ 中的 Grpahics,以及着色器和精灵。我写了一个小的顶点着色器和一个片段着色器。

顶点着色器:

#version 130

in vec2 vertexPosition;

void main() 
    gl_Position.xy = vertexPosition;
    gl_Position.z = 0.0;
    gl_Position.w = 1.0;

片段着色器:

#version 130

out vec3 color;

void main() 
    color = vec3(0.94, 0.37, 0.36);

在编译时,我收到以下错误消息:

Fragment shader failed to compile with the following errors:
ERROR: 0:6: error(#143) Undeclared identifier: gl_Position
ERROR: 0:6: error(#216) Vector field selection out of range "xy"
ERROR: 0:6: error(#160) Cannot convert from: "default in highp 2-component vector of vec2" to: "float"
ERROR: 0:7: error(#216) Vector field selection out of range "z"
ERROR: 0:8: error(#216) Vector field selection out of range "w"
ERROR: error(#273) 5 compilation errors.  No code generated

如何修复这些错误?

PS:我使用的是 AMD A10 8700P Radeon R6 处理器内置显卡。 在阅读其他问题时,我注意到使用 AMD 显卡是几个问题的根本原因,所以如果这是我的问题,那么我该如何解决呢?

我正在为所有 GLSL 操作使用单独的类。

GLSLProgram.h:

#pragma once

#include <GL/glew.h>

#include <string>

class GLSLProgram

public:
    GLSLProgram();
    ~GLSLProgram();

    void compileShaders(const std::string &vertexShaderFilePath, const std::string &fragmentShaderFilePath);

    void linkShaders();

    void addAttribute(const std::string& attributeName);

    void use();
    void unuse();
private:
    int _numAttributes;

    void compileShader(const std::string &filePath, GLuint id);

    GLuint _programID;

    GLuint _vertexShaderID;
    GLuint _fragmentShaderID;
;

GLSLProgram.cpp:

#include "GLSLProgram.h"
#include "Errors.h"

#include <fstream>
#include <vector>

GLSLProgram::GLSLProgram() : 
_numAttributes(0), _programID(0), _vertexShaderID(0), _fragmentShaderID(0) 




GLSLProgram::~GLSLProgram() 


void GLSLProgram::compileShaders(const std::string &vertexShaderFilePath, const std::string &fragmentShaderFilePath) 
    _vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    if (!_vertexShaderID) 
        fatalError("Vertex Shader failed to be created!");
    

    _fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
    if (!_fragmentShaderID) 
        fatalError("Fragment Shader failed to be created!");
    

    compileShader(vertexShaderFilePath, _vertexShaderID);
    compileShader(vertexShaderFilePath, _fragmentShaderID);


void GLSLProgram::linkShaders() 
    // Vertex and fragment shaders are successfully compiled.
    // Now time to link them together into a program.
    // Get a program object.
    _programID = glCreateProgram();

    // Attach our shaders to our program
    glAttachShader(_programID, _vertexShaderID);
    glAttachShader(_programID, _fragmentShaderID);

    // Link our program
    glLinkProgram(_programID);

    // Note the different functions here: glGetProgram* instead of glGetShader*.
    GLint isLinked = 0;
    glGetProgramiv(_programID, GL_LINK_STATUS, (int *)&isLinked);
    if (isLinked == GL_FALSE)
    
        GLint maxLength = 0;
        glGetProgramiv(_programID, GL_INFO_LOG_LENGTH, &maxLength);

        // The maxLength includes the NULL character
        std::vector<char> errorLog(maxLength);
        glGetProgramInfoLog(_programID, maxLength, &maxLength, &errorLog[0]);

        // We don't need the program anymore.
        glDeleteProgram(_programID);
        // Don't leak shaders either.
        glDeleteShader(_vertexShaderID);
        glDeleteShader(_fragmentShaderID);

        std::printf("%s\n", &(errorLog[0]));
        fatalError("Shaders failed to link!");
    

    // Always detach shaders after a successful link.
    glDetachShader(_programID, _vertexShaderID);
    glDetachShader(_programID, _fragmentShaderID);
    glDeleteShader(_vertexShaderID);
    glDeleteShader(_fragmentShaderID);


void GLSLProgram::addAttribute(const std::string &attributeName) 
    glBindAttribLocation(_programID, _numAttributes++, attributeName.c_str());



void GLSLProgram::use() 
    glUseProgram(_programID);
    for(int i = 0; i < _numAttributes; ++i) 
        glEnableVertexAttribArray(i);
    


void GLSLProgram::unuse() 
    glUseProgram(0);
    for(int i = 0; i < _numAttributes; ++i) 
        glDisableVertexAttribArray(i);
    



void GLSLProgram::compileShader(const std::string &filePath, GLuint id)

    std::ifstream shaderFile(filePath);
    if (shaderFile.fail())
    
        perror(filePath.c_str());
        fatalError("Failed to open " + filePath);
    

    std::string fileContents = "";
    std::string line;

    while (std::getline(shaderFile, line))
    
        fileContents += line + "\n";
    

    shaderFile.close();

    const char *contentsPtr = fileContents.c_str();
    glShaderSource(id, 1, &contentsPtr, nullptr);

    glCompileShader(id);

    GLint success = 0;
    glGetShaderiv(id, GL_COMPILE_STATUS, &success);

    if (success == GL_FALSE)
    
        GLint maxLength = 0;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);

        //The maxLength includes the NULL character
        std::vector<char> errorLog(maxLength);
        glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]);

        glDeleteShader(id);

        std::printf("%s\n", &(errorLog[0]));
        fatalError("Shader " + filePath + " Failed to compile");
    

致命错误只是打印提供的字符串并退出。

【问题讨论】:

对于顶点着色器,您必须通过glCreateShader( GL_VERTEX_SHADER)创建着色器对象。 我已经在一个单独的类中完成了该操作,该类处理所有 GLSL 操作。我也将在此处添加该代码。 是的,gl_Position 仅在顶点着色器中可用。 【参考方案1】:

gl_Position 仅在顶点着色器中有效。

你编译了两次顶点着色器,但是你没有编译compileShaders中的片段着色器:

必须是

compileShader(vertexShaderFilePath, _vertexShaderID);
compileShader(fragmentShaderFilePath, _fragmentShaderID);

而不是

compileShader(vertexShaderFilePath, _vertexShaderID);compileShader(vertexShaderFilePath, _fragmentShaderID);

【讨论】:

以上是关于为啥在使用 OpenGL 编译顶点着色器时会出现着色器编译器错误 #143、#160 和 #216?的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL着色器版本编译错误

将 emscripten 与 opengl 着色器一起使用

OpenGL:为啥我不能将单个浮点数从顶点着色器传递到片段着色器?

OpenGL 着色器编译但窗口中未出现渲染

传递给片段着色器的纹理坐标全部为 0

OpenGl固定管线各种存储着色器