Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL 3.3/GLSL & C++ error: "must write to gl_Position"

I'm currently trying to get a triangle to render using OpenGL 3.3 and C++ with the GLM, GLFW3 and GLEW libraries, but get an error when trying to create my shaderprogram.

Vertex info

(0) : error C5145: must write to gl_Position

I already tried to find out why this happens and asked on other forums, but no one knew what the reason is. There are three possible points where this error could have his origin - in my main.cpp, where I create the window, the context, the program, the vao etc. ...

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>

#include <iostream>
#include <string>

#include "util/shaderutil.hpp"

#define WIDTH   800
#define HEIGHT  600

using namespace std;
using namespace glm;

GLuint vao;
GLuint shaderprogram;

void initialize() {
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);

  glClearColor(0.5, 0.7, 0.9, 1.0);

  string vShaderPath   = "shaders/shader.vert";
  string fShaderPath   = "shaders/shader.frag";
  shaderprogram        = ShaderUtil::createProgram(vShaderPath.c_str(), fShaderPath.c_str());
}

void render() {
  glClear(GL_COLOR_BUFFER_BIT);

  glUseProgram(shaderprogram);

  glDrawArrays(GL_TRIANGLES, 0, 3);
}

void clean() {
  glDeleteProgram(shaderprogram);
}


int main(int argc, char** argv) {
  if (!glfwInit()) {
    cerr << "GLFW ERROR!" << endl;
    return -1;
  }

  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

  GLFWwindow* win = glfwCreateWindow(WIDTH, HEIGHT, "Rendering a triangle!", NULL, NULL);
  glfwMakeContextCurrent(win);
  glewExperimental = GL_TRUE;

  if (glewInit() != GLEW_OK) {
    cerr << "GLEW ERROR!" << endl;
    return -1;
  } else {
    glGetError();
    //GLEW BUG: SETTING THE ERRORFLAG TO INVALID_ENUM; THEREFORE RESET
  }

  initialize();

  while (!glfwWindowShouldClose(win)) {
    render();

    glfwPollEvents();
    glfwSwapBuffers(win);
  }

  clean();

  glfwDestroyWindow(win);
  glfwTerminate();

  return 0;
}

...the ShaderUtil class, where I read in the shader files, compile them, do error checking and return a final program...

#include "shaderutil.hpp"

#include <iostream>
#include <string>
#include <fstream>
#include <vector>

using namespace std;

GLuint ShaderUtil::createProgram(const char* vShaderPath, const char* fShaderPath) {
  /*VARIABLES*/
  GLuint vertexShader;
  GLuint fragmentShader;
  GLuint program;

  ifstream vSStream(vShaderPath);
  ifstream fSStream(fShaderPath);
  string vSCode, fSCode;

  /*CREATING THE SHADER AND PROGRAM OBJECTS*/
  vertexShader   = glCreateShader(GL_VERTEX_SHADER);
  fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  program    = glCreateProgram();

  /*READING THE SHADERCODE*/
  /*CONVERTING THE SHADERCODE TO CHAR POINTERS*/
  while (vSStream.is_open()) {
    string line = "";
    while (getline(vSStream, line)) {
      vSCode += "\n" + line;
    }
    vSStream.close();
  }
  const char* vSCodePointer = vSCode.c_str();

  while (fSStream.is_open()) {
    string line = "";
    while (getline(fSStream, line)) {
      fSCode += "\n" + line;
    }
    fSStream.close();
  }
  const char* fSCodePointer = fSCode.c_str();

  /*COMPILING THE VERTEXSHADER*/
  glShaderSource(vertexShader, 1, &vSCodePointer, NULL);
  glCompileShader(vertexShader);

  /*VERTEXSHADER ERROR CHECKING*/
  GLint vInfoLogLength;
  glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &vInfoLogLength);

  if (vInfoLogLength > 0) {
    vector<char> vInfoLog(vInfoLogLength + 1);
    glGetShaderInfoLog(vertexShader, vInfoLogLength, &vInfoLogLength, &vInfoLog[0]);

    for(int i = 0; i < vInfoLogLength; i++) {
      cerr << vInfoLog[i];
    }
  }

  /*COMPILING THE FRAGMENTSHADER*/
  glShaderSource(fragmentShader, 1, &fSCodePointer, NULL);
  glCompileShader(fragmentShader);

  /*FRAGMENTSHADER ERROR CHECKING*/
  GLint fInfoLogLength; 
  glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &fInfoLogLength);

  if (fInfoLogLength > 0) {
    vector<char> fInfoLog(fInfoLogLength + 1);
    glGetShaderInfoLog(fragmentShader, fInfoLogLength, &fInfoLogLength, &fInfoLog[0]);

    for(int i = 0; i < fInfoLogLength; i++) {
      cerr << fInfoLog[i];
    }
  }

  /*LINKING THE PROGRAM*/
  glAttachShader(program, vertexShader);
  glAttachShader(program, fragmentShader);
  glLinkProgram(program);
  //glValidateProgram(program);

  /*SHADERPROGRAM ERROR CHECKING*/
  GLint programInfoLogLength;
  glGetProgramiv(program, GL_INFO_LOG_LENGTH, &programInfoLogLength);

  if (programInfoLogLength > 0) {
    vector<char> programInfoLog(programInfoLogLength + 1);
    glGetProgramInfoLog(program, programInfoLogLength, &programInfoLogLength, &programInfoLog[0]);

    for(int i = 0; i < programInfoLogLength; i++) {
      cerr << programInfoLog[i];
    }
  }

  /*CLEANUP & RETURNING THE PROGRAM*/
  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);

  return program;
}

...and the vertex shader itself, which is nothing special. I just create an array of vertices and push them into gl_Position.

#version 330 core

void main() {
  const vec3 VERTICES[3] = vec3[3] {
    0.0, 0.5, 0.5,
    0.5,-0.5, 0.5,
   -0.5,-0.5, 0.5
  };

  gl_Position.xyz = VERTICES;
  gl_Position.w   = 1.0;
}

The fragmentshader just outputs a vec4 called color, which is set to (1.0, 0.0, 0.0, 1.0). The compiler doesn't show me any errors, but when I try to execute the program, I just get a window without the triangle and the error message that's shown above.

There's a few things I already tried to solve this problem, but none of them worked:

  • I tried creating the vertices inside my main.cpp and pushing them into the vertex-shader via a vertex buffer object; I changed some code inspired by opengl-tutorials.org and finally got a triangle to show up, but the shaders weren't applied; I only got the vertices inside my main.cpp to show up on the screen, but the "must write to gl_Position" problem remained.

  • I tried using glGetError() on different places and got 2 different error-codes: 1280 and 1282; the first one was caused by a bug inside GLEW, which causes the state to change from GL_NO_ERROR to GL_INVALID_ENUM or something like that. I was told to ignore this one and just change the state back to GL_NO_ERROR by using glGetError() after initializing GLEW. The other error code appeared after using glUseProgram() in the render-function. I wanted to get some information out of this, but the gluErrorString() function is deprecated in OpenGL 3.3 and I couldn't find an alternative provided by any of my libraries.

  • I tried validating my program via glValidateProgram() after linking it. When I did this, the gl_Position error message didn't show up anymore, but the triangle didn't either, so I assumed that this function just clears the infolog to put in some new information about the validation process

So right now, I have no idea what causes this error.

like image 592
DocCoock Avatar asked Sep 13 '14 01:09

DocCoock


2 Answers

The problem got solved! I tried to print the source that OpenGL tries to compile and saw that there was no source loaded by the ifstream. Things I had to change:

  1. Change the "while (vVStream.is_open())" to "if (vVStream.is_open())".
  2. Error check, if the condition I listed first is executed (add "else {cerr << "OH NOES!" << endl}
  3. Add a second parameter to the ifstreams I'm creating: change "ifstream(path)" to "ifstream(path, ios::in)"
  4. Change the path I'm passing from a relative path (e.g "../shaders/shader.vert") to an absolute path (e.g "/home/USERNAME/Desktop/project/src/shaders/shader.vert"); this somehow was necessary, because the relative path wasn't understood; using an absolute one isn't a permanent solution though, but it fixes the problem of not finding the shader.

Now it actually loads and compiles the shaders; there are still some errors to fix, but if someone has the same "must write to gl_Position" problem, double, no, triple-check if the source you're trying to compile is actually loaded and if the ifstream is actually open.

I thank everyone who tried to help me, especially @MtRoad. This problem almost made me go bald.

like image 66
DocCoock Avatar answered Sep 22 '22 14:09

DocCoock


Vertex shaders run on each vertex individually, so gl_Position is the output vertex after whatever transforms you wish to apply to the vertex being processed by vertex shader, so trying to emit multiple vertices doesn't make sense. Geometry shaders can emit additional geometry on the fly and can be used to do this to create motion blur for example.

For typical drawing, you bind a vertex array object like you did, but put data into buffers called Vertex Buffer Objects and tell OpenGL how to interpret the data's "attributes" using glVertexAttrib which you can read in your shaders.

like image 20
pyj Avatar answered Sep 26 '22 14:09

pyj