I don't know what you're doing wrong on your code, as you didn't provided a minimal reproducible example of your problem, so I can't point what you're doing it wrong.
By writing my own application to:
- Load a GLFW window
- Load OpenGL Context
- Load a Shader based on your GLSL scripts (vertex and fragment)
- Load all uniforms
- Print all uniforms
That's the output of my application:
SHADER: Loading uniforms
(location = 0 ): light.intensity <- NOTE: This looks weird because
(location = 1 ): light.position i'm not searching the correct location
(location = 2 ): material.ka id for each uniform name. I'm guessing
(location = 3 ): material.kd them as if you've never set the
(location = 4 ): material.ks locations manually. The print
(location = 5 ): material.shininess occurs inside a for-loop. If you
(location = 6 ): normals_to_view_space take out all `layout(location=*)`
(location = 7 ): to_screen_space from the GLSL scripts, the ids printed
(location = 8 ): to_view_space here will look ok.
SHADER: Printing Uniforms
Uniform 'light.intensity' location is (4)
Uniform 'light.position' location is (3)
Uniform 'material.ka' location is (6)
Uniform 'material.kd' location is (7)
Uniform 'material.ks' location is (8)
Uniform 'material.shininess' location is (9)
Uniform 'normals_to_view_space' location is (2)
Uniform 'to_screen_space' location is (0)
Uniform 'to_view_space' location is (1)
So, in my test application, the uniforms locations were loaded successfully.
Here's the code I used. Note I also use the OpenGL version 4.50, with Core Profile. My code is an adaptation of the code provided from the learnopengl tutorials:
main.cpp:
#include "shader.hpp"
int main(int argc, char **argv) {
GLFWwindow* window = NULL;
Shader shader;
GLuint vao;
glewExperimental = true;
if (!glfwInit()) {
std::cout << "GLFW::FAILED" << std::endl;
return false;
} else {
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Our OpenGL version must be set
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); // to 4.50 (same as the shader)
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(800, 600, "GLSLloader.exe", NULL, NULL);
if (window == NULL) {
std::cout << "GLFW::FAILED::CREATE::WINDOW" << std::endl;
return false;
} else {
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
std::cout << "GLEW::FAILED" << std::endl;
} else {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
shader.LoadProgram();
shader.PrintUniforms();
}
}
}
return 0;
}
shader.hpp:
#ifndef _MY_SHADER_LOADER_
#define _MY_SHADER_LOADER_
// You can get all g++ flags and links by using the following command:
// pkg-config glfw3 glm glew --cflags --libs
//
// Compile with:
// g++ main.cpp shader.cpp -I./ -IC:/msys64/mingw64/bin/../include -LC:/msys64/mingw64/bin/../lib -lglfw3 -lglew32 -o GLSLloader.exe
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <istream>
#include <ostream>
#include <map>
#include <vector>
#include <list>
extern "C" {
#include <GL/glew.h>
#include <GLFW/glfw3.h>
}
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using ShaderUniforms = std::map<std::string, GLuint>;
class Shader {
private:
ShaderUniforms uniforms;
GLuint program;
void LoadUniforms();
GLuint Attachment(std::string filename, GLenum stype);
public:
Shader();
~Shader();
bool LoadProgram();
void ReleaseProgram();
void SetUniform(std::string key, const float data);
void PrintUniforms();
};
#endif
shader.cpp:
#include "shader.hpp"
// Code adaptated from: https://learnopengl.com/Getting-started/Shaders
Shader::Shader() {
program = 0;
uniforms = ShaderUniforms();
}
Shader::~Shader() {
ReleaseProgram();
}
bool Shader::LoadProgram() {
char infoLog[512];
bool success;
int result;
GLuint vertex = Attachment("vertex.glsl", GL_VERTEX_SHADER);
GLuint fragment = Attachment("fragment.glsl", GL_FRAGMENT_SHADER);
ReleaseProgram();
program = glCreateProgram();
success = true;
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &result);
if (!result) {
glGetProgramInfoLog(program, 512, NULL, infoLog);
std::cout << "SHADER::FAILED::LINK-PROGRAM " << infoLog << std::endl;
success = false;
}
if (vertex != 0) {
glDeleteShader(vertex);
}
if (fragment != 0) {
glDeleteShader(fragment);
}
if (success) {
LoadUniforms();
return true;
} else {
return false;
}
}
void Shader::ReleaseProgram() {
if (program != 0) {
glDeleteProgram(program);
program = 0;
}
uniforms.clear();
}
void Shader::SetUniform(std::string key, const float data) {
ShaderUniforms::iterator it;
it = uniforms.find(key);
if (it != uniforms.end()) {
glUniform1f(it->second, data);
}
}
// Private
// Source: https://stackoverflow.com/a/442819/14956120
void Shader::LoadUniforms() {
GLint n;
GLint size;
GLint bufSize;
GLenum type;
GLsizei length;
std::string name;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &bufSize);
std::vector<GLchar> uName = std::vector<GLchar>(bufSize+1, 0);
std::cout << "SHADER: Loading uniforms" << std::endl;
for (GLint i = 0; i < n; ++i) {
std::fill(uName.begin(), uName.end(), 0);
glGetActiveUniform(program, i, bufSize, &length, &size, &type, &(uName[0]));
if (length > 0) {
name = std::string(uName.begin(), uName.end());
std::cout << "(location = " << i << " ): " << name << std::endl;
uniforms.insert(std::pair<std::string, GLuint>(name, (GLuint) i));
}
}
}
// Private
GLuint Shader::Attachment(std::string filename, GLenum stype) {
std::string code;
std::ifstream file;
std::stringstream stream;
GLuint shader;
char* ccode;
char infoLog[512];
int result;
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
file.open(filename);
stream << file.rdbuf();
file.close();
code = stream.str();
} catch (std::ifstream::failure& e) {
std::cout << "SHADER::FAILED::READ::SOURCECODE (" << filename << ")" << std::endl;
return 0;
}
shader = glCreateShader(stype);
ccode = (char*) code.c_str();
glShaderSource(shader, 1, (const GLchar**) &(ccode), NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (!result) {
memset(infoLog, '\0', sizeof(char) * 512);
glGetShaderInfoLog(shader, 512, NULL, infoLog);
std::cout << "SHADER::FAILED::COMPILE (" << filename << "): " << infoLog << std::endl;
}
return shader;
}
// Used for testing only
void Shader::PrintUniforms() {
ShaderUniforms::iterator it;
GLint location = -1;
std::string name;
std::cout << std::endl;
std::cout << "SHADER: Printing Uniforms" << std::endl;
for (it = uniforms.begin(); it != uniforms.end(); ++it) {
name = it->first;
location = glGetUniformLocation(program, name.c_str());
if (location == -1) {
std::cout << "ERROR::SHADER::UNIFORM::" << name << "::NOT_FOUND"<<std::endl;
return;
} else {
std::cout << "Uniform '" << name << "' location is (" << location << ")" << std::endl;
}
}
}
vertex.glsl:
#version 450
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 norm;
layout (location = 2) out vec3 v_space_norm;
layout (location = 3) out vec3 v_space_pos;
layout(location = 0) uniform mat4 to_screen_space; // mvp
layout(location = 1) uniform mat4 to_view_space; //mv
layout(location = 2) uniform mat3 normals_to_view_space;
//layout(location = 4) float light_intensity;
void main() {
// for some reason, you wrote \* instead of *. So I removed the
// backslash character as the GLSL compiler complained about it
gl_Position = to_screen_space * vec4(pos, 1.0);
v_space_norm = normals_to_view_space * norm;
v_space_pos = (to_view_space * vec4(pos, 1.0)).xyz;
}
fragment.glsl:
#version 450
precision mediump float;
//------------ Structs ------------
// struct Light{
// vec3 position;
// float intensity;
// };
//------------ Variying ------------
layout (location = 2) in vec3 v_space_norm;
layout (location = 3) in vec3 v_space_pos;
//------------ Uniforms ------------
layout(location = 1) uniform mat4 to_view_space; //mv
//layout(location = 3) uniform vec3 light_position;
//layout(location = 4) uniform float light_intensity;
layout(location = 3) uniform struct{
vec3 position;
float intensity;
}light;
layout(location = 6) uniform struct{
vec3 ka;
vec3 kd;
vec3 ks;
float shininess;
} material;
out vec4 color;
void main() {
vec3 v_space_norm = normalize(v_space_norm);
vec3 l = normalize( (to_view_space * vec4(light.position, 1)).xyz - v_space_pos);//normalize(l); //light vector
vec3 h = normalize(l + vec3(0,0,1)); //half vector
float cos_theta = dot(l, v_space_norm);
if(cos_theta >= 0)
{
vec3 diffuse = material.kd * max(cos_theta,0);
vec3 ambient = material.ka;
vec3 specular= material.ks * pow(max(dot(h, v_space_norm),0), material.shininess);
color = vec4(light.intensity * (specular + diffuse) + ambient, 1);
}
else
{
color = vec4(material.ka,1);
}
}
Here's my project structure:
.
├── main.cpp
├── shader.hpp
├── shader.cpp
├── vertex.glsl
└── fragment.glsl
I'm using MSYS2 on windows 10, to compile and run the application.