OpenGL shader linking error with no error message - c++

I've been trying to figure this one out for a long time, but can't manage to get things to work. I want simply to compile/run my OpenGL program, but my shaders does not link correctly and I get no helpful error message. In one case the error is purely empty, and in the other case it is ??y? for some reason.
To create my program and compile my shaders, I have the following code:
GLuint buildProgram(const char* vertexShaderFile, const char* fragmentShaderFile)
{
std::string vs = fileContents(vertexShaderFile);
std::string fs = fileContents(fragmentShaderFile);
return createProgram(vs.c_str(), fs.c_str());
}
The shaders look like
#version 330
out vec4 out_color;
void main()
{
out_color = vec4(0.5, 0.5, 0.5, 0.5);
}
#version 330
in vec4 in_Position;
void main()
{
gl_Position = in_Position;
}
With
GLuint createProgram(const char* vertexSource, const char* fragmentSource)
{
GLuint vertexshader = createShader(vertexSource, GL_VERTEX_SHADER);
GLuint fragmentshader = createShader(fragmentSource, GL_FRAGMENT_SHADER);
GLuint program = glCreateProgram();
glAttachShader(program, vertexshader);
glAttachShader(program, fragmentshader);
glLinkProgram(program);
GLint ret;
checkShader(vertexshader, GL_LINK_STATUS, &ret, "unable to link vertex shader");
checkShader(fragmentshader, GL_LINK_STATUS, &ret, "unable to link fragment shader");
glUseProgram(program);
return program;
}
GLuint createShader(const char* source, GLenum shaderType)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint isCompiled = 0;
checkShader(shader, GL_COMPILE_STATUS, &isCompiled, "shader failed to compile");
if (isCompiled == GL_FALSE)
{
glDeleteShader(shader);
return 0;
}
return shader;
}
I try to generate error messages from the shaders by
void checkShader(GLuint shader, GLuint type, GLint* ret, const char* onfail)
{
switch(type) {
case(GL_COMPILE_STATUS):
glGetShaderiv(shader, type, ret);
if(*ret == false) {
int infologLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
GLchar buffer[infologLength];
GLsizei charsWritten = 0;
std::cout << onfail << std::endl;
glGetShaderInfoLog(shader, infologLength, &charsWritten, buffer);
std::cout << buffer << std::endl;
}
break;
case(GL_LINK_STATUS):
glGetProgramiv(shader, type, ret);
if(*ret == false) {
int infologLength = 0;
glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
GLchar buffer[infologLength];
GLsizei charsWritten = 0;
std::cout << onfail << std::endl;
glGetProgramInfoLog(shader, infologLength, &charsWritten, buffer);
std::cout << buffer << std::endl;
}
break;
default:
break;
};
}
Running GLuint program = buildProgram("shaders/test.vert", "shaders/test.frag"); gives me the following output:
unable to link vertex shader
unable to link fragment shader
??y?
error build program
error 502 : GL_INVALID_OPERATION
Does anyone have a guess why my shaders compile just fine but does not link?

You are calling getProgramiv(...,GL_LINK_STATUS,...) on shader objects. It doesn't make the slightest sense to even call that checkShader function twice - once for each shader object - when you try to get information about the program (of which there is only one). And it also doesn't make sense to name the function that way, for the GL_LINK_STATUS case.

Related

Why do I get a linking error when there should be nothing wrong

I'm a Java developer and I recently switched to C++. I've been trying to make a little OpenGL program and I ran into a problem. Whenever I try compiling my shader program it gives a linking error. Here it is:
ERROR::SHADER::PROGRAML::LINKING_ERROR
Link info
---------
error: "TexCoord" not declared as an output from the previous stage
Here are the shader files:
Vertex:
#version 440 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
Fragment
#version 440 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
And here is the shader creation:
int success;
char infoLog[512];
const char* vertexSource;
const char* fragmentSource;
// Load in shader source
std::ifstream inFile;
inFile.open(vertexPath);
std::string temp = "";
std::string source = "";
if (inFile.is_open())
{
while (std::getline(inFile, temp))
source += temp + "\n";
}
else
{
std::cout << "ERROR::SHADER::VERTEX::COULD_NOT_OPEN_SOURCE_FILE" << std::endl;
}
inFile.close();
vertexSource = source.c_str();
temp = "";
source = "";
inFile.open(fragmentPath);
if (inFile.is_open())
{
while (std::getline(inFile, temp))
source += temp + "\n";
}
else
{
std::cout << "ERROR::SHADER::FRAGMENT::COULD_NOT_OPEN_SOURCE_FILE" << std::endl;
}
inFile.close();
fragmentSource = source.c_str();
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, nullptr);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COULD_NOT_COMPILE\n" << infoLog << std::endl;
}
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, nullptr);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COULD_NOT_COMPILE\n" << infoLog << std::endl;
}
// Program
ID = glCreateProgram();
glAttachShader(ID, vertexShader);
glAttachShader(ID, fragmentShader);
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, 512, nullptr, infoLog);
std::cout << "ERROR::SHADER::PROGRAML::LINKING_ERROR\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glUseProgram(0);
To my understanding, I should only be getting this error if the two variables that I'm trying to link aren't the same name or type, but they are. I just don't understand.
Thanks.
You essentially have...
std::string source;
const char *vertexSource;
const char *fragmentSource;
...read into source...
vertexSource = source.c_str();
...read into source...
fragmentSource = source.c_str();
The pointer stored in vertexSource will be invalidated by the second read into source. From the documentation
The pointer obtained from c_str() may be invalidated by:
Passing a non-const reference to the string to any standard library function, or
Calling non-const member functions on the string, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and
rend().

C++ / OpenGL 3.3+: No vertices are being rendered

I guess this is the millionth question of the same type. I am using OpenGL 3.3 Core Profile with C++ and try to render a triangle.
I have already read the following two pages, including typing AND copy-pasting the code that is being discussed. Below I posted the significant bits. I already had a triangle being rendered, but obviously I changed some minor detail and messed it up. GLFW and GLEW are being initialized and clearing with the glClearColor works just fine.
Frameworks in use: GLFW for windowing, GLEW and GLM.
Question: What is the error in my code and why is nothing being rendered?
Expectation: A white triangle should be visible.
Result: Nothing is being rendered. The window is filled with the glClearColor
Game.cpp
const float vertex_data[9] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
void Game::init()
{
shader = ShaderProgram();
shader.attachShader(readTextFromFile("data/shaders/main.vs"), GL_VERTEX_SHADER);
shader.attachShader(readTextFromFile("data/shaders/main.fs"), GL_FRAGMENT_SHADER);
shader.linkProgram();
mesh = Mesh(vertex_data);
}
void Game::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.bind();
{
mesh.render();
}
shader.unbind();
}
Mesh.cpp
uint32_t vao;
uint32_t vertex_buffer;
Mesh::Mesh(const float vertex_data[])
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
}
void Mesh::render()
{
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
{
// Is this actually necessary for every draw-call?
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
glDisableVertexAttribArray(0);
}
ShaderProgram.cpp
uint32 id = 0;
bool linked = false;
uint32 vertex_shader = 0;
uint32 fragment_shader = 0;
ShaderProgram::~ShaderProgram()
{
unbind();
if (vertex_shader > 0)
{
glDetachShader(id, vertex_shader);
glDeleteShader(vertex_shader);
}
if (fragment_shader > 0)
{
glDetachShader(id, fragment_shader);
glDeleteShader(fragment_shader);
}
if (id > 0 && linked)
{
glDeleteProgram(id);
}
}
void ShaderProgram::attachShader(std::string source, int32 type)
{
assert(type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER);
assert(id == 0);
const char* code = source.c_str();
switch (type)
{
case GL_VERTEX_SHADER:
assert(vertex_shader == 0);
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &code, NULL);
glCompileShader(vertex_shader);
int32 vresult;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vresult);
if (vresult != GL_TRUE)
{
int32 infolength;
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &infolength);
GLchar* infolog = new GLchar[infolength + 1];
glGetShaderInfoLog(vertex_shader, infolength + 1, NULL, infolog);
std::stringstream ss;
ss << "Shader compilation failed for Vertex Shader: " << infolog << std::endl;
std::cout << ss.str() << std::endl;
throw std::runtime_error(ss.str());
}
break;
case GL_FRAGMENT_SHADER:
assert(fragment_shader == 0);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &code, NULL);
glCompileShader(fragment_shader);
int32 fresult;
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fresult);
if (fresult != GL_TRUE)
{
int32 infolength;
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &infolength);
int32 infosize = infolength + 1;
GLchar* infolog = new GLchar[infosize];
glGetShaderInfoLog(fragment_shader, infosize, NULL, infolog);
std::stringstream ss;
ss << "Shader compilation failed for Fragment Shader: " << infolog << std::endl;
std::cout << ss.str() << std::endl;
throw std::runtime_error(ss.str());
}
break;
default:
throw std::invalid_argument("Unknown Shader-Type specified");
}
}
void ShaderProgram::linkProgram()
{
assert(id == 0);
assert(vertex_shader > 0);
assert(fragment_shader > 0);
id = glCreateProgram();
glAttachShader(id, vertex_shader);
glAttachShader(id, fragment_shader);
glLinkProgram(id);
int32 result;
glGetProgramiv(id, GL_LINK_STATUS, &result);
if (result != GL_TRUE)
{
int32 infolength;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infolength);
int32 infosize = infolength + 1;
GLchar* infolog = new GLchar[infosize];
glGetProgramInfoLog(id, infosize, NULL, infolog);
std::stringstream ss;
ss << "Shader Program Linking failed: " << infolog << std::endl;
throw std::runtime_error(ss.str());
}
linked = true;
}
void ShaderProgram::bind()
{
assert(id > 0);
assert(linked);
glUseProgram(id);
}
void ShaderProgram::unbind()
{
int32 current;
glGetIntegerv(GL_CURRENT_PROGRAM, &current);
if (current == id)
{
glUseProgram(0);
}
}
bool ShaderProgram::isLinked()
{
return linked;
}
Vertex Shader: "main.vs"
#version 330
layout(location = 0) in vec3 VertexPosition;
void main()
{
gl_Position = vec4(VertexPosition.xyz, 1.0);
}
Fragment Shader "main.fs":
#version 330
out vec4 FinalColor;
void main()
{
FinalColor = vec4(1.0, 1.0, 1.0, 1.0);
}
This line has an error:
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
The second parameter expects the size of the array but you are passing the size of a pointer. To fix it use something like vertex count * sizeof( float )

OpenGL can't send variables from vertex shader to fragment shader

I'm pretty new to OpenGL and just started with a basic program that has a vertex shader and a fragment shader. Everything worked until I tried to send data from the vertex shader to the fragment shader. I use out in the vertex shader and in in the fragment shader.
Here are the shaders.
The Vertex:
#version 120
varying vec4 ourColor;
attribute vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
ourColor = vec4(1.0,0.1,0.2,0.5);
}
And the Fragment:
#version 120
varying vec4 ourColor;
void main()
{
gl_FragColor = ourColor;
}
The error is:
Fragment Shader contains a user varying but is linked without a vertex shader.
I tried using the flat keyword, and the varying keyword, same result. Also I've tried changing the version and then using in and out, same error.
Here is the Shader code (it's in a shader class, this is Shader.cpp):
Shader::Shader(const std::string & fileName)
{
m_program = glCreateProgram();
//vertex shader
m_shaders[0] = CreateShader(LoadShader(fileName + ".vs"), GL_VERTEX_SHADER);
m_shaders[0] = CreateShader(LoadShader(fileName + ".fs"),
GL_FRAGMENT_SHADER);
for(unsigned int i = 0; i < NUM_SHADERS; i++)
glAttachShader(m_program, m_shaders[i]);
glBindAttribLocation(m_program, 0, "position");
glLinkProgram(m_program);
CheckShaderError(m_program, GL_LINK_STATUS, true, "Error: Program linking failed. ");
glValidateProgram(m_program);
CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Error: Program is invalid. ");
}
//-----------
Shader::~Shader(void)
{
for(unsigned int i = 0; i < NUM_SHADERS; i++)
{
glDetachShader(m_program, m_shaders[i]);
glDeleteShader(m_shaders[i]);
}
glDeleteProgram(m_program);
}
//----------
void Shader::Bind()
{
glUseProgram(m_program);
}
static GLuint CreateShader(const std::string & text, GLenum shaderType)
{
GLuint shader = glCreateShader(shaderType);
if(shader == 0)
{
std::cerr << "Error: Shader creation failed! " << std::endl;
}
const GLchar* ShaderSourceStrings[1];
GLint ShaderSourceStringsLengths[1];
ShaderSourceStrings[0] = text.c_str();
ShaderSourceStringsLengths[0] = text.length();
glShaderSource(shader, 1, ShaderSourceStrings, ShaderSourceStringsLengths);
glCompileShader(shader);
CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error: Shader compilation failed");
return shader;
}
//-----------
static std::string LoadShader(const std::string & fileName)
{
std::ifstream file;
file.open((fileName).c_str());
std::string output;
std::string line;
if(file.is_open())
{
while(file.good())
{
getline(file, line);
output.append(line + "\n");
}
}
else
{
std::cerr << "unable to load shader file: " << fileName << std::endl;
}
return output;
}
//-----------
static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage)
{
GLint success = 0;
GLchar error[1024] = {0};
if(isProgram)
glGetProgramiv(shader, flag, &success);
else
glGetShaderiv(shader, flag, &success);
if(success == GL_FALSE)
{
if(isProgram){
glGetProgramInfoLog(shader, sizeof(error), NULL, error);
std::cout << "error from program" << std::endl;
}
else{
glGetShaderInfoLog(shader, sizeof(error), NULL, error);
std::cout << "error from shader" << std::endl;
}
std::cerr << errorMessage << ": '" << error << "'" << std::endl;
}
}
Here's the error.
m_shaders[0] =
m_shaders[0] =
Fragment Shader contains a user varying but is linked without a vertex shader.
Linked without a vertex shader? That would definitely cause problems. The code should look something vaguely like this:
GLuint load_shader(GLenum shader_type, ...) {
GLuint shader = glCreateShader(shader_type);
... load shader source code ...
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
// boom
}
... glGetShaderInfoLog ...
return shader;
}
GLuint load_program(...) {
GLuint prog = glCreateProgram();
// Attach both fragment and vertex shader
glAttachShader(prog, load_shader(GL_VERTEX_SHADER, ...));
glAttachShader(prog, load_shader(GL_FRAGMENT_SHADER, ...));
// Then link them together
glLinkProgram(prog);
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
// boom
}
... glGetProgramInfoLog ...
}
It's a fair bit of boilerplate code, and there are a lot of opportunities for the code to contain errors, so it's common for something to be wrong, especially since practically everything in OpenGL is just typedef int GLxxx; or something like that.
In GLSL 120, in and out are not storage qualifiers. Use varying instead.
// Same in vertex and fragment shader.
varying vec4 ourColor;
Alternatively, use a newer GLSL version.
#version 330
out vec4 ourColor;
in vec3 position;
#version 330
in vec4 ourColor;
out vec4 fragColor;

Unable to use separate shader programs "<program> object is not successfully linked."

const char *vs_source =
"#version 440\n\
layout(location = 0) in vec2 position;\n\
layout(location = 1) in float offset;\n\
void main() {\n\
vec2 new_pos = vec2(position.x + offset,position.y);\n\
gl_Position = vec4(new_pos,0,1);\n\
}";
const char *fs_source =
"#version 440\n\
out vec4 out_color;\n\
void main() {\n\
out_color = vec4(1,0,0,1);\n\
}";
auto vsp = createShaderProgram(GL_VERTEX_SHADER,1,&vs_source);
auto fsp = createShaderProgram(GL_FRAGMENT_SHADER,1,&fs_source);
GLuint pipeline;
glGenProgramPipelines(1,&pipeline);
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT , vsp.handle);
glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, fsp.handle);
glBindProgramPipeline(pipeline);
with
struct Program{
GLuint handle;
};
Program createShaderProgram(GLenum type,
GLsizei count,
const char **strings){
const GLuint shader = glCreateShader(type);
if (shader) {
glShaderSource(shader, count, strings, NULL);
glCompileShader(shader);
const GLuint program = glCreateProgram();
if (program) {
GLint compiled = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
if (compiled) {
glAttachShader(program, shader);
glLinkProgram(program);
glDetachShader(program, shader);
}
else{
/* append-shader-info-log-to-program-info-log */
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar* infoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, NULL, infoLog);
std::cout << "ERROR: Unable to compile shader" << std::endl << infoLog << std::endl;
delete[] infoLog;
}
}
glDeleteShader(shader);
return Program{program};
} else {
return Program{0};
}
}
OpenGL tells me that
message: GL_INVALID_OPERATION error generated. <program> object is not successfully linked.
type: ERROR
HIGH
and I am not sure why. If I link it the old way and only create one program it works perfectly.
I am guessing I have misused the the new pipeline system?
I should also mention that the error only appears when I start to call
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT , vsp.handle);
glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, fsp.handle);
Could this be a driver bug?
Solved it. The vertex shader didn't link. I had to redeclare gl_Position.
const char *vs_source =
"#version 440\n\
layout(location = 0) in vec2 position;\n\
layout(location = 1) in float offset;\n\
out gl_PerVertex\n\
{\n\
vec4 gl_Position;\n\
float gl_PointSize;\n\
float gl_ClipDistance[];\n\
};\n\
void main() {\n\
vec2 new_pos = vec2(position.x + offset,position.y);\n\
gl_Position = vec4(new_pos,0,1);\n\
}";

Can't get ids assigned to an attribute in OpenGL

I am trying to have OpenGL automatically assign an ID to a glsl-attribute, but it is failing.
My main program:
#include <iostream>
#include <GL/glew.h>
#include <GL/glfw3.h>
#include "test.h"
#include "shader_utils.h"
static void error_callback(int error, const char* description) {
std::cout << description << std::endl;
}
static void key_callback(GLFWwindow* window, int a, int b) {
if (a == GLFW_KEY_ESCAPE && b == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
void test()
{
std::cout << "Starting up" << std::endl;
init();
run();
}
GLFWwindow *window;
GLuint shaders;
GLuint vertexBuffer;
int init() {
glfwSetErrorCallback(error_callback);
if(!glfwInit()) {
return -1;
}
window = glfwCreateWindow(640, 480, "GLFW test", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glewExperimental = true;
glewInit();
shaders = LoadShaders("vertex.glsl", "fragment.glsl");
GLuint vao_id;
glGenVertexArrays(1, &vao_id);
glBindVertexArray(vao_id);
static const GLfloat vertex_data[] = {
// Bottom
-.5f, -.5f, -.5f, 1.f, 0.f, 0.f,
-.5f, -.5f, .5f, 1.f, 0.f, 0.f,
.5f, -.5f, .5f, 1.f, 0.f, 0.f,
};
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
}
void checkE() {
std::cout << "Checking for errors: ";
int err;
int a = 0;
while((err = glGetError()) != GL_NO_ERROR) {
std::cout << "Error: " << err << std::endl;
a = 1;
}
if(a == 0) {
std::cout << "no errors" << std::endl;
}
std::cout.flush();
}
int run() {
GLfloat angle = 0;
while(!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaders);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
GLuint attrLocation = glGetAttribLocation(shaders, "location");
GLuint attrColor = glGetAttribLocation(shaders, "color");
std::cout << "AttribLocation('location'): ";
std::cout << glGetAttribLocation(shaders, "location") << std::endl;
std::cout << "AttribLocation('color'): ";
std::cout << glGetAttribLocation(shaders, "color") << std::endl;
checkE();
std::cout << std::endl;
std::cout << "glEnableVertexAttribArray()" << std::endl;
glEnableVertexAttribArray(attrLocation);
glEnableVertexAttribArray(attrColor);
checkE();
std::cout << std::endl;
std::cout << "glVertexAttribPointer();" << std::endl;
glVertexAttribPointer(
glGetAttribLocation(shaders, "location"), // Attribute
3, // Size
GL_FLOAT, // Size
GL_FALSE, // Normalized
24, // Stride
(GLvoid*) 0 // Offset
);
checkE();
std::cout << std::endl;
std::cout << "glVertexAttribPointer();" << std::endl;
glVertexAttribPointer(
glGetAttribLocation(shaders, "color"),
3,
GL_FLOAT,
GL_FALSE,
24,
(GLvoid*) (3*sizeof(GLfloat))
);
checkE();
std::cout << std::endl;
glDrawArrays(GL_TRIANGLES, 0, 3);
checkE();
std::cout << std::endl;
glDisableVertexAttribArray(attrLocation);
glDisableVertexAttribArray(attrColor);
checkE();
std::cout << std::endl;
glfwSwapBuffers(window);
glfwPollEvents();
glfwSetWindowShouldClose(window, GL_TRUE);
}
glfwDestroyWindow(window);
glfwTerminate();
}
Output from program:
Starting up
Compiling shader : vertex.glsl
Compiling shader : fragment.glsl
Linking program
AttribLocation('location'): -1
AttribLocation('color'): -1
Checking for errors: no errors
glEnableVertexAttribArray()
Checking for errors: Error: 1281
glVertexAttribPointer();
Checking for errors: Error: 1281
glVertexAttribPointer();
Checking for errors: Error: 1281
Checking for errors: no errors
Checking for errors: Error: 1281
Shader loader:
#include "shader_utils.h"
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include "GL/glew.h"
#include "GL/glfw3.h"
GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path){
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open())
{
std::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
} else {
std::cout << "could not open\n";
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::string Line = "";
while(getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
// Link the program
fprintf(stdout, "Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
std::cout.flush();
return ProgramID;
}
Vertex shader:
#version 130
in vec4 position;
in vec3 color;
out vec3 f_color;
void main() {
f_color = color;
gl_Position = position * gl_ModelViewProjectionMatrix;
}
Fragment shader:
#version 130
in vec3 color;
void main() {
gl_FragColor = vec4(color, 1);
}
For some reason I get just -1 as the location for both the attributes. Obviously the rest of the errors are caused by invalid location indices?
From OpenGL docs:
If the named attribute variable is not an active attribute in the specified program object or if name starts with the reserved prefix "gl_", a value of -1 is returned.
The names do not begin with gl_ and they are in use in the shaders, so I shouldn't get a value of -1. What am I missing?
You are failing to get an attribute location for color because it is not active. While it is true that color is used to calculate f_color in this example, the fragment shader does not use f_color so the linker determines that the vertex attribute named: color is inactive.
The solution is quite simple, really:
Fragment Shader:
#version 130
in vec3 f_color; // RENAMED from color, so that this matches the output from the VS.
void main() {
gl_FragColor = vec4(f_color, 1);
}
It is not an error to re-use the name color for different purposes in the Vertex Shader (input vertex attribute) and Fragment Shader (input varying) stages so the compiler/linker will not complain. It would be an error if you tried to do something like inout color though, so this is why you have to pass vertex attributes to geometry/tessellation/fragment shaders using a differently named varying. If the input/output names between stages do not match then chances are quite good that the original vertex attribute will be considered inactive.
Also, unless you are transposing your ModelViewProjection matrix, you have the matrix multiplication in your vertex shader backwards. Column-major matrix multiplication, as OpenGL uses, should read right-to-left. That is, you start with an object space position (right-most) and transform to clip space (left-most).
In other words, this is the proper way to transform your vertices...
gl_Position = gl_ModelViewProjectionMatrix * position;
~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~
clip space object space to clip space obj space