Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 20 hours ago.
Improve this question
This shader doesn't seem to compile i am using c++ and glew, openGL. The glew version is 2.2.0 and the openGL version is 4.6. the glGetShaderInfoLog() function just returns nonsense. The compiled shaders id's just return as 0. The glGetShaderiv() return GLEW_ERROR_NO_GL_VERSION. here are the shaders and the c++ code for compiling and linking the shaders.
INIT
glfwSetErrorCallback(GlfwErrorCallback);
if(!glfwInit()) ERROR("failed to initialize glfw\n");
LOG("glfw version: " << glfwGetVersionString() << "\n");
m_Window = glfwCreateWindow(800, 800, "Cotton Game Engine", NULL, NULL);
if(!m_Window) ERROR("failed to create window\n");
glfwMakeContextCurrent(m_Window);
if(glewInit() != GLEW_OK) ERROR("failed to initialize glew\n");
LOG("glew version: " << glewGetString(GLEW_VERSION) << "\n");
LOG("opengl version: " << glGetString(GL_VERSION) << "\n");
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(GlErrorCallback, 0);
VERTEX SHADER
#version 460 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
layout(location = 2) in vec2 a_TexCoord;
layout(location = 3) in float a_TexIndex;
uniform mat4 u_MVP;
out vec4 v_Color;
out vec2 v_TexCoord;
out float v_TexIndex;
void main()
{
v_TexCoord = a_TexCoord;
v_Color = a_Color;
v_TexIndex = a_TexIndex;
gl_Position = u_MVP * vec4(a_Position, 1.0);
}
FRAGMENT SHADER
#version 460 core
layout(location = 0) out vec4 o_Color;
in vec4 v_Color;
in vec2 v_TexCoord;
in float v_TexIndex;
uniform sampler2D u_Textures[10];
void main()
{
o_Color = texture(u_Textures[int(v_TexIndex)], v_TexCoord) * v_Color;
}
C++ Side
Shader::Shader(const std::string &vertexFilepath, const std::string &fragmentFilepath)
{
std::string vertexSource = ReadFileIntoString(vertexFilepath);
std::string fragmentSource = ReadFileIntoString(fragmentFilepath);
m_ID = CreateShader(vertexSource, fragmentSource);
}
unsigned int Shader::CreateShader(const std::string& vertexSource, const std::string& fragmentSource)
{
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexSource);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentSource);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
unsigned int Shader::CompileShader(unsigned int type, const 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 != GLEW_OK) {
char message[128];
glGetShaderInfoLog(id, sizeof(message), NULL, message);
ERROR("could not compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader: " << message << "\n");
glDeleteShader(id);
return 0;
}
return id;
}
Related
Im trying to create a material struct and a light struct that I will use in GLSL fragment shader. I can render the scene I have correctly when I have only one struct defined (either material or light) but when I define both of them together the glGetUniformLocation(...) calls return -1 for Material structs (order of defnitions does not matter) as if they are not there or not being used. I need to use the structs for the future use please do not ask me to use PODs. I want to learn how to upload multiple structs as uniforms. Thanks.
Here is the vertex shader:
#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() {
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;
}
and fragment shader:
#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);
}
}
And the way I set uniforms:
...
program->SetUniform("light.position", light.position);
program->SetUniform("light.intensity", light.intensity);
program->SetUniform("material.ka", material.ambient);
program->SetUniform("material.kd", material.diffuse);
program->SetUniform("material.ks", material.specular);
program->SetUniform("material.shininess", material.shininess);
...
The definition of SetUniform:
GLint location = glGetUniformLocation(glID, name);
if (location == -1)
{
std::cout << "ERROR::SHADER::UNIFORM::" << name << "::NOT_FOUND"<<std::endl;
return;
}
glUniform1f(location, value);//or what ever the type is there are definitions for all types!!!
I was unable to find anything online about my problem
I was hoping to see the teapot rendered and blinn shaded. And I can get that if I only define one struct and then upload the other properties as PODs.
So using the fragment shader below:
//------------ 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;
...
//using light_position and light_intensity instead of light.position, light.intensity
Of course setUniform calls are also changed accordingly.
enter image description here
But if I use both of the structs I get this:
enter image description here
Edit: Instead of accessing via glGetUniformLocation(glID, name); I can manually set each variable via layout location number. Now the question becomes "Can I set the structs using the string variable names?"
Using named structs like:
struct Light{
vec3 position;
float intensity;
};
And then using them as uniforms seems to be the correct way to go according to OpenGL wiki (I could have sworn I tried that but oh well...).
layout(location = 3) uniform Light light;
So,
layout(location = 3) uniform struct{
vec3 position;
float intensity;
}light;
this is either not good or undefined behavior which is beyond my knowledge.
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.
I trying to learn OpenGl and now I wanted to make a simple red triangle on a black background with vertices and shaders. I copied the code from that YouTube video. I've changed a view things. That's my code:
#include "prec.h"
struct Vector2
{
float x, y;
};
struct TrianglePos
{
Vector2 a, b, c;
};
static unsigned int CompileShader(unsigned int type, const 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)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile shader, message: " << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int createShader(const std::string& vertexShader, const 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);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main() {
if (!glfwInit())
return -1;
GLFWwindow *window = glfwCreateWindow(640, 480, "Sand Box GL", NULL, NULL);
if (!window) {
std::cout << "problems with window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (GLEW_OK != glewInit()) {
std::cout << "something with glew went wrong" << std::endl;
return -1;
}
TrianglePos trianglePos = {
-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, sizeof(trianglePos), &trianglePos, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), 0);
std::string vertexShader =
"#version 400 core\n"
"\n"
"layout(location = 0) in vec4 position;\n"
"\n"
"void main() \n"
"{\n"
" gl_Position = position;\n"
"}\n";
std::string fragmentShader =
"#version 400 core\n"
"\n"
"layout(location = 0) out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
const char *versionGL;
versionGL = (char *) (glGetString(GL_VERSION));
std::cout << "openGl version: " << versionGL << std::endl;
if(GL_VERSION_4_0)
std::cout << "opengl 4.0 supported" << std::endl;
unsigned int shader = createShader(vertexShader, fragmentShader);
glUseProgram(shader);
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
and that's the precompiled header (prec.h): #pragma once
#ifndef GLEWINIT_PREC_H
#define GLEWINIT_PREC_H
#endif //GLEWINIT_PREC_H
#include "GL/glew.h"
#include <GLFW/glfw3.h>
#include <iostream>
the program prints that to the console ("OpenGL 4.0 supported" means that GL_VERSION_4_0 == true):
openGl version: 2.1 INTEL-14.5.22
opengl 4.0 supported
When I try to run it I get this error message from the shader Compiler for my vertex and fragment shader:
ERROR: 0:1: '' : version '400' is not supported
ERROR: 0:1: '' : syntax error: #version
ERROR: 0:3: 'layout' : syntax error: syntax error
When I change the #version 400 core to #version 120 I only get the syntax error for the layout. Because of that I think I messed up something with glew. What could I try?
Your system does not support OpenGL 4.0. It just supports OpenGL 2.1. See the output
openGl version: 2.1 INTEL-14.5.22
GLSL 1.20 corresponds to OpenGL 2.1. Downgrade the shader:
Vertex shader
#version 120
attribute vec4 position;
void main()
{
gl_Position = position;
}
Fragment shader
#version 120
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
Respectively using Raw string literals (C++11):
std::string vertexShader =
R"(#version 120
attribute vec4 position;
void main()
{
gl_Position = position;
}
)";
std::string fragmentShader =
R"(#version 120
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
)";
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().
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;
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\
}";