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

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

本文关键字:write must to Position gl GLSL C++ 错误 OpenGL      更新时间:2023-10-16

我目前正试图使用OpenGL 3.3和C++以及GLM、GLFW3和GLEW库来渲染一个三角形,但在尝试创建阴影程序时出错。

顶点信息

(0):错误C5145:必须写入gl_Position

我已经试图找出为什么会发生这种情况,并在其他论坛上询问,但没有人知道原因是什么。有三个可能的点,这个错误可能有他的起源-在我的main.cpp中,我在那里创建窗口,上下文,程序,vao等…

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

ShaderUtil类,我在其中读取着色器文件,编译它们,进行错误检查并返回最终程序。。。

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

以及顶点着色器本身,这没什么特别的。我只是创建一个顶点数组,并将它们推入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;
}

fragmentshader只输出一个名为color的vec4,它被设置为(1.0,0.0,0.0,1.0)。编译器不会显示任何错误,但当我尝试执行程序时,我只得到一个没有三角形和上面显示的错误消息的窗口。

我已经尝试了一些方法来解决这个问题,但都没有奏效:

  • 我尝试在main.cpp中创建顶点,并通过顶点缓冲区对象将它们推入顶点着色器;受opengl-tutorials.org的启发,我修改了一些代码,最终得到了一个三角形,但着色器没有应用;我只让main.cpp中的顶点显示在屏幕上,但"必须写入gl_Position"的问题仍然存在。

  • 我尝试在不同的地方使用glGetError(),得到了两个不同的错误代码:1280和1282;第一个是由GLEW内部的一个错误引起的,它导致状态从GL_NO_ERROR变为GL_INVALID_ENUM或类似的东西。有人告诉我忽略这个,在初始化GLEW后使用glGetError()将状态改回GL_NO_ERROR。在渲染函数中使用glUseProgram()后,出现了另一个错误代码。我想从中获得一些信息,但OpenGL 3.3中不赞成使用gluErrorString()函数,我找不到任何库提供的替代函数。

  • 链接后,我尝试通过glValidateProgram()验证我的程序。当我这样做时,gl_Position错误消息不再显示,但三角形也没有,所以我认为这个函数只是清除了信息日志,以放入一些关于验证过程的新信息

所以现在,我不知道是什么原因导致了这个错误。

问题解决了!我试图打印OpenGL试图编译的源代码,发现ifstream没有加载任何源代码。我必须改变的事情:

  1. 将"while(vVStream.is_open()"更改为"if(vVSstream.is_open())"
  2. 错误检查,如果执行了我首先列出的条件(添加"else{cerr<<"OH NOES!"<<endl}
  3. 在我正在创建的ifstreams中添加第二个参数:将"ifstream(path)"更改为"ifstream(path,ios:in)"
  4. 将我传递的路径从相对路径(例如"../shaders/shader.vert")更改为绝对路径(例如,"/home/USERNAME/Desktop/project/src/shaders/shader.vert");这在某种程度上是必要的,因为相对路径没有被理解;使用绝对着色器并不是一个永久的解决方案,但它解决了找不到着色器的问题

现在它实际加载并编译着色器;仍然有一些错误需要修复,但如果有人有同样的"必须写入gl_Position"问题,请仔细检查您试图编译的源是否真的加载了,以及ifstream是否真的打开了

我感谢所有试图帮助我的人,尤其是@MtRoad。这个问题差点让我秃顶。

顶点着色器分别在每个顶点上运行,因此gl_Position是在您希望应用于顶点着色器正在处理的顶点的任何变换之后的输出顶点,因此尝试发射多个顶点是没有意义的。几何体着色器可以动态发射额外的几何体,例如,可以用于创建运动模糊。

对于典型的图形,可以像以前一样绑定顶点阵列对象,但将数据放入名为"顶点缓冲区对象"的缓冲区中,并告诉OpenGL如何使用glVertexAttrib来解释数据的"属性",您可以在着色器中读取该属性。

最近遇到此问题&我怀疑原因可能和你的相同。

然而,我对g++并不熟悉,关于VS的构建环境&调试时运行*exe的位置可能会对此产生影响例如一个这样的设置:

Project Properties -> General -> Output directory ->

Visual Studios Express-更改调试输出目录

这里还有另一个类似的问题";系统找不到指定的文件";运行C++程序时

您需要确保,如果您更改了构建环境,并且从不同的输出目录进行调试,则任何相关文件都与执行*exe的位置相对。

这可以解释为什么你不得不使用"if(vVStream.is_open())",我怀疑它失败了,&因此随后使用着色器的完整文件路径,因为原始引用文件不是相对的。

我的问题和你的完全一样,但只是在发布模式下。一旦我将着色器复制到*exe可以访问它们的发布文件夹中,问题就消失了。