I'm trying to implement tonemap correction in my own graphic engine and I'm using, as reference, the excellent demo from asylum2010 (https://github.com/asylum2010/Asylum_Tutorials)
Now look: this is an adaptation of the shader taken from the aforesaid demo:
#version 150
uniform sampler2D sampler0;
uniform vec2 texelSize;
uniform int prevLevel;
in vec2 tex;
out vec4 my_FragColor0;
void main()
{
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721);
vec4 sample = texture(sampler0, tex + vec2(-0.5, -0.5) * texelSize);
float dt = dot(sample.rgb, LUMINANCE_VECTOR);
if (sample.r > 0.99 && sample.g > 0.99 && sample.b > 0.99)
{
if (dt > 0.9998)
{
if (log(0.0001 + dt) < 1.0) // <== NOTICE THIS!
my_FragColor0 = vec4(0.1, 0.0, 0.0, 1.0);
else
my_FragColor0 = vec4(1.0, 0.0, 0.0, 1.0);
}
else
my_FragColor0 = vec4(0.0, 0.0, 0.0, 1.0);
}
else
my_FragColor0 = vec4(0.0, 0.0, 0.0, 1.0);
}
and this is the shader I wrote:
#version 150
uniform sampler2D ColorMap;
uniform vec2 TexelSize;
uniform int PreviousLevel;
in vec2 fragmentUV;
out vec4 fragment;
void main()
{
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721);
vec4 sample = texture(ColorMap, fragmentUV + vec2(-0.5, -0.5) * TexelSize);
float dt = dot(sample.rgb, LUMINANCE_VECTOR);
if (sample.r > 0.99 && sample.g > 0.99 && sample.b > 0.99)
{
if (dt > 0.9998)
{
if (log(0.0001 + dt) < 1.0) // <== NOTICE THIS!
fragment = vec4(0.1, 0.0, 0.0, 1.0);
else
fragment = vec4(1.0, 0.0, 0.0, 1.0);
}
else
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
else
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
You may notice that, except for the variable names, the code is exactly the same.
Now when I run the first shader on its own engine, it outputs a full red color for almost white pixels of the passed sampler is almost white (r, g and b > 0.99), meaning the result of the log calculation is greater than 1.0
When I run my own shader (of course passing the same sample and with the same texel size), it outputs a dark red, meaning the log result is lower than 1.0.
It looks to me that the result of the second shader is correct but this is not the point. The point is: how coult the result be different?
Ok for the ones interested I finally found the issue.
The error is actually the dot product. I was passing as ColorMap a texture with internal format GL_RGBA while it is supposed to be a floating point texture in order to store values higher than 1.
Also I would like to know the reason of the downvote I received. Knowing the reason will help me to avoid any mistake I possibly made posting the question.
Related
Here is a picture of the program running:
I can't figure out why my plane is getting a bullseye coloring, I'm pretty sure I'm doing something wrong with the shaders but I'm not entirely sure what's the problem.
this is my fragment shader.
#version 430 core
in vec4 color;
in vec4 position;
uniform float fTime;
uniform vec3 lookat;
out vec4 fColor;
vec4 calculateMyNormal(vec4 mposition)
{
float dfdx = 2*(mposition.x) * 4 * cos(radians((mposition.x*mposition.x)+ (mposition.z*mposition.z)+fTime));
float dfdz = 2*(mposition.z) * 4 * cos(radians((mposition.x*mposition.x)+(mposition.z*mposition.z)+fTime));
vec3 a = vec3(1, dfdx, 0);
vec3 b = vec3(0, dfdz, 1);
vec3 normal = normalize(cross(a, b));
return vec4(normal, 1.0);
}
vec4 ADSLightModel(vec4 myNormal, vec4 myPosition)
{
const vec4 myLightPosition = vec4(1.0, 0.5, 0.0, 1.0 );
const vec4 myLightAmbient = vec4( 0.2, 0.2, 0.2, 1.0 );
const vec4 myLightDiffuse = vec4( 1.0 , 1.0 , 1.0, 1.0 );
const vec4 myLightSpecular = vec4( 1.0 , 1.0 , 1.0 , 1.0);
const vec4 myMaterialAmbient = vec4( 1.0 , 0.5, 0.0, 1.0 );
const vec4 myMaterialDiffuse = vec4( 0.5 , 0.1, 0.5, 1.0 );
const vec4 myMaterialSpecular = vec4( 0.6, 0.6, 0.6, 1.0 );
const float myMaterialShininess = 80;
vec4 norm = normalize( myNormal );
vec4 lightv = normalize( myLightPosition - myPosition );
vec4 viewv = normalize( vec4(lookat, 1.0) - myPosition );
vec4 refl = reflect( vec4(lookat, 1.0) - lightv, norm );
vec4 ambient = myMaterialAmbient*myLightAmbient;
vec4 diffuse = max(0.0, dot(lightv, norm)) * myMaterialDiffuse * myLightDiffuse;
vec4 specular = vec4( 0.0, 0.0, 0.0, 1.0 );
if( dot(lightv, viewv) > 0)
{
specular = pow(max(0.0, dot(viewv,refl)), myMaterialShininess)*myMaterialSpecular* myLightSpecular;
}
return clamp(ambient + diffuse + specular, 0.0, 1.0);
}
void main()
{
vec4 norml = calculateMyNormal(position);
fColor = ADSLightModel(norml, position);
}
the plane moves and I do that in the vertex shader, I don't know if that might be the problem.
#version 430 core
layout (location = 0) in vec4 vPosition;
uniform float fTime;
uniform mat4 mTransform;
out vec4 color;
out vec4 position;
float calculaY(float x, float z, float time)
{
return 0.5 * sin(time + (x*x + z*z) / 50.0);
}
void main()
{
vec4 vNewpos = vPosition;
vNewpos.y = calculaY(vNewpos.x, vNewpos.z, fTime);
color = vec4(0.0, 0.0, 1.0, 1.0);
position = vNewpos;
gl_Position = mTransform * vNewpos;
}
The last thing I can imagine being wrong, would be the normals, but I'm using a the code of my teacher to generate the plane and his plane had a solid color all over the plane so either he did something wrong and fixed it or as I think, the problem is in my shaders.
Your reflection vector does not really make sense:
vec4 refl = reflect( vec4(lookat, 1.0) - lightv, norm );
There are a couple of things which should make you suspicious:
refl is not normalized. The reflect operation will preserve the length of the input vector, but the input vec4(lookat, 1.0) - lightv is not normalized.
The value of vec4(lookat, 1.0) - lightv references a point, not a direction vector, since it is the difference between a point and another direction vector.
The term vec4(lookat, 1.0) - lightv does not make sense geometrically. What you want is the reflection of the light incidence vector lightv around the normal. The viewing position is totally irrelevant for determining the direction an incident light ray will be reflected to at some surface point.
The reflection vector should just be:
refl = reflect(lightv, normal);
I'm trying to do point source directional lighting in OpenGL using my textbooks examples. I'm showing a rectangle centered at the origin, and doing the lighting computations in the shader. The rectangle appears, but it is black even when I try to put colored lights on it. Normals for the rectangle are all (0, 1.0, 0). I'm not doing any non-uniform scaling, so the regular model view matrix should also transform the normals.
I have code that sets the light parameters(as uniforms) and material parameters(also as uniforms) for the shader. There is no per vertex color information.
void InitMaterial()
{
color material_ambient = color(1.0, 0.0, 1.0);
color material_diffuse = color(1.0, 0.8, 0.0);
color material_specular = color(1.0, 0.8, 0.0);
float material_shininess = 100.0;
// set uniforms for current program
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialAmbient"), 1, material_ambient);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialDiffuse"), 1, material_diffuse);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialSpecular"), 1, material_specular);
glUniform1f(glGetUniformLocation(Programs[lightingType], "shininess"), material_shininess);
}
For the lights:
void InitLight()
{
// need light direction and light position
point4 light_position = point4(0.0, 0.0, -1.0, 0.0);
color light_ambient = color(0.2, 0.2, 0.2);
color light_diffuse = color(1.0, 1.0, 1.0);
color light_specular = color(1.0, 1.0, 1.0);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightPosition"), 1, light_position);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightAmbient"), 1, light_ambient);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightDiffuse"), 1, light_diffuse);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightSpecular"), 1, light_specular);
}
The fragment shader is a simple pass through shader that sets the color to the one input from the vertex shader. Here is the vertex shader :
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
uniform vec4 materialAmbient, materialDiffuse, materialSpecular;
uniform vec4 lightAmbient, lightDiffuse, lightSpecular;
uniform float shininess;
uniform mat4 modelView;
uniform vec4 lightPosition;
uniform mat4 projection;
void main()
{
// Transform vertex position into eye coordinates
vec3 pos = (modelView * vPosition).xyz;
vec3 L = normalize(lightPosition.xyz - pos);
vec3 E = normalize(-pos);
vec3 H = normalize(L + E);
// Transform vertex normal into eye coordinates
vec3 N = normalize(modelView * vec4(vNormal, 0.0)).xyz;
// Compute terms in the illumination equation
vec4 ambient = materialAmbient * lightAmbient;
float Kd = max(dot(L, N), 0.0);
vec4 diffuse = Kd * materialDiffuse * lightDiffuse;
float Ks = pow(max(dot(N, H), 0.0), shininess);
vec4 specular = Ks * materialSpecular * lightSpecular;
if(dot(L, N) < 0.0) specular = vec4(0.0, 0.0, 0.0, 1.0);
gl_Position = projection * modelView * vPosition;
color = ambient + diffuse + specular;
color.a = 1.0;
}
Ok, it's working now. The solution was to replace glUniform3fv with glUniform4fv, I guess because the glsl counterpart is a vec4 instead of a vec3. I thought that it would be able to recognize this and simply add a 1.0 to the end, but no.
I'm trying to get a sun shader to work, but I can't get it to work.
What I currently get is a quarter of a circle/elipsis on the lower left of my screen, that is really stuck to my screen (if I move the camera, it also moves).
All I do is render two triangles to form a screen-covering quad, with screen width and height in uniforms.
Vertex Shader
#version 430 core
void main(void) {
const vec4 vertices[6] = vec4[](
vec4(-1.0, -1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4(1.0, 1.0, 1.0, 1.0),
vec4(1.0, 1.0, 1.0, 1.0),
vec4(1.0, -1.0, 1.0, 1.0),
vec4(-1.0, -1.0, 1.0, 1.0)
);
gl_Position = vertices[gl_VertexID];
}
Fragment Shader
#version 430 core
layout(location = 7) uniform int screen_width;
layout(location = 8) uniform int screen_height;
layout(location = 1) uniform mat4 view_matrix;
layout(location = 2) uniform mat4 proj_matrix;
out vec4 color;
uniform vec3 light_pos = vec3(-20.0, 7.5, -20.0);
void main(void) {
//calculate light position in screen space and get x, y components
vec2 screen_space_light_pos = (proj_matrix * view_matrix * vec4(light_pos, 1.0)).xy;
//calculate fragment position in screen space
vec2 screen_space_fragment_pos = vec2(gl_FragCoord.x / screen_width, gl_FragCoord.y / screen_height);
//check if it is in the radius of the sun
if (length(screen_space_light_pos - screen_space_fragment_pos) < 0.1) {
color = vec4(1.0, 1.0, 0.0, 1.0);
}
else {
discard;
}
}
What I think it does:
Get the position of the sun (light_pos) in screen space.
Get the fragment position in screen space.
If the distance between them is below a certain value, draw fragment with yellow color;
Else discard.
screen_space_light_pos is not yet in clip space. You've missed perspective division:
vec3 before_division = (proj_matrix * view_matrix * vec4(light_pos, 1.0)).xyw;
vec2 screen_space_light_pos = before_division.xy / before_division.z;
With common proj_matrix configurations, screen_space_light_pos will be in [-1,1]x[-1,1]. To match screen_space_fragment_pos range, you probably need to adjust screen_space_light_pos:
screen_space_light_pos = screen_space_light_pos * 0.5 + 0.5;
I'm working on some basic lighting in my application, and am unable to get a simple light to work (so far..).
Here's the vertex shader:
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 pvmMatrix;
uniform mat3 normalMatrix;
in vec3 in_Position;
in vec2 in_Texture;
in vec3 in_Normal;
out vec2 textureCoord;
out vec4 pass_Color;
uniform LightSources {
vec4 ambient = vec4(0.5, 0.5, 0.5, 1.0);
vec4 diffuse = vec4(0.5, 0.5, 0.5, 1.0);
vec4 specular = vec4(0.5, 0.5, 0.5, 1.0);
vec4 position = vec4(1.5, 7, 0.5, 1.0);
vec4 direction = vec4(0.0, -1.0, 0.0, 1.0);
} lightSources;
struct Material {
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
Material mymaterial = Material(
vec4(1.0, 0.8, 0.8, 1.0),
vec4(1.0, 0.8, 0.8, 1.0),
vec4(1.0, 0.8, 0.8, 1.0),
0.995
);
void main() {
gl_Position = pvmMatrix * vec4(in_Position, 1.0);
textureCoord = in_Texture;
vec3 normalDirection = normalize(normalMatrix * in_Normal);
vec3 lightDirection = normalize(vec3(lightSources.direction));
vec3 diffuseReflection = vec3(lightSources.diffuse) * vec3(mymaterial.diffuse) * max(0.0, dot(normalDirection, lightDirection));
/*
float bug = 0.0;
bvec3 result = equal( diffuseReflection, vec3(0.0, 0.0, 0.0) );
if(result[0] && result[1] && result[2]) bug = 1.0;
diffuseReflection.x += bug;
*/
pass_Color = vec4(diffuseReflection, 1.0);
}
And here's the fragment shader:
#version 150 core
uniform sampler2D texture;
in vec4 pass_Color;
in vec2 textureCoord;
void main() {
vec4 out_Color = texture2D(texture, textureCoord);
gl_FragColor = pass_Color;
//gl_FragColor = out_Color;
}
I'm rendering a textured wolf to the screen as a test. If I change the fragment shader to use out_Color, I see the wolf rendered properly. If I use the pass_Color, I see nothing on the screen.
This is what the screen looks like when I use out_Color in the fragment shader:
I know the diffuseReflection vector is full of 0's, by uncommenting this code in the vertex shader:
...
/*
float bug = 0.0;
bvec3 result = equal( diffuseReflection, vec3(0.0, 0.0, 0.0) );
if(result[0] && result[1] && result[2]) bug = 1.0;
diffuseReflection.x += bug;
*/
...
This will make the x component of the diffuseReflection vector 1.0, which turns the wolf red.
Does anyone see anything obvious I'm doing wrong here?
As suggested in the comments, try debugging incrementally. I see a number of ways your shader could be wrong. Maybe your normalMatrix isn't being passed properly? Maybe your in_Normal isn't mapped to the appropriate input? Maybe when you're casting lightSources.direction to a vec3, the compiler's doing something funky? Maybe your shader isn't even running at all, but you think it is? Maybe you have geometry or tessellation units and it's not passing correctly?
No one really has a chance of answering this correctly. As for me, it looks fine--but again, any of the factors above could happen--and probably more.
To debug this, you need to break it down. As suggested in the comments, try rendering the normals. Then, you should try rendering the light direction. Then render your n dot l term. Then multiply by your material parameters, then by your texture. Somewhere along the way you'll figure out the problem. As an additional tip, change your clear color to something other than black so that any black-rendered objects stand out.
It's worth noting that the above advice--break it down--is applicable to all things debugging, not just shaders. As I see it, you haven't done so here.
i want to shade the quad with checkers:
f(P)=[floor(Px)+floor(Py)]mod2.
My quad is:
glBegin(GL_QUADS);
glVertex3f(0,0,0.0);
glVertex3f(4,0,0.0);
glVertex3f(4,4,0.0);
glVertex3f(0,4, 0.0);
glEnd();
The vertex shader file:
varying float factor;
float x,y;
void main(){
x=floor(gl_Position.x);
y=floor(gl_Position.y);
factor = mod((x+y),2.0);
}
And the fragment shader file is:
varying float factor;
void main(){
gl_FragColor = vec4(factor,factor,factor,1.0);
}
But im getting this:
It seems that the mod function doeasn't work or maybe somthing else...
Any help?
It is better to calculate this effect in fragment shader, something like that:
vertex program =>
varying vec2 texCoord;
void main(void)
{
gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);
gl_Position = sign(gl_Position);
texCoord = (vec2(gl_Position.x, gl_Position.y)
+ vec2(1.0)) / vec2(2.0);
}
fragment program =>
#extension GL_EXT_gpu_shader4 : enable
uniform sampler2D Texture0;
varying vec2 texCoord;
void main(void)
{
ivec2 size = textureSize2D(Texture0, 0);
float total = floor(texCoord.x * float(size.x)) +
floor(texCoord.y * float(size.y));
bool isEven = mod(total, 2.0) == 0.0;
vec4 col1 = vec4(0.0, 0.0, 0.0, 1.0);
vec4 col2 = vec4(1.0, 1.0, 1.0, 1.0);
gl_FragColor = (isEven) ? col1 : col2;
}
Output =>
Good luck!
Try this function in your fragment shader:
vec3 checker(in float u, in float v)
{
float checkSize = 2;
float fmodResult = mod(floor(checkSize * u) + floor(checkSize * v), 2.0);
float fin = max(sign(fmodResult), 0.0);
return vec3(fin, fin, fin);
}
Then in main you can call it using :
vec3 check = checker(fs_vertex_texture.x, fs_vertex_texture.y);
And simply pass x and y you are getting from vertex shader. All you have to do after that is to include it when calculating your vFragColor.
Keep in mind that you can change chec size simply by modifying checkSize value.
What your code does is calculate the factor 4 times (once for each vertex, since it's vertex shader code) and then interpolate those values (because it's written into a varying varible) and then output that variable as color in the fragment shader.
So it doesn't work that way. You need to do that calculation directly in the fragment shader. You can get the fragment position using the gl_FragCoord built-in variable in the fragment shader.
May I suggest the following:
float result = mod(dot(vec2(1.0), step(vec2(0.5), fract(v_uv * u_repeat))), 2.0);
v_uv is a vec2 of UV values,
u_repeat is a vec2 of how many times the pattern should be repeated for each axis.
result is 0 or 1, you can use it in mix function to provide colors, for example:
gl_FragColor = mix(vec4(1.0, 1.0, 1.0, 1.0), vec4(0.0, 0.0, 0.0, 1.0) result);
Another nice way to do it is by just tiling a known pattern (zooming out). Assuming that you have a square canvas:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;
uv -= 0.5; // moving the coordinate system to middle of screen
// Output to screen
fragColor = vec4(vec3(step(uv.x * uv.y, 0.)), 1.);
}
Code above gives you this kind of pattern.
Code below by just zooming 4.5 times and taking the fractional part repeats the pattern 4.5 times resulting in 9 squares per row.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fract(fragCoord/iResolution.xy * 4.5);
uv -= 0.5; // moving the coordinate system to middle of screen
// Output to screen
fragColor = vec4(vec3(step(uv.x * uv.y, 0.)), 1.);
}