简体   繁体   English

OpenGL 着色器编译和链接错误

[英]OpenGL Shader Compilation and Linking Error

I have a method that creates and returns a shader program from two given strings (vertex and fragment shader filenames).我有一个方法可以从两个给定的字符串(顶点和片段着色器文件名)创建并返回一个着色器程序。 Initially, it was working perfectly, with the compilation and linking being successful, before randomly failing and giving me an error message of unicode emoji's.最初,它运行良好,编译和链接成功,然后随机失败并给我一条 unicode 表情符号的错误消息。

Example Code:示例代码:

#define GLEW_STATIC
#define NO_SDL_GLEXT
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFSIZE 1024
#define MAXSIZE 1048576

typedef struct Shader {
  unsigned int data;
} Shader;

char* loadshader(char*);
Shader* createShader(char* vertexfile, char* fragmentfile) {
  const char* vertexcode = loadshader(vertexfile);
  unsigned int vertex = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertex, 1, &vertexcode, NULL);
  glCompileShader(vertex);

  {
    char log[512]; int success; glGetProgramiv(vertex, GL_COMPILE_STATUS, &success);
    printf("Vertex File Name: %s\n", vertexfile); printf("Vertex Code: %d\n", vertexcode); printf("Vertex Value: %d\n", vertex);
    glGetProgramInfoLog(vertex, 512, NULL, log);
    printf("Vertex Shader Failed to Compile!\n> OpenGL Error: %s\n\n - - - - - \n\n", log);
  }

  const char* fragmentcode = loadshader(fragmentfile);
  unsigned int fragment = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragment, 1, &fragmentcode, NULL);
  glCompileShader(fragment);

  {
    char log[512]; int success; glGetProgramiv(fragment, GL_COMPILE_STATUS, &success);
    printf("Fragment File Name: %s\n", fragmentfile); printf("Fragment Code: %d\n", fragmentcode); printf("Fragment Value: %d\n", fragment);
    glGetProgramInfoLog(fragment, 512, NULL, log);
    printf("Fragment Shader Failed to Compile!\n> OpenGL Error: %s\n\n - - - - - \n\n", log);
  }

  unsigned int data = glCreateProgram();
  glAttachShader(data, vertex);
  glAttachShader(data, fragment);
  glLinkProgram(data);

  {
    char log[512]; int success; glGetProgramiv(data, GL_LINK_STATUS, &success);
    printf("Program Value: %d\n", data); glGetProgramInfoLog(data, 512, NULL, log);
    printf("Shader Failed to Link!\n> OpenGL Error: %s", log);
  }

  glDeleteShader(vertex);
  glDeleteShader(fragment);
  free((void*) vertexcode);
  free((void*) fragmentcode);

  Shader* shader = (Shader*) malloc(sizeof(Shader));
  shader -> data = data;
  return shader;
}

int WinMain(int argc, char const *argv[]) {
  SDL_Init(SDL_INIT_VIDEO);
  SDL_Window* window = SDL_CreateWindow("Basic Window", 660, 240, 600, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
  SDL_GLContext context = SDL_GL_CreateContext(window);
  glewInit();
  Shader* shader = createShader("data/test.vs", "data/test.fs");
  return 0;
}

char* loadshader(char* filename) {
  FILE* file = fopen(filename, "r");
  if (!file)
    return NULL;

  int flag = 0;
  char* shader = (char*) malloc(MAXSIZE);
  char* buffer = (char*) malloc(BUFFSIZE);
  while (fgets(buffer, BUFFSIZE, file) != NULL)
    strcat(shader, buffer);

  free(buffer);
  fclose(file);

  printf("\"%s\" Content:\n%s\n", filename, shader);
  return shader;
}

The output of the print statements are as follows:打印语句的output如下:

"data/test.vs" Content:
#version 330 core
layout (location = 0) in vec3 POSITION;

void main() {
  gl_Position = vec4(POSITION, 1.0);
}

Vertex File Name: data/test.vs
Vertex Code: -1521078208
Vertex Value: 1
Vertex Shader Failed to Compile!
> OpenGL Error: ░╗x¥j☻

 - - - - -

"data/test.fs" Content:
#version 330 core
out vec4 COLOR;

void main() {
  COLOR = vec4((1.0f, 0.5f, 0.2f, 1.0f);
}

Fragment File Name: data/test.fs
Fragment Code: -1486147520
Fragment Value: 2
Fragment Shader Failed to Compile!
> OpenGL Error: ░╗x¥j☻

 - - - - -

Program Value: 3
Shader Failed to Link!
> OpenGL Error: Fragment shader(s) were not successfully compiled before glLinkProgram() was called.  Link failed.

Solution : The error was in my GLSL shader code, not the code I was using to compile the shaders.解决方案:错误出现在我的 GLSL 着色器代码中,而不是我用来编译着色器的代码中。 That being said, I also made changes to properly check for compilation and linking errors based on @Rabbid76 and @David Sullivan 's responses.话虽如此,我还根据@Rabbid76@David Sullivan的回复进行了更改,以正确检查编译和链接错误。

Shader* createShader(char* vertexfile, char* fragmentfile) {
  const char* vertexcode = loadshader(vertexfile);
  unsigned int vertex = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertex, 1, &vertexcode, NULL);
  glCompileShader(vertex);

  {
    char log[1024]; int success; glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
    if (!success) {
      glGetShaderInfoLog(vertex, 1024, NULL, log);
      printf("Vertex Shader Failed to Compile!\n> OpenGL Error: %s\n", log);
    }
  }

  const char* fragmentcode = loadshader(fragmentfile);
  unsigned int fragment = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragment, 1, &fragmentcode, NULL);
  glCompileShader(fragment);

  {
    char log[1024]; int success; glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
    if (!success) {
      glGetShaderInfoLog(fragment, 1024, NULL, log);
      printf("Fragment Shader Failed to Compile!\n> OpenGL Error: %s\n", log);
    }
  }

  unsigned int data = glCreateProgram();
  glAttachShader(data, vertex);
  glAttachShader(data, fragment);
  glLinkProgram(data);

  {
    char log[1024]; int success; glGetProgramiv(data, GL_LINK_STATUS, &success);
    if (!success) {
      glGetProgramInfoLog(data, 1024, NULL, log);
      printf("Shader Failed to Link!\n> OpenGL Error: %s", log);
    }
  }

  glDeleteShader(vertex);
  glDeleteShader(fragment);
  free((void*) vertexcode);
  free((void*) fragmentcode);

  Shader* shader = (Shader*) malloc(sizeof(Shader));
  shader -> data = data;
  return shader;
}

glGetProgramInfoLog is not the appropriate function for checking if a shader was compiled correctly. glGetProgramInfoLog不是用于检查着色器是否正确编译的合适 function。 Shader objects and program objects are not the same thing (programs are composed of shaders).着色器对象和程序对象不是一回事(程序是由着色器组成的)。 So passing vertex into glGetProgramInfoLog will not give you what you want, and likely a call to glGetError() would return GL_INVALID_OPERATION .所以将vertex传递给glGetProgramInfoLog不会给你你想要的,并且可能调用glGetError()会返回GL_INVALID_OPERATION The docs say that what is written to log is a null terminated string, but since the invariants of the function are not upheld (ie, not a program passed to it), its output is likely garbage.文档说写入日志的是 null 终止的字符串,但由于不支持 function 的不变量(即,不是传递给它的程序),它的 Z78E6221F6393D1356681ZFCE38D 可能是垃圾。 What you actually want is glGetShaderInfoLog() 2 .你真正想要的是glGetShaderInfoLog() 2 The output of this will help debug further.其中的 output 将有助于进一步调试。 LearnOpenGL has an example of validating a shader in the "Compiling a shader" section of this page. LearnOpenGL在本页的“编译着色器”部分中有一个验证着色器的示例。

If the compiling of a shader succeeded has to be checked by glGetShaderiv and the parameter GL_COMPILE_STATUS instead of glGetProgramiv .如果着色器编译成功必须通过glGetShaderiv和参数GL_COMPILE_STATUS而不是glGetProgramiv THe log can be get with glGetShaderInfoLog instead of glGetProgramInfoLog eg:可以使用glGetShaderInfoLog而不是glGetProgramInfoLog获取日志,例如:

glCompileShader(vertex);

{
    glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
    if (!success) {
        // [...]

        glGetShaderInfoLog(vertex, 512, NULL, log);
        printf(strcat(strcpy(msg, "Vertex Shader Failed to Compile!\n> OpenGL Error: "), log));
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM