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

3

5

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.

Schrick answered 13/9, 2014 at 1:4 Comment(2)
VERTICES is an array of three vec3 instances. gl_Position.xyz is a vec3. Does not compute.Reduplicative
Yes, that vertex shader is not going to compile. Have you checked in a debugger if you hit the error case? You might not see the error output for some reason. For example, you're not outputting a newline after printing the error. Try adding a cerr << endl.Catabolite
S
11

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.

Schrick answered 13/9, 2014 at 20:39 Comment(3)
I had a similar issue where the source arrived in one line, and since I had comments, nothing compiled (every row after the first comment was considered a comment). adding "\n" after every line fixed it for meSympathetic
Similar issue for me too. Except to fix this using relative paths, I have to include the nested folder's name into the filename, but leave out the "../" part in the beginning. For example, I have a foo.vert file in $(SolutionDir)entities. I should provide a relative path of entities/foo.vert to the ifstream constructor and it works.Clog
Thanks for posting your solution. I had a similar issue and similar to this question, my problem was that I was calling c_str() on a string object likely to be destroyed before the shader string is actually used.Carmelitacarmelite
I
2

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.

Importunity answered 13/9, 2014 at 4:55 Comment(6)
I created a VBO like you said, created an array of GLFloats inside my main.cpp, put it inside the VBO and tried drawing it. My triangle shows up now, but the "gl_Position"-error remains and the shaders don't seem to be applied. This is how it looks currently: pastebin.com/fZs16288Schrick
Sure! Vertex shader: pastebin.com/VSRHQG6g Fragment shader: pastebin.com/nhqUT2T7Schrick
You are not binding your fragment output to anything.Importunity
If I understood that correctly I'm supposed to change the output to 'layout(location = 0) out vec4 color;' - did that, didn't change anything about the error-message or the color of my triangle.Schrick
Are you making a call to glDrawBuffers too?Importunity
I'm not. This function was never used in any of the tutorials I looked at; it doesn't seem to be necessary to just draw a triangle and use those two simple shaders. However, I tried using this function, which didn't change anything; I still get the "must write to gl_Position" error, so I think there's still something wrong with the vertex shader or the way I'm processing it to get a shaderprogram. Really confusing. BTW: I'm using the g++ compiler on Ubuntu, but that doesn't seem to make a difference, because I get the same error on my Windows machine.Schrick
S
0

Recently encountered this issue & I suspect the cause may be same as yours.

I'm not familiar with g++ however, on VS ones' build environment & the location on where your *exe is running from when you're debugging can impact on this. For example one such setting:

Project Properties -> General -> Output directory ->

Visual Studios Express - change debug output directory

And another similar issue here "The system cannot find the file specified" when running C++ program

You need to make sure if you've change the build environment and you're debugging from a different output directory that any of the relevant files are relative from where the *exe is being executed from.

This would explain why you've had to resort to using "if (vVStream.is_open())", which I suspect fails, & so then subsequently use full filepath of the shaders as the original referenced files are not relative.

My issue was exactly as yours but only in release mode. Once I copied over my shaders, into the release folder where the *exe could access them, the problem went away.

Sacrilegious answered 18/11, 2016 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.