【问题标题】:OpenGL shader linkingOpenGL着色器链接
【发布时间】:2015-07-18 18:34:04
【问题描述】:

在学习了一组很棒但没有让我理解基础知识的 OpenGL 教程之后,我正在尝试使用 C++ 进行一些非常基本的 OpenGL 编码。 我的程序应该读取顶点和片段着色器并绘制一个三角形。

链接着色器时出现错误(我怀疑错误可以追溯到着色器的编译)。我知道我的着色器已被我的程序读取,但对它们的任何更改都不会影响我的错误。通过运行:

glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success);

我收到错误消息:“在没有任何附加着色器对象的情况下调用链接”。程序构建,我的三角形显示,但不受着色器的影响。

更新

修复错误后,我不再收到上述错误。我现在在 glCompileShader() 之后得到一个抱怨:​​

“错误:0:3 '位置':语法错误解析错误”

所以我想这与我的着色器文件有关(将在下面添加它们)。着色器文件取自教程,所以我认为它们可以工作。

着色器文件:

顶点着色器:

#version 330                                                            

layout (location = 0) in vec3 Position;                                 

void main()                                                             
{                                                                       
    gl_Position = vec4(0.5*Position.x, 0.5*Position.y, Position.z, 1.0);    
}

片段着色器:

#version 330                                                            

out vec4 FragColor;                                                     

void main()                                                             
{                                                                       
    FragColor = vec4(1.0, 0.0, 0.0, 1.0);                               
}

在我的主要功能中我运行:

compileShader();

附加着色器:

static void AddShader(GLuint ShaderProgram, GLenum ShaderType, std::string filePath){

//create shader object
GLuint ShaderObj = glCreateShader(ShaderType);
//error if no shader
if (ShaderObj == 0){
    fprintf(stderr, "Error creating shader type %d\n", ShaderType);
    exit(0);
}

//"specify source code"
//readShaderFile returns the shader file as a string
std::string shaderFile = readShaderFile(filePath);
const char* shaderFilePointer = shaderFile.c_str();
GLint ShaderFileLength[1];  
ShaderFileLength[0] = strlen(shaderFilePointer);

glShaderSource(ShaderObj, 1, &shaderFilePointer, ShaderFileLength);

//compile the shader
glCompileShader(ShaderObj);

//check if compile successful
GLint success;
glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
if (!success){
    GLchar InfoLog[1024];
    glGetShaderInfoLog(ShaderObj, sizeof(InfoLog), NULL, InfoLog);
    fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
    exit(1);
}

glAttachShader(ShaderProgram, ShaderObj);

}

下面是用到的函数:

static void compileShaders(){

//create program
GLuint ShaderProgram = glCreateProgram();
//check error
if (ShaderProgram == 0){
    fprintf(stderr, "Error creating shader program!\n");
    exit(1);
}

//attach compiled shaders
std::string vertexShaderFilePath    = "Shaders/colShading.vert";
std::string fragShaderFilePath      = "Shaders/colShading.frag";

AddShader(ShaderProgram, GL_VERTEX_SHADER, vertexShaderFilePath);
AddShader(ShaderProgram, GL_FRAGMENT_SHADER, fragShaderFilePath);

GLint Success = 0;
GLchar ErrorLog[1024] = { 0 };

//link shader to program
glLinkProgram(ShaderProgram);
//check link error
glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success);

if (Success == 0) {
    glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
    fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
}

//use the linked shader program
glUseProgram(ShaderProgram);
}

我怀疑需要更多代码才能在这里找到问题,但请告诉我。提前非常感谢!

解决方案

下面的第一个答案成功了。我删除了:

layout (location = 0) 

从顶点着色器然后添加:

glBindAttribLocation(ShaderProgram, 0, "Position");

在链接之前。

【问题讨论】:

  • 您是否有任何需要调用glBindAttribLocation 的属性?
  • 不,着色器文件非常简单,如果理解正确,则不需要它。更重要的是,我忘了提;对我的着色器文件的任何更改都不会影响任何东西。我仍然遇到同样的错误。
  • 你能发布你的着色器吗?
  • 您是否尝试过将if (ShaderObj = 0){ 行更改为使用比较(==)而不是赋值(=)?然后可能会将ShaderObj 重新分配为始终为0,这可能不存在,或者类型错误。
  • 哇,我犯了一个严重的错误。我不知道我是怎么错过的。但是在修复它之后,它仍然没有正常运行,所以会检查并更新问题。谢谢@SebastianMendez

标签: c++ opengl


【解决方案1】:

您的硬件或驱动程序似乎不支持显式着色器位置语法,这需要 OpenGL/GLSL > 3.3。

要解决这个问题,如果 samgak 的回答没有帮助,你还有两个选择:

  1. 在链接着色器之前显式设置位置:

这是通过glBindAttribLocation 函数完成的,其含义与着色器中的基本相同。示例:

AddShader(ShaderProgram, GL_VERTEX_SHADER, vertexShaderFilePath);
AddShader(ShaderProgram, GL_FRAGMENT_SHADER, fragShaderFilePath);
//...

//Define the location of the attributes
glBindAttribute(ShaderProgram, 0, "Position") //Bind "in Position" to location 0

//link shader to program
glLinkProgram(ShaderProgram);
  1. 链接后,在构建您的 VAO(或绘制几何图形)时,查询属性的位置,并相应地设置缓冲区:

您可以使用 glGetAttribLocation 函数来执行此操作。

GLuint positionLoc = glGetAttribLocation(ShaderProgram, "Position");// Ask for the location of the attribute "Position

//Create buffers and transfer data...
glBindBuffer(gl.ARRAY_BUFFER, ...);


glBufferData(...);

//Turns on the vertex attribute for "Position" 
glEnableVertexAttribArray(positionLoc);

//Set the pointer between buffer and attribute 
glVertexAttribPointer(positionLoc,...);

出于性能原因,建议使用第一个选项,因为它不会强制刷新。

【讨论】:

  • 谢谢!我从顶点着色器中删除了:“layout (location = 0)”,并在链接之前添加了 glBindAttribute(...),它工作得很好。喜欢这个论坛,总是有很大的帮助!
  • 或者实际上我现在做了什么?通过删除“layout (location=0)”,它也可以在不使用 glBindAttribLocation(...) 的情况下正常工作。
  • 赞成,但我仍然认为我们还没有深入了解:为什么在 3.3+ 版本应该支持指定属性索引时它不起作用?跨度>
  • @remi000:如果不使用glBindAttribLocation,驱动会任意分配一个位置号。在您的情况下,它恰好也是 0,因此您的程序可以正常工作。但是,总是依赖这种情况是不明智的。驱动程序可能出于某种原因将1 指定为位置,而您的着色器中的数据将不正确。
  • @samgak 现在运行良好,我什至不确定“location = 0”最初在做什么,因为我对此很陌生。但这实际上应该如何工作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多