GLSL - Test Fragment Values - glsl

Say you have a vec3 colourIn going from a vertex shader to a frag shader, is there a way to test a value and overwrite it if you want to?
For example, set any fragment that has a blue value larger than 0.5 to the colour white?
In my Shader.frag I implemented this test:
if(colourIn.b>0.5){ //or if(greaterThan(colourIn.b,0.5))
colourIn.b=0.0;
}
It compiles and renders the scene, but I can't tell if it's worked because I'm colourblind (lol)... Have I got the theory right and implemented it correctly?

You could directly write the conditional if you wanted, and your example should be correct, but a smarter move might be something like:
float mixValue = clamp(floor(colourIn.b * 2.0), 0.0, 1.0);
colourIn.b = mix(colourIn.b, 0.0, mixValue);
// the floor will be:
// 0.0 for [0.0 — 0.5);
// 1.0 for [0.5, 1.0)
// 2.0 1.0
//
// so the clamp will make mixValue:
// 0.0 for [0.0, 0.5]
// 1.0 for (0.5, 1.0]
//
// if you were to multiply by 1.99 then you could
// get rid of the clamp but if the input is a
// GLubyte then that'd move 128 into the low group
// instead of the high one
Which avoids the conditional and therefore any related pipeline stalls or parallelisation breakdowns.

Related

normal map not applying correctly

I am currently trying to apply a normal map in my shader but the shading in the final image is way off.
Surfaces that should be shaded are completely bright, surfaces that should be bright are completely shaded and the top surface, which should have the same shade regardless of rotation of the y-axis, is alternating between bright and dark.
After some trial and error i found out that i can get the correct shading by changing this
vec3 normal_viewspace = normal_matrix * normalize((normal_color.xyz * 2.0) - 1.0);
to this
vec3 normal_viewspace = normal_matrix * normalize(vec3(0.0, 0.0, 1.0));
Diffuse and specular lighting are now working correctly,
but obviously without the normal map applied. I honestly have no idea where exactly the error is originating. I am quite new to shader programming and was following this tutorial. Below are the shader sources, with all irrelevant parts cut.
Vertex shader:
#version 450
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 bitangent;
layout(location = 4) in vec2 texture_coordinates;
layout(location = 0) out mat3 normal_matrix;
layout(location = 3) out vec2 texture_coordinates_out;
layout(location = 4) out vec4 vertex_position_viewspace;
layout(set = 0, binding = 0) uniform Matrices {
mat4 world;
mat4 view;
mat4 projection;
} uniforms;
void main() {
mat4 worldview = uniforms.view * uniforms.world;
normal_matrix = mat3(worldview) * mat3(normalize(tangent), normalize(bitangent), normalize(normal));
vec4 vertex_position_worldspace = uniforms.world * vec4(position, 1.0);
vertex_position_viewspace = uniforms.view * vertex_position_worldspace;
gl_Position = uniforms.projection * vertex_position_viewspace;
texture_coordinates_out = texture_coordinates;
}
Fragment shader:
#version 450
layout(location = 0) in mat3 normal_matrix;
layout(location = 3) in vec2 texture_coordinates;
layout(location = 4) in vec4 vertex_position_viewspace;
layout(location = 0) out vec4 fragment_color;
layout(set = 0, binding = 0) uniform Matrices {
mat4 world;
mat4 view;
mat4 projection;
} uniforms;
// ...
layout (set = 0, binding = 2) uniform sampler2D normal_map;
// ...
const vec4 LIGHT = vec4(1.25, 3.0, 3.0, 1.0);
void main() {
// ...
vec4 normal_color = texture(normal_map, texture_coordinates);
// ...
vec3 normal_viewspace = normal_matrix * normalize((normal_color.xyz * 2.0) - 1.0);
vec4 light_position_viewspace = uniforms.view * LIGHT;
vec3 light_direction_viewspace = normalize((light_position_viewspace - vertex_position_viewspace).xyz);
vec3 view_direction_viewspace = normalize(vertex_position_viewspace.xyz);
vec3 light_color_intensity = vec3(1.0, 1.0, 1.0) * 7.0;
float distance_from_light = distance(vertex_position_viewspace, light_position_viewspace);
float diffuse_strength = clamp(dot(normal_viewspace, light_direction_viewspace), 0.0, 1.0);
vec3 diffuse_light = (light_color_intensity * diffuse_strength) / (distance_from_light * distance_from_light);
// ...
fragment_color.rgb = (diffuse_color.rgb * diffuse_light);
fragment_color.a = diffuse_color.a;
}
There are some things i am a bit uncertain about. For example i noticed that in the tutorial, the light is called lightPosition_worldSpace, making me think i need to multiply the light by the world matrix first, but doing so only makes my light rotate with the cube and still doesn't fix my lighting issue.
Any help or ideas on what i could be doing wrong would be greatly appreciated.
I'm the one who created the tutorial site you're referencing.
If possible could you share a link to your normal map as well? When you say that when you changed the line where the normal of the fragment is calculated using the normal map from this
vec3 normal_viewspace = normal_matrix * normalize((normal_color.xyz * 2.0) - 1.0);
to one where you hardcode a value like this
vec3 normal_viewspace = normal_matrix * normalize(vec3(0.0, 0.0, 1.0));
and that fixes the rendering issue, it seems to indicate an issue with the normal map itself.
One way to verify this is to set your entire normal map image to the RGB value (128, 128, 255), which is exactly the same as the vec3(0.0, 0.0, 1.0) value you were using in your changed line. If this results in the object rendering correctly the same as when you were using a hardcoded value, that means you were using a bad normal map.
The normal map is just a texture/image that stores the directions of the normals of your object in "tangent-space" (think of it as like if you had to flatten out your entire object into a 2D surface, and then the normals for each point of that surface is plotted on the map). For each pixel, the red channel represents the X-axis, the green channel represents the Y-axis, and the blue channel represents the Z-axis.
With colors, the range of colors in a normal map goes from (0, 0, 128) to (255, 255, 255) (for images where each color channel uses 8 bits/1 byte), but in GLSL this would be a range from (0.0, 0.0, 0.5) to (1.0, 1.0, 1.0). Let's just work with the range that is used in GLSL for the sake of simplicity.
When looking at the actual possible values for normals, their range actually is (-1.0, -1.0, 0.0) to (1.0, 1.0, 1.0) because you can have a normal direction be either forwards or backwards in either the X-axis or Y-axis.
So when we have a color value of (0.0, 0.0, 0.5), we're actually talking about a normal direction vector (-1.0, -1.0, 0.0). Similarly, a color value of (0.5, 0.5, 0.5) means the normal direction vector (0.0, 0.0, 0.0), and a color value of (1.0, 1.0, 1.0) means a normal value of (1.0, 1.0, 1.0).
So the goal now becomes transforming the value from the normal map from the color value range ((0.0, 0.0, 0.5) to (1.0, 1.0, 1.0)) to the actual range for normals ((-1.0, -1.0, 0.0) to (1.0, 1.0, 1.0)).
If you multiply a value from a normal map by 2.0, you change the possible range of the value from (0.0, 0.0, 0.5) - (1.0, 1.0, 1.0) to (0.0, 0.0, 1.0) - (2.0, 2.0, 2.0). And then if you subtract 1.0 from the result, the range now changes from (0.0, 0.0, 1.0) - (2.0, 2.0, 2.0) to (-1.0, -1.0, 0.0) - (1.0, 1.0, 1.0), which is exactly the possible range of the normals of an object.
So you have to make sure that when you're creating your normal map, the range of the RGB color values is between (0, 0, 128) - (255, 255, 255).
Side note: As for why the range of the blue channel (Z-axis) in the normal map can only be between 128 to 255, a value less than 128 means that a negative value on the Z-axis, meaning that the normal of the fragment is pointing into the surface, not out of it. Since a normal map is supposed to represent the values of the normals when the surface of the object is flattened and facing towards you, having a normal with a negative Z-axis value would mean that at that point the surface is actually facing away from you, which doesn't really make sense, hence why negative values are not allowed.
You could still try having the blue channel be a value less than 128 and see what interesting results pop out.
Also with regards to the doubt you mentioned in the end and in the comments:
What does lightPosition_worldSpace mean?
lightPosition_worldSpace represents the coordinate at which light is present relative to the center of the world (relative to the entire world you're rendering), hence the world-space suffix. You just need to multiply this position with the your view-matrix if you wish to know the position of the light is view-space (relative to your camera).
If you have a coordinate that is relative to the center of the object you're rendering, then you should multiply it with your model matrix (uniforms.world) to transform that coordinate from one that's relative to the center of your model to one that's relative to the center of the world. Since the lightPosition_worldSpace is the position of the light already relative to the center of the world, you don't need to multiply them. This is why you saw the behavior of the light moving with the cube when you did try to do so (the light was moved since its coordinates were thought to be placed relative to the cube itself).
Your comment regarding confusion with the line vec3 view_direction_viewspace = normalize(vertex_position_viewspace.xyz - vec3(0.0, 0.0, 0.0));
This is bad on my part for not representing what vec3(0.0, 0.0, 0.0) is with a variable. This is supposed to represent the position of the camera in view-space. Since in view-space the camera is at the center, its coordinate is vec3(0.0, 0.0, 0.0).
As for why I'm doing
vec3 view_direction_viewspace = normalize(vertex_position_viewspace.xyz - vec3(0.0, 0.0, 0.0));
when
vec3 view_direction_viewspace = normalize(vertex_position_viewspace.xyz);
is simpler and is basically the same thing, I had written it so to make it more obvious what was happening (which it appears I failed to do).
Typically, when you have two coordinates and you want to find the direction from a source coordinate to a destination coordinate you subtract the two coordinates to get their direction + magnitude. By normalizing that difference, you then just the directional component, with the magnitude part removed. So the equation for finding a direction from a source coordinate to a destination coordinate becomes:
direction = normalize(destination coordinate - source coordinate)
view_direction_viewspace Is supposed to represent the direction from the camera towards the fragment. To calculate this, we can just subtract the position of the camera (vec3(0.0, 0.0, 0.0)) from the position of the fragment (vertex_position_viewspace.xyz) and then run normalize(...) on the difference to get that result.
I've generally tried to maintain this consistency where when I'm calculating a direction using two coordinates I always have a destination and source coordinate explicitly written out, hence why you see the line vec3 view_direction_viewspace = normalize(vertex_position_viewspace.xyz - vec3(0.0, 0.0, 0.0)); in the fragment shader code.
I've updated the code by setting vec3(0.0, 0.0, 0.0) to a variable cameraPosition_viewSpace and using that to better clarify this intention.
Feel free to reach out through GitHub issues if you want to ask anything else or help improve the tutorial.
I haven't updated this post in a while because i have completely shifted away from using normal mapping (for now) but still wanted to post an answer, in case that someone else runs into the same problem. I still can't be 100% sure but i am fairly certain, that this behavior was caused by the library i was using to load the normal map. Special thanks to sabarnac who has been a huge help to me in solving this.

Is it possible to pass a GLSL variable to javaScript.

I see that you can pass variables from javaScript to GLSL but is it possible to go the other way around. Basically I have a shader that converts a texture to 3 colors red, green, and blue based on the alpha channel.
if (texture.a == 1.0) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
if (texture.a == 0.0) {
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
call0nce = 1;
}
if (texture.a > 0.0 && texture.a < 1.0) {
"gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);",
}
I have been using the colors to help visualize things better. What I'm really trying to do is pick a random point with with an alpha of 1.0 and a random point with an alpha of 0.0 and output the texture coordinates of both in a way that I can access them from javaScript. How would I go about this?
You can not directly pass values from GLSL back to JavaScript. GLSL, at least in WebGL 1.0, can only output pixels to textures, renderbuffers, and the backbuffer.
You can read the pixels though by calling gl.readPixels so you can indirectly get data from GLSL back into JavaScript by writing the values you want and then calling gl.readPixels.

What exactly happens with alpha colors after blending?

I am working on a test project where one big 3D quad is intersected by several other 3D quads (rotated differently). All quads have transparency (ranging from fully opaque to fully transparent). The small quads never overlap, well, they might, but the camera placement and the Z-buffer make sure that only those parts that may overlap actually overlap.
To render this, I first render the big quad to a different rgba framebuffer for later lookup.
Now I start rendering to the screen. A skybox is first rendered, then the small quads are rendered with alpha blending enabled: GL_SRC_ALHPA and GL_ONE_MINUS_SRC_ALPHA. After that I render the big quad again with alpha blending also enabled this time. Of course, only the pixels in front of the quads will be rendered because of the Z-buffer.
That's why, in the fragment shader of the small quads, I do a raytrace to find the intersection with the big quad. If the intersection point is BEHIND the small quad, I fetch the texel from the originally created framebuffer and blend this texel manually with the calculated small quad texel color.
But the result is not the same: the colors in front are rendered correctly (GPU handles the blending there), the colors behind them are "weird". They are lighter or darker but I never get the same result. After consideration, I think this must be because I am not emitting the correct alpha value from my small-quads shader, so that the GPU performed blending changes the colors even more.
So, how exactly is the alpha value calculated when blending on the GPU when using the above mentioned blending method. In the opengl manual, I find: A * Srgba + (1 - A) * Drgba. When I emit that result, the blending is not the same. I am quite sure that this is because the result is again passing through the GPU blending again.
The ray tracing is correct, I'm certain of that.
So, what should I do with my manual blending?
Or, should I use another method to get the right effect?
Not really necessary I believe, but here is some code (optimization is for later):
vec4 vRayOrg = vec4(0.0, 0.0, 0.0, 1.0);
vec4 vRayDir = vec4(normalize(vBBPosition.xyz), 0.0);
vec4 vPlaneOrg = mView * vec4(0.0, 0.0, 0.0, 1.0);
vec4 vPlaneNormal = mView * vec4(0.0, 1.0, 0.0, 0.0);
float div = dot(vRayDir.xyz, vPlaneNormal.xyz);
float t = dot(vPlaneOrg.xyz - vRayOrg.xyz, vPlaneNormal.xyz) / div;
vec4 pIntersection = vRayOrg + t * vRayDir;
vec3 normal = normalize(vec4(vCoord, 0.0, 0.0)).xyz;
vec3 vLight = normalize(vPosition.xyz / vPosition.w);
float distance = length(vCoord) - 1.0;
float distf = clamp(0.225 - distance, 0.0, 1.0);
float diffuse = clamp(0.25 + dot(-normal, vLight), 0.0, 1.0);
vec4 cOut = diffuse * 9.0 * distf * cGlow;
if (distance > 0.0 && t >= 0.0 && pIntersection.z <= vBBPosition.z)
{
vec2 vTexcoord = (vProjectedPosition.xy / vProjectedPosition.w) * 0.5 + 0.5;
vec4 cLookup = texture(tLookup, vTexcoord);
cOut = cLookup.a * cLookup + (1.0 - cLookup.a) * cOut;
}
vFragColor = cOut;

GLSL Fragment Position

In my .cpp code I create a list of quads, a few of them have a flag, in the pixel shader I check if this flag is set or not, if the flag is not set, the quad gets colored in red for example, if the flag is set, I want to decide the color of every single pixel, so if I need to colour half of the flagged quad in red and the other half in blue I can simply do something like :
if coordinate in quad < something color = red
else colour = blue;
In this way I can get half of the quad colored in blue and another half colored in red, or I can decide where to put the red color or where to put the blue one.
Imagine I've got a quad 50x50 pixels
[frag]
if(quad.flag == 1)
{
if(Pixel_coordinate.x<25 ) gl_fragColor = vec4(1.0, 0.0, 0.0, 1.0);
else gl_fragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
In this case I would expect that a quad with the flag set will get two colors per face.
I hope I have been more specific now.
thanks.
Just to add something I can't use any texture.
Ok i do this now :
Every quad has 4 textures coordinated (0,0), (0,1), (1,1), (1,0);
I enable the texture coordinates using :
glTexCoordPointer(2, GL_SHORT, sizeof(Vertex), BUFFER_OFFSET(sizeof(float) * 7));
[vert]
varying vec2 texCoord;
main()
{
texCoord = gl_MultiTexCoord0.xy;
}
[frag]
varying vec2 texCoord;
main()
{
float x1 = texCoord.s;
float x2 = texCoord.t;
gl_FragColor = vec4(x1, x2, 0.0, 1.0);
}
I get always the yellow color so x1 =1 and x2 = 1 almost always and some quad is yellow/green.
I would expect that the texture coordinates change in the fragment shader and so I should get a gradient, am I wrong?
If you want to know the coordinate within the quad, you need to calculate it yourself. In order to that, you'll need to create a new interpolant (call it something like vec2 quadCoord), and set it appropriately for each vertex, which means you'll likely also need to add it as an attribute and pass it through your vertex shader. eg:
// in the vertex shader
attribute vec2 quadCoordIn;
varying vec2 quadCoord;
main() {
quadCoord = quadCoordIn;
:
You'll need to feed in this attribute in your drawing code when drawing your quads. For each quad, the vertexes will have likely have quadCoordIn values of (0,0), (0,1), (1,1) and (1,0) -- you could use some other coordinate system if you prefer, but this is the easiest.
Then, in your fragment program, you can access quadCoord.xy to determine where in the quad you are.
In addition to Chris Dodd's answer, you can also access the screen-space coordinate (in pixels, though actually pixel centers and thus ?.5) of the currently processed fragment through the special fragment shader variable gl_FragCoord:
gl_FragColor = (gl_FragCoord.x<25.0) ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(0.0, 1.0, 0.0, 1.0);
But this gives you the position of the fragment in screen-space and thus relative to the lower left corner of you viewport. If you actually need to know the position inside the individual quad (which makes more sense if you want to actually color each quad half-by-half, since the "half-cut" would otherwise vary with the quad's position), then Chris Dodd's answer is the correct approach.

Why isn't this orthographic vertex shader producing the correct answer?

My issue is that I have a (working) orthographic vertex and fragment shader pair that allow me to specify center X and Y of a sprite via 'translateX' and 'translateY' uniforms being passed in. I multiply by a projectionMatrix that is hardcoded and works great. Everything works as far as orthographic operation. My incoming geometry to this shader is based around 0, 0, 0 as its center point.
I want to now figure out what that center point (0, 0, 0 in local coordinate space) becomes after the translations. I need to know this information in the fragment shader. I assumed that I can create a vector at 0, 0, 0 and then apply the same translations. However, I'm NOT getting the correct answer.
My question: what I am I doing wrong, and how can I even debug what's going on? I know that the value being computed must be wrong, but I have no insight in to what it is. (My platform is Xcode 4.2 on OS X developing for OpenGL ES 2.0 iOS)
Here's my vertex shader:
// Vertex Shader for pixel-accurate rendering
attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
uniform float translateX;
uniform float translateY;
// Set up orthographic projection
// this is for 640 x 960
mat4 projectionMatrix = mat4( 2.0/960.0, 0.0, 0.0, -1.0,
0.0, 2.0/640.0, 0.0, -1.0,
0.0, 0.0, -1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
void main()
{
// Set position
gl_Position = a_position;
// Translate by the uniforms for offsetting
gl_Position.x += translateX;
gl_Position.y += translateY;
// Translate
gl_Position *= projectionMatrix;
// Do all the same translations to a vector with origin at 0,0,0
vec4 toPass = vec4(0, 0, 0, 1); // initialize. doesn't matter if w is 1 or 0
toPass.x += translateX;
toPass.y += translateY;
toPass *= projectionMatrix;
// this SHOULD pass the computed value to my fragment shader.
// unfortunately, whatever value is sent, isn't right.
//v_translatedOrigin = toPass;
// instead, I use this as a workaround, since I do know the correct values for my
// situation. of course this is hardcoded and is terrible.
v_translatedOrigin = vec4(500.0, 200.0, 0.0, 0.0);
}
EDIT: In response to my orthographic matrix being wrong, the following is what wikipedia has to say about ortho projections, and my -1's look right. because in my case for example the 4th element of my mat should be -((right+left)/(right-left)) which is right of 960 left of 0, so -1 * (960/960) which is -1.
EDIT: I've possibly uncovered the root issue here - what do you think?
Why does your ortho matrix have -1's in the bottom of each column? Those should be zeros. Granted, that should not affect anything.
I'm more concerned about this:
gl_Position *= projectionMatrix;
What does that mean? Matrix multiplication is not commutative; M * a is not the same as a * M. So which side do you expect gl_Position to be multiplied on?
Oddly, the GLSL spec does not say (I filed a bug report on this). So you should go with what is guaranteed to work:
gl_Position = projectionMatrix * gl_Position;
Also, you should use proper vectorized code. You should have one translate uniform, which is a vec2. Then you can just do gl_Position.xy = a_position.xy + translate;. You'll have to fill in the Z and W with constants (gl_Position.zw = vec2(0, 1);).
Matrices in GLSL are column major. The first four values are the first column of the matrix, not the first row. You are multiplying with a transposed ortho matrix.
I have to echo Nicol Bolas's sentiment. Two wrongs happening to make things work is frustrating, but doesn't make them any less wrong. The fact that things are showing up where you expect is likely because the translation portion of your matrix is 0, 0, 0.
The equation you posted is correct, but the notation is row major, and OpenGL is column major:
I run afoul of this stuff every new project I start. This site is a really good resource that helped me keep these things straight. They've got another page on projection matrices.
If you're not sure if your orthographic projection is correct (right now it isn't), try plugging the same values into glOrtho, and reading the values back out of GL_PROJECTION.