I have a simply shader creation pipeline. Nothing special. The shader source reads in properly from what I can tell. Originally, I had the shader code in files with a suffix of '.glsl' just because I wanted to, but they are now plain '.txt' files.
After reading in the shader code, I compile the shader and link the shader as well as check the compile status and info log for errors. The actual shader code below doesn't look to me like it has an error considering it't now basically a carbon copy of a simple tutorial you can find online which I'll link if you need it.
I do get an error though, which is "0(1) : error C0104: Unknown pre-processor directive #version330".
This is the same for both the vertex and the fragment shaders, which have an almost identical creation process.
My driver version is [4.6.0 NVIDIA 445.87] as well, so I should be able to use #version 330.
I did also have them both set to '#version 330 core', but I was getting the same error.
This is my program and shader creation process.
struct s_Program
{
uint32_t program, vert, frag;
s_Program()
{
vert = glCreateShader(GL_VERTEX_SHADER);
frag = glCreateShader(GL_FRAGMENT_SHADER);
program = glCreateProgram();
}
bool genVert(const char* fpath)
{
std::fstream file(fpath);
if (!file)
{
logf("[FILE_ERROR] : Failed to read shader file.");
return(false);
}
logf("Reading vert shader.");
const char* source;
std::string newSource, line;
while (file >> line)
{
newSource += line;
}
source = newSource.c_str();
glShaderSource(vert, 1, &source, 0);
glCompileShader(vert);
int comp;
glGetShaderiv(vert, GL_COMPILE_STATUS, &comp);
if (comp == GL_FALSE)
{
int maxLength = 0;
glGetShaderiv(vert, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<char> errorLog(maxLength);
glGetShaderInfoLog(vert, maxLength, &maxLength, &errorLog[0]);
logf(&errorLog[0]);
glDeleteShader(vert);
return(false);
}
glAttachShader(program, vert);
return(true);
}
bool genFrag(const char* fpath)
{
std::fstream file(fpath);
if (!file)
{
logf("[FILE_ERROR] : Failed to read shader file.");
return(false);
}
const char* source;
std::string newSource = "", line;
while (file >> line)
{
newSource += line;
}
source = newSource.c_str();
glShaderSource(frag, 1, &source, 0);
glCompileShader(frag);
int comp;
glGetShaderiv(frag, GL_COMPILE_STATUS, &comp);
if (comp == GL_FALSE)
{
int maxLength = 0;
glGetShaderiv(frag, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<char> errorLog(maxLength);
glGetShaderInfoLog(frag, maxLength, &maxLength, &errorLog[0]);
logf(&errorLog[0]);
glDeleteShader(frag);
return(false);
}
glAttachShader(program, frag);
return(true);
}
void linkProgram()
{
glLinkProgram(program); glDetachShader(program, vert); glDetachShader(program, frag);
glDeleteShader(vert); glDeleteShader(frag);
}
void bindProgram()
{ glUseProgram(program); }
void unbindProgram()
{ glUseProgram(0); }
};
These are my shaders.
// Vertex
#version 330
in vec4 _pos;
out vec4 aColor;
void main()
{
_pos = vec4(_pos, 1.0);
gl_Position = _pos;
}
// Fragment
#version 330
out vec4 FragColor;
in vec4 _color;
void main()
{
_color = vec4(0.5, 0.5, 0.1, 1.0);
FragColor = _color;
}
This is the implementation in the main file.
s_Program mainShader;
if (!mainShader.genVert("data/shaders/standardVert.txt"))
{ logf("[ERR] : Failed to generate Vertex Shader."); }
if (mainShader.genFrag("data/shaders/standardFrag.txt"))
{ logf("[ERR] : Failed to generate Fragment Shader."); }
mainShader.linkProgram();
I then call my function "bindProgram" in my loop witch sets GL to use that program.
I'm clearly missing something, I just want to know what.
Your while (file >> line) loop reads on a word-by-word basis. Appending each word to a string effectively strips all whitespace from your shader.
Instead, do this to read the file as-is into a std::string:
std::stringstream src_ss;
file >> src_ss.rdbuf();
std::string newSource{ src_ss.str() };
Related
I've a weird problem with GLSL shaders. My program seems to not launch or launch successfully depending on the size of my shader files. If I only write a few lines of code in shader files, the program works fine. For example, the program launches successfully with this much code:
vertex.vs:
#version 460 core
layout (location = 0) in vec2 coords;
uniform float u_time;
out vec3 result_color;
void main()
{
vec3 colorA = vec3(0.514f, 0.179f, 0.900f);
vec3 colorB = vec3(0.895f, 0.359f, 0.488f);
gl_Position = vec4(coords, 0.0f, 1.0f);
result_color = colorA;
}
fragment.fs:
#version 460 core
in vec3 result_color;
out vec4 color;
void main()
{
color = vec4(result_color, 1.0f);
}
If I add more code to any of my shader files it only launches about 50% of the time:
vertex.vs:
#version 460 core
layout (location = 0) in vec2 coords;
uniform float u_time;
out vec3 result_color;
// float wave(float x)
// {
// return min(2.0f - 2.0f * fract(x / 2.0f),
// 2.0f * fract(x / 2.0f));
// }
void main()
{
vec3 colorA = vec3(0.514f, 0.179f, 0.900f);
vec3 colorB = vec3(0.895f, 0.359f, 0.488f);
// float frequency = 15.0f;
// float y = wave(coords.x * frequency + cos(u_time) * 5.0f);
// float fr_y = fract(coords.y * frequency + u_time);
gl_Position = vec4(coords, 0.0f, 1.0f);
result_color = colorA;
}
Note that the code I added is commented out but still the error occurs. And the more code I add the less is the chance it works.
Here's the class I use to read shaders from files and create a shader program:
#include <iostream>
#include <fstream>
#include <sstream>
#include <glad/glad.h>
#include "shader_program.h"
ShaderProgram::ShaderProgram(std::string vertexShaderPath, std::string fragmentShaderPath)
{
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::stringstream vShaderStream;
std::stringstream fShaderStream;
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
vShaderFile.open(vertexShaderPath);
vShaderStream << vShaderFile.rdbuf();
}
catch(std::ifstream::failure e)
{
std::cout << "ERROR: FAILED TO READ SHADER FILE: VERTEX SHADER" << std::endl;
}
try
{
fShaderFile.open(fragmentShaderPath);
fShaderStream << fShaderFile.rdbuf();
}
catch(std::ifstream::failure e)
{
std::cout << "ERROR: FAILED TO READ SHADER FILE: FRAGMENT SHADER" << std::endl;
}
const char* vertexShaderSource = vShaderStream.str().c_str();
const char* fragmentShaderSource = fShaderStream.str().c_str();
CreateShaderProgram(vertexShaderSource, fragmentShaderSource);
}
unsigned int ShaderProgram::GetProgram()
{
return program;
}
void ShaderProgram::CreateShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
{
program = glCreateProgram();
unsigned int vertexShader = CompileShader(GL_VERTEX_SHADER, vertexShaderSource);
unsigned int fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
int linkingResult;
glGetProgramiv(program, GL_LINK_STATUS, &linkingResult);
if (linkingResult == GL_FALSE)
{
char infoLog[512];
glGetProgramInfoLog(program, 512, NULL, infoLog);
std::cout << "ERROR: FAILED TO LINK PROGRAM\n" << infoLog << std::endl;
}
}
unsigned int ShaderProgram::CompileShader(GLuint type, const char* source)
{
unsigned int shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
int compilationResult;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compilationResult);
if (compilationResult == GL_FALSE)
{
char infoLog[512];
glGetShaderInfoLog(shader, 512, NULL, infoLog);
std::cout << "ERROR: FAILED TO COMPILE SHADER: "
<< (type == GL_VERTEX_SHADER ? "VERTEX" : "FRAGMENT")
<< " SHADER\n" << infoLog << std::endl;
}
return shader;
}
The error message I get sometimes seems random. Most of the time it's this:
ERROR: FAILED TO LINK PROGRAM
Vertex shader(s) failed to link, fragment shader(s) failed to link.
Vertex link error: INVALID_OPERATION.
ERROR: error(#97) No program main found
fragment link error: INVALID_OPERATION.
ERROR: error(#97) No program main found
But sometimes it's about a syntax error which is nowhere to be found really:
ERROR: FAILED TO COMPILE SHADER: VERTEX SHADER
Vertex shader failed to compile with the following errors:
ERROR: 0:1: error(#132) Syntax error: "0" parse error
ERROR: error(#273) 1 compilation errors. No code generated
ERROR: FAILED TO LINK PROGRAM
Vertex shader(s) were not successfully compiled before glLinkProgram() was called. Link failed.
I use GLFW 3.3.8 and Glad. I started with OpenGL version 3.3 and tried switching to 4.6 which had no effect. Also tried to update my GPU drivers to no success either. I really have no idea where this behaviour may be coming from.
You have undefined behaviour.
vShaderStream.str().c_str();
str() returns string by value. So this temporary string object is destroyed at the end of full expression, and the pointer obtained by c_str() is dangling. As a solution you could do:
CreateShaderProgram(vShaderStream.str().c_str(), fShaderStream.str().c_str());
in case above, string temporaries are still alive when CreateShaderProgram is called.
I am trying to write a function for loading and compiling a shader using OpenGl, but the shader refuses to compile while giving me an empty (or random) error log.
The following is my minimal example:
vertexShader = glCreateShader( GL_VERTEX_SHADER );
std::string vertexSource = ShaderLoader::load("vertexShader.vert");
const char * vertexAdress = vertexSource.c_str();
glShaderSource( vertexShader, 1, &vertexAdress, NULL );
int shaderCompiled = GL_FALSE;
char errorLog[512];
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &shaderCompiled );
glGetShaderInfoLog(vertexShader, 512, nullptr, &errorLog[0]);
glDeleteShader(vertexShader);
Outputting shaderCompiled gives 0 and errorLog gives either an empty string or a few random characters.
The function ShaderLoader::load contains the following code:
std::string ShaderLoader::load(std::string source) {
std::string shader;
std::fstream readFile(source, std::ios::in);
if (readFile.is_open()){
std::stringstream buffer;
buffer << readFile.rdbuf();
shader = buffer.str() + "\0";
} else {
throw std::runtime_error( "Couldn't load shader file: " + source);
}
return shader;
}
It seems to be working as expected. The shader source code is
#version 330 core
layout (location = 0) in vec3 inVertex;
layout (location = 1) in vec3 inNormal;
out vec3 FragmentPosition;
out vec3 Normal;
uniform mat4 transform;
void main()
{
FragmentPosition = vec3(inVertex);
Normal = mat3(transpose(inverse(transform))) * inNormal;
gl_Position = transform * vec4( inVertex, 1 );
}
How can I populate errorLog with an actual error message, or even better, get the shader to compile.
First only use error logging if shaderCompiled is false so you don't get random strings,
glGetShaderiv(VS, GL_COMPILE_STATUS, &shaderCompiled);
if (!shaderCompiled)
{
//error
GLchar InfoLog[256];
glGetShaderInfoLog(vertexShader, sizeof(InfoLog), NULL, InfoLog);
Second, are you actually linking and using the shaders, the problem might not be with the compilation:
// after compilation
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glLinkProgram(shaderProgram);
glDetachShader(shaderProgram, vertexShader);
glDeleteShader(vertexShader);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
I recently started working on Vertex and Fragment shaders in GLEW. For some reason I am getting a failed to compile shader error.
The error I am getting is as follow:
Failed to compile vertex shader: Vertex shader failed to compile with the following errors:
ERROR: 0:3 error (#12) Unexpected qualifier.
ERROR: 0:3 error(#132) Syntax error: "position" parse error
ERROR: error(#273) 2 compilation errors. No code generated.
The text document that contain the code for the shader is:
#version 330 core
layout (location = 0) in Vector4 position;
uniform Matrix pr_matrix;
uniform Matrix vw_matrix = Matrix(1, 0);
uniform Matrix ml_matrix = Matrix(1, 0);
void main()
{
gl_Position = /*pr_matrix **/ position;
}
And the code that compile the shader is:
GLuint Shader::load() {
GLuint program = glCreateProgram();
GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vertexSourceString = File::read_file(mVertex);
std::string fragmentSourceString = File::read_file(mFragment);
const char* vertexSource = vertexSourceString.c_str();
const char* fragmentSource = fragmentSourceString.c_str();
glShaderSource(vertex, 1, &vertexSource, NULL);
glCompileShader(vertex);
GLint result;
glGetShaderiv(vertex, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
GLint length;
glGetShaderiv(vertex, GL_INFO_LOG_LENGTH, &length);
std::vector<char> error(length);
glGetShaderInfoLog(vertex, length, &length, &error[0]);
std::cout << "Failed to compile vertex shader: " << &error[0] << std::endl;
glDeleteShader(vertex);
return 0;
}
glShaderSource(fragment, 1, &fragmentSource, NULL);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
GLint length;
glGetShaderiv(fragment, GL_INFO_LOG_LENGTH, &length);
std::vector<char> error(length);
glGetShaderInfoLog(fragment, length, &length, &error[0]);
std::cout << "Failed to compile fragment shader: " << &error[0] << std::endl;
glDeleteShader(fragment);
return 0;
}
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vertex);
glDeleteShader(fragment);
return program;
}
I think something is wrong with the vertex, if anyone can help I will appreciate it. Thanks.
The strings Vertex4 and Matrix have no meaning for GLSL. Types in GLSL are things like vec4 and mat4
I'm developing a 3d Engine and I got some trouble with the GLSL shader in C++.
Vertex shader:
layout(location = 0) in vec3 vertexUP;
layout(location = 1) in vec3 vertexUV;
out vec3 UP;
out vec3 UV;
void main(){
UP = vertexUP;//Without this line, everything works fine
UV = vertexUV;
gl_Position = ftransform();
}
Fragment shader:
in vec3 UP;
in vec3 UV;
out vec3 color;
uniform sampler2D rs0;
uniform sampler2D rs1;
uniform sampler2D rs2;
void main(){
if(UV[2]==0){//Selects between different textures
color = texture( rs0, vec2(UV[0], UV[1]) ).rgb;
}else if(UV[2]==1){
color = texture( rs1, vec2(UV[0], UV[1]) ).rgb;
}else{
color = texture( rs2, vec2(UV[0], UV[1]) ).rgb;
}
if(UP[0]<2){//Test thing
color[0] = 1.0;
}
}
I want to parse the position array (Location 0) to the fragement shader so I can use it for lighting. It Compiles but linking the vertex shader gives a error:
Vertex shader(s) failed to link, Fragment shader(s) linked.
What am I doing wrong?
EDIT:
The code to load the shaders:
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();
}
// 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(InfoLogLength);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
You can't do that:
layout(location = 0) in vec3 vertexUP;
layout(location = 1) in vec3 vertexUV;
...
gl_Position = ftransform();
ftransform() uses the builtin gl_Vertex, and the GL spec requires that to alias attribute index 0, so the GL cannot assign the attribute indices without collision.
You really shouldn't mix the old, deprecated builtins with generic attributes. And if you do, you should led the GL assign the attribute locations.
I'm trying to compile a shader program in OpenGL 3.2, but I'm getting a strange linking error.
After creating the vertex and fragment shaders compiling and attaching them, I try to link them into a program but I get the following infolog error:
ERROR: Compiled vertex shader was corrupt.
ERROR: Compiled fragment shader was corrupt.
I have absolutely no idea what it means and the only thing I could find on google was to ignore it. However, when I glUseProgram() it I get an invalid operation, so I can't just ignore this error.
Moreover, I just updated to XCode 5 and the very same code/shader source was working. Don't know how it can be related though..
Edit: shader source
Vertex:
#version 150
in vec3 position;
uniform mat4 worldMatrix;
uniform float time;
out vec3 outPos;
void main(){
gl_Position = worldMatrix*vec4(position, 1.0);
outPos = position;
}
Fragment:
#version 150
out vec4 outColor;
uniform float time;
uniform float red;
uniform float green;
uniform float blue;
void main(){
outColor=vec4(red, green, blue,1.0);
}
Got it to work.
At first I rewrote the shaders with another editor (text mate) and then it worked sometimes. Then I made sure that it was properly null terminated and it worked every time.
Maybe somehow there were non-printing characters like Andon M. Coleman suggested.
I had the same issue, and discovered that if you use the ' std::stringstream buffer' to read the file, as many code examples on the web use, the method .str().c_str() to get a *ptr needed for glShaderSource, the pointer gets deleted, meaning, you get random linker errors. Here is the work around I created...
int shaderFromFile(const std::string& filePath, GLenum shaderType) {
//open file
std::ifstream f;
f.open(filePath.c_str(), std::ios::in);
if(!f.is_open()){
throw std::runtime_error(std::string("Failed to open file: ") + filePath);
}
//read whole file into stringstream buffer
std::stringstream buffer;
buffer << f.rdbuf();
buffer << "\0";
f.close();
// need to copy, as pointer is deleted when call is finished
std::string shaderCode = buffer.str().c_str();
//create new shader
int ShaderID = glCreateShader(shaderType);
//set the source code
const GLchar* code = (const GLchar *) shaderCode.c_str();
glShaderSource(ShaderID, 1, &code, NULL);
//compile
glCompileShader(ShaderID);
//throw exception if compile error occurred
GLint status;
glGetShaderiv(ShaderID, GL_COMPILE_STATUS, &status);
std::cout << "Status from compile:" << status << "\r\n";
if (status == GL_FALSE) {
std::string msg("Compile failure in shader:\n");
GLint infoLogLength;
glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
char* strInfoLog = new char[infoLogLength + 1];
glGetShaderInfoLog(ShaderID, infoLogLength, NULL, strInfoLog);
msg += strInfoLog;
delete[] strInfoLog;
glDeleteShader(ShaderID); ShaderID = 0;
throw std::runtime_error(msg);
}
return ShaderID;
}