OpenGL着色器编译和链接错误

vlf7wbxs  于 2022-09-26  发布在  其他
关注(0)|答案(2)|浏览(405)

我有一个方法,可以从两个给定的字符串(顶点和片段着色器文件名)创建并返回着色器程序。起初,它工作得很好,编译和链接成功,然后随机失败,给我一个Unicode表情符号的错误信息。

示例代码:


# 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: %sn", vertexfile); printf("Vertex Code: %dn", vertexcode); printf("Vertex Value: %dn", vertex);
    glGetProgramInfoLog(vertex, 512, NULL, log);
    printf("Vertex Shader Failed to Compile!n> OpenGL Error: %snn - - - - - nn", 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: %sn", fragmentfile); printf("Fragment Code: %dn", fragmentcode); printf("Fragment Value: %dn", fragment);
    glGetProgramInfoLog(fragment, 512, NULL, log);
    printf("Fragment Shader Failed to Compile!n> OpenGL Error: %snn - - - - - nn", 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: %dn", 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%sn", filename, shader);
  return shader;
}

打印语句的输出如下所示:

"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.

解决方案:错误出现在我的GLSL着色器代码中,而不是我用来编译着色器的代码中。话虽如此,我还是进行了修改,根据@Rabbit76和@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: %sn", 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: %sn", 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;
}
sqougxex

sqougxex1#

如果着色器编译成功,则必须通过glGetShaderiv和参数GL_COMPILE_STATUS而不是glGetProgramiv进行检查。可以使用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));
    }
}
vohkndzv

vohkndzv2#

glGetProgramInfoLog不是用于检查着色器是否已正确编译的适当函数。着色器对象和程序对象不是一回事(程序由着色器组成)。因此,将vertex传递给glGetProgramInfoLog不会得到您想要的结果,调用glGetError()可能会返回GL_INVALID_OPERATIONdocs表示写入日志的是以空结尾的字符串,但由于不支持函数的不变量(即,不是传递给它的程序),因此其输出很可能是垃圾。您实际需要的是glGetShaderInfoLog()2。这将有助于进一步的调试。LearnOpenGL在本页的“编译着色器”一节中有一个验证着色器的示例。

相关问题