OpenGL 着色器无法编译

Posted

技术标签:

【中文标题】OpenGL 着色器无法编译【英文标题】:OpenGL shaders don't compile 【发布时间】:2017-12-17 08:47:27 【问题描述】:

我的 OpenGL 项目中的着色器无法编译。我有 Ubuntu 16.04 LTS,使用 CLion。没有找到任何解决方案,所以在这里问。

这是我的错误列表:

ATTENTION: default value of option force_s3tc_enable overridden by environment.
ERROR::SHADER::VERTEX::COMPILATION_FAILED
0:1(1): error: syntax error, unexpected $end

ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
0:1(1): error: syntax error, unexpected $end

ERROR::SHADER::PROGRAM::LINKING_FAILED
error: linking with uncompiled shadererror: linking with uncompiled shader

这是我的 main.cpp 代码:

#include <iostream>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>

// Other includes
#include "Shader.h"

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

// The MAIN function, from here we start the application and run the game loop
int main( )

    // Init GLFW
    glfwInit( );

    // Set all the required options for GLFW
    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );

    glfwWindowHint( GLFW_RESIZABLE, GL_FALSE );

    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow *window = glfwCreateWindow( WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr );

    int screenWidth, screenHeight;
    glfwGetFramebufferSize( window, &screenWidth, &screenHeight );

    if ( nullptr == window )
    
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate( );

        return EXIT_FAILURE;
    

    glfwMakeContextCurrent( window );

    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    if ( GLEW_OK != glewInit( ) )
    
        std::cout << "Failed to initialize GLEW" << std::endl;
        return EXIT_FAILURE;
    

    // Define the viewport dimensions
    glViewport( 0, 0, screenWidth, screenHeight );

    // Build and compile our shader program
    Shader ourShader( "core.vs", "core.frag" );


    // Set up vertex data (and buffer(s)) and attribute pointers
    GLfloat vertices[] =
            
                    // Positions         // Colors
                    0.5f, -0.5f, 0.0f,   1.0f, 0.0f, 0.0f,  // Bottom Right
                    -0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,  // Bottom Left
                    0.0f,  0.5f, 0.0f,   0.0f, 0.0f, 1.0f   // Top
            ;
    GLuint VBO, VAO;
    glGenVertexArrays( 1, &VAO );
    glGenBuffers( 1, &VBO );
    // Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
    glBindVertexArray( VAO );

    glBindBuffer( GL_ARRAY_BUFFER, VBO );
    glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW );

    // Position attribute
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof( GLfloat ), ( GLvoid * ) 0 );
    glEnableVertexAttribArray( 0 );
    // Color attribute
    glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof( GLfloat ), ( GLvoid * )( 3 * sizeof( GLfloat ) ) );
    glEnableVertexAttribArray( 1 );

    glBindVertexArray( 0 ); // Unbind VAO

    // Game loop
    while ( !glfwWindowShouldClose( window ) )
    
        // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
        glfwPollEvents( );

        // Render
        // Clear the colorbuffer
        glClearColor( 0.2f, 0.3f, 0.3f, 1.0f );
        glClear( GL_COLOR_BUFFER_BIT );

        // Draw the triangle
        ourShader.Use( );
        glBindVertexArray( VAO );
        glDrawArrays( GL_TRIANGLES, 0, 3 );
        glBindVertexArray(0);

        // Swap the screen buffers
        glfwSwapBuffers( window );
    

    // Properly de-allocate all resources once they've outlived their purpose
    glDeleteVertexArrays( 1, &VAO );
    glDeleteBuffers( 1, &VBO );

    // Terminate GLFW, clearing any resources allocated by GLFW.
    glfwTerminate( );

    return EXIT_SUCCESS;

Shader.h 代码:

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <GL/glew.h>
#include <cstring>

class Shader

public:
    GLuint Program;
    // Constructor generates the shader on the fly
    Shader( const GLchar *vertexPath, const GLchar *fragmentPath )
    
        // 1. Retrieve the vertex/fragment source code from filePath
        std::string vertexCode;
        std::string fragmentCode;
        std::ifstream vShaderFile;
        std::ifstream fShaderFile;
        // ensures ifstream objects can throw exceptions:
        vShaderFile.exceptions ( std::ifstream::badbit );
        fShaderFile.exceptions ( std::ifstream::badbit );
        try
        
            // Open files
            vShaderFile.open( vertexPath );
            fShaderFile.open( fragmentPath );
            std::stringstream vShaderStream, fShaderStream;
            // Read file's buffer contents into streams
            vShaderStream << vShaderFile.rdbuf( );
            fShaderStream << fShaderFile.rdbuf( );
            // close file handlers
            vShaderFile.close( );
            fShaderFile.close( );
            // Convert stream into string
            vertexCode = vShaderStream.str( );
            fragmentCode = fShaderStream.str( );
        
        catch ( std::ifstream::failure e )
        
            std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
        
        const GLchar *vShaderCode = vertexCode.c_str( );
        const GLchar *fShaderCode = fragmentCode.c_str( );
        // 2. Compile shaders
        GLuint vertex, fragment;
        GLint success;
        GLchar infoLog[512];
        // Vertex Shader
        vertex = glCreateShader( GL_VERTEX_SHADER );
        glShaderSource( vertex, 1, &vShaderCode, NULL);
        glCompileShader( vertex );
        // Print compile errors if any
        glGetShaderiv( vertex, GL_COMPILE_STATUS, &success );
        if ( !success )
        
            glGetShaderInfoLog( vertex, 512, NULL, infoLog );
            std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
        
        // Fragment Shader
        fragment = glCreateShader( GL_FRAGMENT_SHADER );
        glShaderSource( fragment, 1, &fShaderCode, NULL);
        glCompileShader( fragment );
        // Print compile errors if any
        glGetShaderiv( fragment, GL_COMPILE_STATUS, &success );
        if ( !success )
        
            glGetShaderInfoLog( fragment, 512, NULL, infoLog );
            std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
        
        // Shader Program
        this->Program = glCreateProgram( );
        glAttachShader( this->Program, vertex );
        glAttachShader( this->Program, fragment );
        glLinkProgram( this->Program );
        // Print linking errors if any
        glGetProgramiv( this->Program, GL_LINK_STATUS, &success );
        if (!success)
        
            glGetProgramInfoLog( this->Program, 512, NULL, infoLog );
            std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
        
        // Delete the shaders as they're linked into our program now and no longer necessery
        glDeleteShader( vertex );
        glDeleteShader( fragment );

    
    // Uses the current shader
    void Use( )
    
        glUseProgram( this->Program );
    
;

#endif

这是我的 core.vs:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;

out vec3 ourColor;
out vec2 TexCoord;

void main()

    gl_Position = vec4(position, 1.0f);
    ourColor = color;
    // We swap the y-axis by substracing our coordinates from 1. This is done because most images have the top y-axis inversed with OpenGL's top y-axis.
    // TexCoord = texCoord;
    TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);

...和 ​​core.frag:

#version 330 core
in vec3 ourColor;
in vec2 TexCoord;

out vec4 color;

// Texture samplers
uniform sampler2D ourTexture1;

void main()

// Linearly interpolate between both textures (second texture is only slightly combined)
color = texture(ourTexture1, TexCoord);

我还附上了我的 CMakeLists.txt。希望对您有所帮助:

cmake_minimum_required(VERSION 3.9)
project(STUDY_GL)

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -std=c++14 -pthread -fpermissive")

find_package (OpenGL REQUIRED)
find_package (GLUT REQUIRED)
find_package (glfw3 REQUIRED)
find_library (glew REQUIRED)
find_library (glad REQUIRED)


include_directories($/usr/include/GLFW/)
include_directories($/usr/include/GL/)


file(GLOB SOURCE_FILES
        *.cpp
        *.h
        )

add_executable(main.cpp $SOURCE_FILES Shader.h)

target_link_libraries (main.cpp $OPENGL_LIBRARIES $GLUT_LIBRARIES $GLFW3_LIBRARIES -lGL -lglfw -lglut -lGLEW)

我在项目中有一个 SOIL2 目录。这是它的link。

【问题讨论】:

在GLSL版本声明之后你不写core会发生什么?只是问,因为我从未见过这样的声明。 【参考方案1】:

一般来说你的代码没问题,但你必须将std::ifstream::failbit 传递给std::ios::exceptions,因为如果std::ifstream::open 失败,则设置失败位状态标志。

vShaderFile.exceptions ( std::ifstream::failbit | std::ifstream::badbit );
fShaderFile.exceptions ( std::ifstream::failbit | std::ifstream::badbit );
try

   vShaderFile.open( vertexPath );
   fShaderFile.open( fragmentPath );
   .....

catch ( std::ifstream::failure e )

    std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;

我敢打赌,您的工作目录设置不正确。出于调试原因,使用着色器文件的绝对文件路径。 如果无法访问着色器源文件,并且您的代码没有抛出任何异常,那么您尝试编译空字符串。这会导致错误消息。

顺便说一句,由于您在问题中发布的代码 sn-p 中没有使用任何纹理,因此您应该对片段着色器进行以下更改:

// color = texture(ourTexture1, TexCoord); <--- skip
color = vec4(ourColor,1.0);                <--- add

【讨论】:

我认为只有 badbit 传递的字符串会是空的吗?【参考方案2】:

您看到的错误通常发生在最后没有空终止符的着色器源被传递给 glShaderSource 而不指定源字符串长度时。由于典型文件通常不包含空终止符,因此 OpenGL 将读取源字符串的末尾。

解决方法是传入着色器源字符串的确切长度。

【讨论】:

@Rabbid76:应该,是的。

以上是关于OpenGL 着色器无法编译的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL着色器无法编译

Android OpenGL ES 3.1着色器无法编译

无法获得简单的 2D 着色器以在 C++ openGL 中绘制红色三角形(无编译器错误)

无法在 Maya 插件中编译顶点着色器

Emscripten 无法编译着色器

将 emscripten 与 opengl 着色器一起使用