从文件中读取glsl代码将不起作用

时间:2016-10-13 16:33:29

标签: opengl glsl

我开始创建一个Qt OpenGL应用程序。我遵循了Learnopengl中的教程。在本教程中,它给出了与顶点和片段着色器对应的静态C-String。当我向我的应用程序提供一个静态C-String着色器时,没有错误,我的三角形出现在屏幕上。

但是当我尝试处理所有着色器代码以分离文件时,我在glLinkProgram命令期间出错,例如 必须写入gl_Position

这是我的C ++代码:

#include "widget.h"

Widget::Widget(QOpenGLWidget *parent)
: QOpenGLWidget(parent)
{
   this->setWindowTitle("Learning OpenGL");
   QString pathV="shaders/main.vert";
   QString pathF="shaders/main.frag";
   vertexShaderSource=loadShader(pathV);
   fragmentShaderSource=loadShader(pathF);
}

Widget::~Widget()
{

}
void Widget::initializeGL()
{
  this->initializeOpenGLFunctions();
  qDebug()<<"Vous travaillez sur une OpenGL version:"<<QString((char*)glGetString(GL_VERSION));
  compileShaders();
  glClearColor(0.0,0.0,0.0,1.0);
  glClear(GL_COLOR_BUFFER_BIT);

}
void Widget::paintGL()
{

   GLfloat vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  1.0f, 0.0f
   };
   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);

   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
   glEnableVertexAttribArray(0);

   glBindBuffer(GL_ARRAY_BUFFER, 0); // Note that this is allowed, the call to glVertexAttribPointer registered VBO as the currently bound vertex buffer object so afterwards we can safely unbind

   glBindVertexArray(0); // Unbind VAO (it's always a good thing to unbind any buffer/array to prevent strange bugs)
   // Draw our first triangle
   glUseProgram(shaderProgram);
   glBindVertexArray(VAO);
   glDrawArrays(GL_TRIANGLES, 0, 3);
   glBindVertexArray(0);

 }
 QString Widget::loadShader(QString &path)
 {
    QFile file(path);
    file.open(QIODevice::ReadOnly);
    QTextStream stream(&file);
    QString lines;
    while(!stream.atEnd())
    {
       lines.append(stream.readLine()+"\n");
    }
    //lines.append('\0');
    file.close();
    return lines;
 }
 void Widget::compileShaders()
 {

     /* //Static shaders
     // Shaders
     vs = "#version 330 core\n"
      "layout (location = 0) in vec3 position;\n"
       "void main()\n"
       "{\n"
        "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
       "}\0";
    fs = "#version 330 core\n"
    "out vec4 color;\n"
    "void main()\n"
    "{\n"
    "color = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n"
    "}\n\0";

    //*/
    //Vertex shader
    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    vs=vertexShaderSource.toStdString().c_str();
    glShaderSource(vertexShader, 1,(const GLchar **) &vs, 0);
    glCompileShader(vertexShader);
    //check if any error during compilation
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if(!success)
    {
       glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
       qDebug()<< "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog ;
   }
    else qDebug()<<"compile vertex ok";
   //Fragment shader
   GLuint fragmentShader;
   fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
   fs=fragmentShaderSource.toStdString().c_str();
   glShaderSource(fragmentShader, 1,(const GLchar **)  &fs, 0);
   glCompileShader(fragmentShader);
    //Check if any error during compilation   
   glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
   if(!success)
   {
      glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
      qDebug()<< "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog ;
   }
   else qDebug()<<"compile fragment ok";

   shaderProgram = glCreateProgram();
   glAttachShader(shaderProgram, vertexShader);
   glAttachShader(shaderProgram, fragmentShader);
   glLinkProgram(shaderProgram);
   glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
   if(!success) {
      glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
      qDebug()<< "Linkage error\n" << infoLog;
   }

}

当我在控制台上显示从着色器文件中读取的数据时,它与静态C-String着色器代码相同。

所以我不明白为什么我的着色器文件会崩溃。

2 个答案:

答案 0 :(得分:0)

您的着色器源似乎为空或无效。最可能的原因是你正在为vs / fs变量分配临时副本缓冲区:

 vs=vertexShaderSource.toStdString().c_str();
 fs=fragmentShaderSource.toStdString().c_str();

这些指针可能在这些行之后无效,因此将它们传递给glShaderSource函数可能不是最好的主意。

您必须复制缓冲区内容。尝试这样的事情:

char* vs = new char[vertexShaderSource.size() + 1];
strcpy(vs, vertexShaderSource.toStdString().c_str());

答案 1 :(得分:0)

此代码:

fragmentShaderSource.toStdString()

生成字符串的临时副本。该临时表将在生成它的表达式后被销毁。因此,当您在该字符串上调用c_str()时,您将获得一个指向即将删除的内存的指针。

相反,您的fragmentShaderSource和类似的顶点着色器类型应该只是std::string本身。因此,loadShader应返回std::string(返回lines.toStdString()而非lines)。

完成后,您可以fragmentShaderSource.c_str()并将其自由传递给OpenGL。