我正在学习OpenGL,我刚刚看到了如何编写着色器。但第一个问题是,在课程中,支持GLSL 3.30+(OpenGL 4),但我的驱动程序(mesa)不允许我使用GLSL 1.30或ES 3.20之上的版本。所以我在着色器中更改了#version
预处理器,然后我继续说道。但是,不幸的是,当我尝试使用颜色时,它没有用。
这是我的代码:
#include "colors.h"
#include <iostream>
#include <fstream>
#include <regex>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
unsigned int CompileShader(unsigned int type, std::string& source);
unsigned int CreateShader(std::string& vertexShader, std::string& fragmentShader);
int main(int argc, char* argv[]) {
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit()) {
std::cerr << "Couldn't initialize GLFW" << std::endl;
exit(1);
}
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", nullptr, nullptr);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK) {
std::cerr << "Couldn't initialize GLEW" << std::endl;
exit(1);
}
float positions[6] = {
-0.5f, -0.5f,
0.0f, 0.5f,
0.5f, -0.5f
};
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
// Compiling Shader
std::string vertexShader = "#version 130\n"
"\n"
"in vec4 position;\n"
"\n"
"void main () {\n"
" gl_Position = position;\n"
"}";
std::string fragmentShader = "#version 130\n"
"\n"
"uniform vec4 color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"\n"
"out vec4 outputF;\n"
"\n"
"void main () {\n"
" outputF = color;\n"
"}";
unsigned int shader = CreateShader(vertexShader, fragmentShader);
glUseProgram(shader);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
unsigned int CompileShader(unsigned int type, std::string& source) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cerr << "Failed to compile "
<< (type == GL_VERTEX_SHADER ? "vertex" : "fragment")
<< " shader. Error message:" << std::endl;
std::cerr << "\t" << FG_ERROR << message << std::endl;
}
return id;
}
unsigned int CreateShader(std::string& vertexShader, std::string& fragmentShader) {
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, vs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
我有时间看一下这个,发现你有一个小的复制粘贴错误:
unsigned int CreateShader(std::string& vertexShader, std::string& fragmentShader) {
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, vs); //<--should be fs
您正在连接顶点着色器两次。这将设置一个OpenGL错误,实际上我发现它的方式是我经常使用的OpenGL调试方法。当我更深入地测试你的代码时,我用一个定义来包围所有OpenGL调用,如果OpenGL设置了错误,它会停止执行。我把它放在源代码的顶部并建议使用它:
#include <cstdlib>
#include <iostream>
#include <iomanip>
void CheckOpenGLError(const char *stmt, const char *fname, int line);
#define GL_CHECK(stmt) \
do \
{ \
stmt; \
CheckOpenGLError(#stmt, __FILE__, __LINE__); \
} while (0)
void CheckOpenGLError(const char *stmt, const char *fname, int line)
{
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
std::cout << "OpenGL error 0x" << std::setfill('0') << std::setw(8) << std::hex << err << std::dec << ": " << gluErrorString(err) << ", at " << fname << ":" << line << " - for " << stmt << std::endl;
abort();
}
}
如果你想要以人类可读的形式打印出OpenGL错误,你需要另外链接glu库(windows上的glu32.lib或linux上的libGLU.so)中的gluErrorString函数,否则你需要查找错误代码。在这种情况下,我像这样包围你的电话:
unsigned int CreateShader(std::string& vertexShader, std::string& fragmentShader) {
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
GL_CHECK(glAttachShader(program, vs));
GL_CHECK(glAttachShader(program, vs)); //<--should be fs
然后在运行代码时抛出此错误:
OpenGL error 0x00000502: invalid operation, at main.cpp:147 - for glAttachShader(program, vs)
另外一个小注意事项,您应该在完成链接后分离着色器:
https://gamedev.stackexchange.com/a/47912
unsigned int CreateShader(std::string& vertexShader, std::string& fragmentShader) {
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDetachShader(program, vs);
glDetachShader(program, fs);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}