我有一个方法,可以从两个给定字符串(顶点和片段着色器文件名)创建并返回着色器程序.起初,它工作得很好,编译和链接成功,但随机失败,并给我一个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: %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;
}

打印语句的输出如下:

"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:错误出现在我的GLSL着色器代码中,而不是我用来编译着色器的代码中.也就是说,我还根据@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;
}

推荐答案

如果着色器编译成功,则必须通过glGetShaderiv和参数GL_COMPILE_STATUS(而不是glGetProgramiv)进行判断.可以通过glGetShaderInfoLog(而不是glGetProgramInfoLog)获取日志(log),例如:

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));
    }
}

C++相关问答推荐

海湾合作委员会是否保证大小匹配的访问?

CC crate 示例不会与C函数链接

Ebpf内核代码:permission denied:invalid access to map value

如何一次获取一个字符

是否所有C编译器在将浮点数转换为整型数时都会隐式删除小数?

向上强制转换C中的数值类型总是可逆的吗?

为静态库做准备中的奇怪行为

Sizeof(&Q;字符串&Q;)的正确输出是什么?

为什么中断函数会以这种方式影响数组?

为什么函数是按照定义的顺序执行的,而不是按照从avr-c中的int main()调用的顺序执行的?

S和查尔有什么不同[1]?

覆盖读取函数,但当文件描述符为3或4时,我有问题

C标准关于外部常量的说明

不带Malloc的链表

问题:C#Define上的初始值设定项元素不是常量

被调用方函数内部的C-Struct变量,它是指针还是无关紧要

挥发性语义的形式化理解

在git补丁中自动添加C的宏

STM32:代码的执行似乎取决于它在闪存中的位置

如何使用 raylib 显示数组中的图像