I'm trying to write a set of shaders to do per-vertex lighting with multiple lights, and textures. I think I'm running into the shader compiler optimizing out 'v_texture', one of my attribute variables, because glVertexAttribLocation is failing to find it.
Here's my vertex shader code:
attribute vec3 v_position;
attribute vec3 v_normal;
attribute vec2 v_texture;
varying vec4 color;
varying vec2 texCoord;
const int MAX_LIGHTS = 8;
uniform struct lightSource
{
vec4 position;
vec4 color;
vec3 coneDirection;
float coneAngle;
float ambientFactor;
} sceneLights[MAX_LIGHTS];
uniform mat4 modelView;
uniform mat4 Projection;
uniform float shininess;
uniform int numLights;
vec4 applyLight(lightSource light)
{
vec4 outColor;
float attenuation;
vec3 surfacePos = (modelView * vec4(v_position.xyz, 1.0)).xyz;
vec3 toLight;
if(light.position.w == 0.0)
{
toLight = normalize(light.position.xyz);
attenuation = 1.0;
}
else
{
toLight = normalize(light.position.xyz - surfacePos);
float distanceToLight = length(light.position.xyz - surfacePos);
float lightAngle = degrees(acos(dot(-surfacePos, normalize(light.coneDirection))));
if(lightAngle > light.coneAngle)
{
attenuation = 0.0;
}
else
{
attenuation = 1.0/(1.0 + (0.1 * pow(distanceToLight, 2.0)));
}
}
vec3 Eye = normalize(-surfacePos);
vec3 Halfway = normalize(toLight + Eye);
vec3 worldNormal = normalize(modelView * vec4(v_normal, 0.0)).xyz;
vec4 ambient = vec4(light.ambientFactor * vec3(light.color.xyz), 1.0);
float Kd = max(dot(toLight, worldNormal), 0.0);
vec4 diffuse = Kd * light.color;
float Ks = pow(max(dot(worldNormal, Halfway), 0.0), shininess);
vec4 specular = Ks * light.color;
if(dot(toLight, worldNormal) < 0.0)
{
specular = vec4(0.0, 0.0, 0.0, 0.0);
}
outColor = ambient + (attenuation * (diffuse + specular));
outColor.a = 1.0;
return outColor;
}
void main(void)
{
vec4 colorSum;
colorSum = vec4(0, 0, 0, 0);
for(int i = 0; i < MAX_LIGHTS; i++)
{
if(i >= numLights)
{
break;
}
colorSum += applyLight(sceneLights[i]);
}
colorSum.xyzw = normalize(colorSum.xyzw);
vec3 gammaCorrection = vec3(1.0/2.2);
color = vec4(pow(vec3(colorSum.xyz), gammaCorrection), 1.0);
texCoord = v_texture;
gl_Position = Projection * modelView * vec4(v_position.xyz, 1.0);
}
And the fragment shader:
varying vec4 color;
varying vec2 texCoord;
uniform sampler2D texSampler;
void main(void)
{
gl_FragColor = (color * texture2D(texSampler, texCoord.xy));
}
I've been over the code top to bottom but I just can't see where my problem is. I'm assigning v_texture to the texCoord, and passing it to the frag shader, where I'm using it together with the final lighting result from the vertex shader to yield the final color. I'm checking for shader errors when I compile them, and I'm not getting anything. My only guess at the moment is that maybe gl_FragColor = (color * texture2D(texSampler, texCoord.xy)) isn't a valid statement, but then shouldn't this have caught it?
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &shader_status);
if (!shader_status)
{
GLchar InfoLog[1024];
glGetShaderInfoLog(fragment_shader, sizeof(InfoLog), NULL, InfoLog);
fprintf(stderr, "Fragment Shader %d: '%s'\n", fragment_shader, InfoLog);
}
Edit: I probably should have put this in here in the first place, but this snippet is the shader section from my C++ program's initialize() function. The only one of the glGetAttribLocation calls to fail is for v_texture.
// Begin shader loading.
//compile the shaders
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
GLint shader_status;
pass=new char [2048];
unsigned int len;
//Give a maximum number of attempts to load the vertex shader
int attempts=10;
//Load the vertex shader
do
{
loader.load("lighting.vsh");
shaderCode = loader.hold.c_str();
len=loader.length;
pass=shaderCode;
attempts-=1;
}
while(len!=pass.length()&& attempts>0);
//Pass the temperary variable to a pointer
tmp = pass.c_str();
// Vertex shader first
glShaderSource(vertex_shader, 1,&tmp, NULL);
glCompileShader(vertex_shader);
//check the compile status
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &shader_status);
if (!shader_status)
{
GLchar InfoLog[1024];
glGetShaderInfoLog(vertex_shader, sizeof(InfoLog), NULL, InfoLog);
fprintf(stderr, "Vertex Shader %d: '%s'\n", vertex_shader, InfoLog);
}
const char *fs=loader.load("lighting.fsh");
// Now the Fragment shader
glShaderSource(fragment_shader, 1, &fs, NULL);
glCompileShader(fragment_shader);
//check the compile status
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &shader_status);
if (!shader_status)
{
GLchar InfoLog[1024];
glGetShaderInfoLog(fragment_shader, sizeof(InfoLog), NULL, InfoLog);
fprintf(stderr, "Fragment Shader %d: '%s'\n", fragment_shader, InfoLog);
}
//Now we link the 2 shader objects into a program
//This program is what is run on the GPU
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
//check if everything linked ok
glGetProgramiv(program, GL_LINK_STATUS, &shader_status);
if(!shader_status)
{
std::cerr << "[F] THE SHADER PROGRAM FAILED TO LINK" << std::endl;
return false;
}
//Now we set the locations of the attributes and uniforms
//this allows us to access them easily while rendering
loc_position = glGetAttribLocation(program,
const_cast<const char*>("v_position"));
if(loc_position == -1)
{
std::cerr << "Error: POSITION NOT FOUND IN SHADER" << std::endl;
return false;
}
loc_normals = glGetAttribLocation(program, const_cast<const char*>("v_normal"));
if(loc_normals == -1)
{
std::cerr << "Error: NORMALS NOT FOUND IN SHADER" << std:: endl;
return false;
}
loc_texture = glGetAttribLocation(program, const_cast<const char*>("v_texture"));
if(loc_texture == -1)
{
std::cerr << "[F] TEXTURE NOT FOUND IN SHADER" << std::endl;
return false;
}
// Begin light initialization.
Related
I started learning opengl and I'm at the stage of tessellation and I have problem, my triangle won't displaying when I attach tesselation shaders to program. Shaders compile correctly and there is no linking error. Everything seems to be fine from the code side. When i only use vertex shader and fragment shader everything works good. What could be the reason?
Shaders::Shaders(const char* vertexPath, const char* fragmentPath, const char* tessControlPath, const char* tessEvaluationPath)
{
std::string vs_str = load_file(vertexPath);
std::string fs_str = load_file(fragmentPath);
std::string tc_str = load_file(tessControlPath);
std::string te_str = load_file(tessEvaluationPath);
const char* vs_src = vs_str.c_str();
const char* fs_src = fs_str.c_str();
const char* tc_src = tc_str.c_str();
const char* te_src = te_str.c_str();
create_shader(GL_VERTEX_SHADER, vertexShader, vs_src);
create_shader(GL_FRAGMENT_SHADER, fragmentShader, fs_src);
create_shader(GL_TESS_CONTROL_SHADER, tessControlShader, tc_src);
create_shader(GL_TESS_EVALUATION_SHADER, tessEvaluationShader, te_src);
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glAttachShader(program, tessControlShader);
glAttachShader(program, tessEvaluationShader);
glLinkProgram(program);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteShader(tessControlShader);
glDeleteShader(tessEvaluationShader);
glCreateVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
}
void Shaders::create_shader(GLenum type, GLuint& shader, const char* src)
{
GLint isCompiled = 0;
shader = glCreateShader(type);
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> errorLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
for (int i = 0; i < errorLog.size(); i++)
{
std::cerr << errorLog[i];
}
glDeleteShader(shader);
}
}
int main()
{
Window* window = new Window(1200, 1000);
Shaders* shader = new Shaders("shaders/vertex.glsl", "shaders/fragment.glsl", "shaders/tess_control.glsl", "shaders/tess_evaluation.glsl");
while (glfwWindowShouldClose(window->get_window()) == false)
{
window->loop();
const GLfloat color[]{1.0f, 0.5f, 0.5f, 1.0f};
glClearBufferfv(GL_COLOR, 0, color);
const GLfloat attrib[]{0.0f, 0.0f, 1.0f, 1.0f};
glUseProgram(shader->get_program());
glVertexAttrib4fv(0, attrib);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawArrays(GL_PATCHES, 0, 3);
}
delete window;
delete shader;
glfwTerminate();
}
vertex.glsl
#version 450 core
layout (location = 0) in vec4 color;
out VS_OUT
{
vec4 color;
} vs_out;
void main(void)
{
const vec4 vertices[3] = vec4[3](vec4( 0.25, -0.25, 0.5, 1.0), vec4(-0.25, -0.25, 0.5, 1.0), vec4(0.25, 0.25, 0.5, 1.0));
gl_Position = vertices[gl_VertexID];
vs_out.color = color;
}
fragment.glsl
#version 450 core
in VS_OUT
{
vec4 color;
} fs_in;
out vec4 color;
void main(void)
{
color = fs_in.color;
}
tess_control.glsl
#version 450 core
layout (vertices = 3) out;
void main(void)
{
if (gl_InvocationID = 0)
{
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
tess_evaluation.glsl
#version 450 core
layout (triangles, equal_spacing, ccw) in;
void main(void)
{
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position);
}
You have specifies the number of vertices that will be used to make up a single patch primitive, by glPatchParameteri:
glPatchParameteri(GL_PATCH_VERTICES, 3);
glDrawArrays(GL_PATCHES, 0, 3);
Further more you have to pass the color all the way, through all the shader stages, from the vertex shader to the fragment shader:
The input to the Tessellation Control Shader is a patch and the output is patch too. But the input patch size can be different of the output patch size. While the input patch size is defined by GL_PATCH_VERTICES, the output patch size is define by layout (vertices = 3) out. Thus you have to specify, in the shader program, how the attributes of the input patch are mapped to the attributes of the output patch.
#version 450 core
layout (vertices = 3) out;
in VS_OUT
{
vec4 color;
} in_data[];
out VS_OUT
{
vec4 color;
} out_data[];
void main(void)
{
out_data[gl_InvocationID].color = in_data[gl_InvocationID].color;
if (gl_InvocationID = 0)
{
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
The Tessellation Evaluation Shader performs the interpolation. The attributes of the output patch of the tessellation control shader are interpolated dependent on gl_TessCoord.
You have to implement the algorithm which interpolates the attributes in the shader program.
#version 450 core
layout (triangles, equal_spacing, ccw) in;
in VS_OUT
{
vec4 color;
} in_data[];
out VS_OUT
{
vec4 color;
} out_data;
void main(void)
{
out_data.color = in_data[0].color * gl_TessCoord.x + in_data[1].color * gl_TessCoord.y + in_data[2].color * gl_TessCoord.z;
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position);
}
I came up with code to render a rectangle, but the shaders won't work. It still has the blank white color.
Here I will include the important code
Main:
float verts[] = {
-.5f, -.5f, .0f,
-.5f, .5f, .0f,
.5f, .5f, .0f,
.5f, .5f, .0f,
.5f, -.5f, .0f,
-.5f, -.5f, .0f
};
Shader shader("basicVert.glsl", "basicFrag.glsl");
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
shader.enable();
Shader.cpp (class functions)
Shader::Shader(const string vpath, const string fpath) {
Shader();
current_vpath = vpath;
current_fpath = fpath;
shaderID = init();
}
Shader::Shader(const char *vpath, const char *fpath) {
Shader(string(vpath), string(fpath));
}
Shader::~Shader() {
shaderID = NULL;
glDeleteProgram(shaderID);
}
void Shader::enable() {
glUseProgram(shaderID);
}
GLuint Shader::makeVertextShader(const char* source) {
GLuint vertShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertShaderID, 1, &source, NULL);
glCompileShader(vertShaderID);
GLint r;
glGetShaderiv(vertShaderID, GL_COMPILE_STATUS, &r);
if (r == GL_FALSE) {
GLint l;
glGetShaderiv(vertShaderID, GL_INFO_LOG_LENGTH, &l);
cout << l << endl;
char *bfer = new char[l];
glGetShaderInfoLog(vertShaderID, l, &l, bfer);
cerr << "Failed to compile VERTEXT SHADER! FILE NAME: " <<
current_vpath << endl;
cerr << bfer << endl;
glDeleteShader(vertShaderID);
delete[] bfer;
return NULL;
}
return vertShaderID;
}
GLuint Shader::makeFragmentShader(const char* source) {
GLuint fragShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShaderID, 1, &source, NULL);
glCompileShader(fragShaderID);
GLint r;
glGetShaderiv(fragShaderID, GL_COMPILE_STATUS, &r);
if (r == GL_FALSE) {
GLint l;
glGetShaderiv(fragShaderID, GL_INFO_LOG_LENGTH, &l);
char *bfer = new char[l];
glGetShaderInfoLog(fragShaderID, l, &l, bfer);
cerr << "Failed to compile FRAGMENT SHADER! FILE NAME: " <<
current_fpath << endl;
cerr << bfer << endl;
glDeleteShader(fragShaderID);
delete[] bfer;
return NULL;
}
return fragShaderID;
}
GLuint Shader::init() {
GLuint program = glCreateProgram();
const string vs = readFile(current_vpath);
const string vf = readFile(current_fpath);
const char *vertexsrc = vs.c_str();
const char *fragmentsrc = vf.c_str();
GLuint vertShaderID = this->makeVertextShader(vertexsrc);
GLuint fragShaderID = this->makeFragmentShader(fragmentsrc);
glAttachShader(program, vertShaderID);
glAttachShader(program, fragShaderID);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vertShaderID);
glDeleteShader(fragShaderID);
return program;
}
GLSL Vertex Shader
#version 330 core
layout(location = 0) in vec3 position;
void main(){
gl_Position = position;
}
GLSL Fragment Shader
#version 330 core
layout(location = 0) out vec4 color;
void main(){
color = vec4(1.0, 0.0, 1.0, 1.0);
gl_FragColor = color;
}
gl_FragColor is no longer supported in modern versions of GLSL
so it will be in Vertex Shader,
layout(location = 0) in vec4 position;
void main()
{
gl_Position = position;
}
in FS,
layout(location = 0) out vec4 color;
void main()
{
color = vec4(1.0, 0.0, 1.0, 1.0);
//gl_FragColor is no longer supported in modern versions of GLSL
}
The vertex and fragment shader have to look like this:
#version 330 core
layout(location = 0) in vec3 position;
void main()
{
gl_Position = vec4( position.xyz, 1.0 );
}
#version 330 core
layout(location = 0) out vec4 color;
void main()
{
color = vec4(1.0, 0.0, 1.0, 1.0);
}
Explanation:
There are 2 issues in your code:
1.) While the vertex attribute position, in the Vertex Shader has the type vec3, the Built-in Variable (GLSL) gl_Position has the type vec4.
Either the type of the vertex attribute has to be changed:
layout(location = 0) in vec4 position;
or the assignment to gl_Position has to be adapted:
gl_Position = vec4( position.xyz, 1.0 );
2.) In the Fragment Shader either can be used the Built-in output Variable (GLSL) gl_FragColor:
void main()
{
gl_FragColor = [...];
}
or an explicit output variable has to be declared:
out vec4 color;
void main()
{
color = [...];
}
The problem seems to lie in the vertex shader: You pass a vec3 position to a vec4 gl_Position which effectively sets the w-coordinate to 0. What you need for proper rendering is a homogeneous coordinate of 1 (otherwise the division by w is a division by 0). Try to change your code to
gl_Position = vec4(position, 1.0);
I've been staring at this for too long and I'm too new to GLSL to know what is wrong. All I know is that when checking to see if the vertex shader compiles, it says that it could not do so. If someone could help me find out what I've done wrong that would be amazing.
textureShader.vert
#version 140
uniform mat4 mvpMatrix;
attribute vec3 position;
attribute vec2 textCoord;
varying vec2 TextCoord;
varying vec3 lightDir,normal;
void main()
{
normal = normalize(gl_NormalMatrix * gl_Normal);
lightDir = normalize(vec3(gl_LightSource[0].position));
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = position;
}
textureShader.frag
#version 140
uniform sampler2D texUnit;
varying vec2 TextCoord;
varying vec3 lightDir,normal;
void main()
{
vec3 ct,cf;
vec4 texel;
float intensity,at,af;
intensity = max(dot(lightDir,normalize(normal)),0.0);
cf = intensity * (gl_FrontMaterial.diffuse).rgb + gl_FrontMaterial.ambient.rgb;
af = gl_FrontMaterial.diffuse.a;
texel = texture2D(texUnit, TextCoord);
ct = texel.rgb;
at = texel.a;
gl_FragColor = vec4(ct * cf, at * af);
}
What I'm doing to check the compilation. DBOUT is a function to write to the Visual Studio output box.
glCompileShader(shader_vp);
validateShader(shader_vp, vsFile);
GLint compiled;
glGetShaderiv(shader_vp, GL_COMPILE_STATUS, &compiled);
if (!compiled){
DBOUT("Couldn't Compile Vertex Shader: Aborting Mission\n");
abort();
}
glCompileShader(shader_fp);
validateShader(shader_fp, fsFile);
glGetShaderiv(shader_fp, GL_COMPILE_STATUS, &compiled);
if (!compiled){
DBOUT("Couldn't Compile Fragment Shader: Aborting Mission\n");
abort();
}
The output I receive:
Couldn't Compile Vertex Shader: Aborting Mission
Debug Error!
SOLVED
So with everyones help I go this to compile. I had to replace these lines:
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = position;
With these ones:
TextCoord = vec2(textCoord);
gl_Position = mvpMatrix * vec4(position,1.0f);
Thank you everyone!
I didn't look at your shader but you can get an error message from the compiler with something like:
auto error = GLint();
::glGetShaderiv(id, GL_COMPILE_STATUS, &error);
if(error != GL_TRUE)
{
auto length = GLint();
::glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
if(length > 0)
{
auto log = std::vector<GLchar>(length, 0);
::glGetShaderInfoLog(id, length, nullptr, &log[0]);
auto message = std::string(log.begin(), log.end());
...
}
}
One possible error in the shader might be:
gl_Position = position;
The gl_Position should be of type vec4, but the position is an attribute of vec3, you probably forgot to do something like:
gl_Position = mvpMatrix * vec4(position, 1.0f);
I'm testing the triangle tessellation from the link http://prideout.net/blog/?p=48#shaders. All the shader are compiled correctly, but when I try to link the program using the command:
glLinkProgram(programID);
I got the following error:
Tessellation control info
(0): error C6029: No input primitive type
----------------------------------------
Tessellation evaluation info
(0): error c7005: No tessellation primitive mode specified
-----------------------------------------------------------
Geometry info
(0): error C6022: No input primitive type
(0): error C6029: No ouput primitive type
----------------------------------------
Not valid
It's so strange I declare output for TC Shader using command:
layout(vertices = 3) out;
And input layout for TE shader using command:
layout(triangles, equal_spacing, cw) in;
Why I still got this error?
I hope to see you answer about it.
I put my shaders in below:
Vertex shader:
#version 410 core
in vec4 Position;
out vec3 vPosition;
void main()
{
vPosition = Position.xyz;
}
TC shader:
#version 410 core
layout(vertices = 3) out;
in vec3 vPosition[];
out vec3 tcPosition[];
#define ID gl_InvocationID
void main()
{
float TessLevelInner = 3;
float TessLevelOuter = 2;
tcPosition[ID] = vPosition[ID];
if (ID == 0) {
gl_TessLevelInner[0] = TessLevelInner;
gl_TessLevelOuter[0] = TessLevelOuter;
gl_TessLevelOuter[1] = TessLevelOuter;
gl_TessLevelOuter[2] = TessLevelOuter;
}
}
TE Shader:
#version 410 core
//TessEval
layout(triangles, equal_spacing, cw) in;
in vec3 tcPosition[];
out vec3 tePosition;
out vec3 tePatchDistance;
uniform mat4 Projection;
uniform mat4 Modelview;
void main()
{
vec3 p0 = gl_TessCoord.x * tcPosition[0];
vec3 p1 = gl_TessCoord.y * tcPosition[1];
vec3 p2 = gl_TessCoord.z * tcPosition[2];
tePatchDistance = gl_TessCoord;
tePosition = normalize(p0 + p1 + p2);
gl_Position = Projection * Modelview * vec4(tePosition, 1);
}
Geometry shader:
#version 410 core
//geometry shader
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec3 tePosition[3];
in vec3 tePatchDistance[3];
out vec3 gFacetNormal;
out vec3 gPatchDistance;
out vec3 gTriDistance;
uniform mat4 Modelview;
uniform mat3 NormalMatrix;
void main()
{
vec3 A = tePosition[2] - tePosition[0];
vec3 B = tePosition[1] - tePosition[0];
gFacetNormal = NormalMatrix * normalize(cross(A, B));
gPatchDistance = tePatchDistance[0];
gTriDistance = vec3(1, 0, 0);
gl_Position = gl_in[0].gl_Position; EmitVertex();
gPatchDistance = tePatchDistance[1];
gTriDistance = vec3(0, 1, 0);
gl_Position = gl_in[1].gl_Position; EmitVertex();
gPatchDistance = tePatchDistance[2];
gTriDistance = vec3(0, 0, 1);
gl_Position = gl_in[2].gl_Position; EmitVertex();
EndPrimitive();
}
Fragment Shader:
#version 410 core
//fragment shader
out vec4 FragColor;
in vec3 gFacetNormal;
in vec3 gTriDistance;
in vec3 gPatchDistance;
in float gPrimitive;
uniform vec3 LightPosition;
float amplify(float d, float scale, float offset)
{
d = scale * d + offset;
d = clamp(d, 0, 1);
d = 1 - exp2(-2*d*d);
return d;
}
void main()
{
vec3 AmbientMaterial = vec3(0.04f, 0.04f, 0.04f);
vec3 DiffuseMaterial = vec3(0, 0.75, 0.75);
vec3 LightPosition = vec3(0.25, 0.25, 1);
vec3 N = normalize(gFacetNormal);
vec3 L = LightPosition;
float df = abs(dot(N, L));
vec3 color = AmbientMaterial + df * DiffuseMaterial;
float d1 = min(min(gTriDistance.x, gTriDistance.y), gTriDistance.z);
float d2 = min(min(gPatchDistance.x, gPatchDistance.y), gPatchDistance.z);
color = amplify(d1, 40, -0.5) * amplify(d2, 60, -0.5) * color;
FragColor = vec4(color, 1.0);
}
FINALLY, this is the code I set up shader sources:
std::string filename = "shaders//terrain//terrain_TCShader.glsl"
FILE* fp = fopen(fileName.c_str(), "rt");
if (!fp)
return;
// Get all lines from a file
vector<string> sLines;
char sLine[255];
while (fgets(sLine, 255, fp))
sLines.push_back(sLine);
fclose(fp);
const char** sProgram = new const char*[sLines.size()];
for (int i = 0; i < sLines.size(); i++){
sProgram[i] = sLines[i].c_str();
}
//Also for GL_TESS_EVALUATION_SHADER, ..VERTEX, ...FRAGMENT
pShader[st] = glCreateShader(GL_TESS_CONTROL_SHADER);
glShaderSource(pShader[st], 1, (const GLchar**)sProgram, NULL);
glAttachShader(pProgram, pShader[st]);
glCompileShader(pShader[st]);
//==> I tried to check error here but it's ok, the compiler do not notify anything
After compile all the shader, I link the program
glLinkProgram(pProgram);
//And check error again:
glGetProgramiv(pProgram, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(pProgram, infologLength, &charsWritten, infoLog);
}
//I got the error here, as I described above.
I solved the problem. The error is in the code of loading shader.
glShaderSource(pShader[st], 1, (const GLchar**)sProgram, NULL);
I changed 1 to size of the char* array sProgram
I'm making a crossplatform OpenGL program. However, I've encountered a problem, where glGetUniformLocation, which should return the location of a uniform variable in my shader program, returns -1, and it only occurs on Linux (Raspbian distro, ran on Raspberry PI), and on Windows the same code works perfectly! Here's my code:
Load Shader program function:
int shader, status;
programID = glCreateProgram();
// Load vertex shader
shader = LoadShaderFromString(GL_VERTEX_SHADER, Tools::GetFileAsString("VertexShader.glsl"), "Unable to compile vertex shader.\n");
glAttachShader(programID, shader);
// Load pixel shader
shader = LoadShaderFromString(GL_FRAGMENT_SHADER, Tools::GetFileAsString("FilterPixelShader.glsl"), "Unable to compile pixel shader.\n");
glAttachShader(programID, shader);
// Link the program
glLinkProgram(programID);
glGetProgramiv(programID, GL_LINK_STATUS, &status);
if (status == 0)
{
Log("Unable to link filter shader program.\n");
PrintProgramLog(programID);
Fail(); // Quits program
}
// returns -1 here!
frameTextureLocation = glGetUniformLocation(programID, "FrameTextureUnit");
if (frameTextureLocation == -1)
{
int errorCode = glGetError();
Log(string("Error retrieving variable frameTextureLocation from shader program: "));
Log((const char*)glewGetErrorString(errorCode))
Log("!\n");
Fail();
}
LoadShaderFromString:
int Shader::LoadShaderFromString(int type, const string& shaderSource, const string& errorMessage)
{
int shader, status;
const char* programSource;
shader = glCreateShader(type);
programSource = shaderSource.c_str();
glShaderSource(shader, 1, &programSource, nullptr);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == 0)
{
Log(errorMessage);
PrintShaderLog(shader);
Fail();
}
return shader;
}
Lastly, the shader itself:
uniform sampler2D FrameTextureUnit;
uniform sampler2D BackgroundTextureUnit;
#if __VERSION__ >= 130
// Texture coordinate
in vec2 texCoord;
// Final color
out vec4 gl_FragColor;
#else
// Texture coordinate
varying vec2 texCoord;
#endif
uniform float Tolerance; // Tolerance for color difference
uniform vec4 FilterColor; // Color of the filter
void main()
{
vec4 pixel = texture2D(FrameTextureUnit, texCoord);
vec4 background = texture2D(BackgroundTextureUnit, texCoord);
float difference = abs(background.x - pixel.x)
+ abs(background.y - pixel.y)
+ abs(background.z - pixel.z);
if (difference > Tolerance)
{
gl_FragColor = FilterColor;
}
else
{
// Y = 0.2126 R + 0.7152 G + 0.0722 B
float gray = pixel.x * 0.2126 + pixel.y * 0.7152 + pixel.z * 0.0722;
gl_FragColor = vec4(gray, gray, gray, 1);
}
}
Does anyone know why this might be happening? :( It's worth adding that the error handling code:
int errorCode = glGetError();
Log(string("Error retrieving variable frameTextureLocation from shader program: "));
Log((const char*)glewGetErrorString(errorCode));
Prints "Error retrieving variable frameTextureLocation from shader program: No error".
Always specify GLSL version at the top of your shaders, otherwise it defaults to a very old version. It must be the first line. It will also eliminate the need for version checking inline.
#version 150
// rest of shader here