GLSL alpha test optimized out on NVIDIA - opengl

I have a small fragment shader on glsl, that is used when I want to render shadow texture. To have the desired shadow from textures with alpha channel (like leaves), alpha test is used.
#version 130
in lowp vec2 UV; //comes from vertex shader, works fine
uniform sampler2D DiffuseTextureSampler; //ok, alpha channel IS present in passed texture
void main(){
lowp vec4 MaterialDiffuseColor = texture( DiffuseTextureSampler, UV ).rgba;
if(MaterialDiffuseColor.a < 0.5)
{
discard;
}
//no color output is required at this stage
}
The following shader works fine on Intel cards (HD 520 && HD Graphics 3000), but on NVIDIA (420M and GTX 660, on Win7 and Linux Mint 17.3 respectively, using the latest drivers, 37x.xx something...) the alpha test does not work. Shader does compile without any errors, so it seems that NVIDIA optimizer is doing weird stuff.
I've copy-pasted parts of 'fullbright' shader to the 'shadow' shader, and got to this odd result, that does work as intended, though a lot of useless stuff (for shadow rendering) is done.
#version 130
in lowp vec2 UV;
in lowp float fade;
out lowp vec4 color;
uniform sampler2D DiffuseTextureSampler;
uniform bool overlayBool;
uniform lowp float translucencyAlpha;
uniform lowp float useImageAlpha;
void main(){
lowp vec4 MaterialDiffuseColor = texture( DiffuseTextureSampler, UV ).rgba;
//notice the added OR :/
if(MaterialDiffuseColor.a < 0.5 || overlayBool)
{
discard;
}
//next line is meaningless
color = vec4(0.0, 0.0, 1.0, min(translucencyAlpha * useImageAlpha, fade));
}
If I remove any uniform, or change something (like, replace the min function with some arithmetic, save the declaration of uniform variable but do not use it etc), the alpha test breaks again.
Just outputting the color does not work (ie color = vec4(1.0, 1.0, 1.0, 1.0); has no effect).
I tried using the
#pragma optimize (off)
but it did not help.
By the way, when alpha test is broken, the expression "MaterialDiffuseColor.a == 0.0" is true.
Sorry, if it is a dumb question, but what causes such behaviour on NVIDIA cards and what can I do to avoid it? Thank you.

Related

OpenGL procedural texture antialiasing

I`ve made a grid using a simple GLSL shader, passing texture coordinates to fragment shader. It was applied onto a large scaled plane.
Fragment shader:
#version 330 core
out vec4 fragColor;
smooth in vec2 f_TexCoord;
vec4 gridColor;
void main()
{
if(fract(f_TexCoord.x / 0.0005f) < 0.025f || fract(f_TexCoord.y / 0.0005f) < 0.025f)
gridColor = vec4(0.75, 0.75, 0.75, 1.0);
else
gridColor = vec4(0);
// Check for alpha transparency
if(gridColor.a != 1)
discard;
fragColor = gridColor;
}
As you can see the lines are not smooth and they start to "flickering" at the horizon.
Is it possible to apply some sort of filtering/antialiasing on it? I've tried to increase number of samples (up to 4, because higher values gives me a qt error), but it has no affect on shader.
Switch to GLSL version 4.20 (at least), activate multisampling and use the Auxiliary Storage Qualifier sample for the vertex shader output (and fragment shader input):
#version 420 core
sample smooth in vec2 f_TexCoord;
The qualifier causes per-sample interpolation.

How to implement a Color Matrix Filter in a GLSL shader

I would like to implement a Color Matrix Filter in a GLSL shader but couldn't find any documentation regarding this matter. I'm totaly new to the world of shaders (never coded one myself) so please forgive me if my explanation/vocabulary doesn't make mush sense.
Informations I could gather so far:
A color matrix is composed of 5 columns (RGBA + offset) and 4 rows
The values in the first four columns are multiplied with the source red, green, blue, and alpha values respectively. The fifth column value is added (offset)
I believe the largest matrices in GLSL are 4×4 mat4 matrices (excluding the 'offset' column)
The only mat4 I've seen implemented in a shader looks like this:
colorMatrix = (GPUMatrix4x4){{0.3588, 0.7044, 0.1368, 0.0},
{0.2990, 0.5870, 0.1140, 0.0},
{0.2392, 0.4696, 0.0912 ,0.0},
{0,0,0,1.0}
};
Question:
How can implement one ? As stated above I've never coded a GLSL shader before and unfortunately I'm unable to provide an MCVE. I would love to see an example so I can learn from it.
Thank you
EDIT:
I'm working with Processing and this is the only example I've found of vertex and fragment shaders for color rendering:
colorvert.glsl:
uniform mat4 transform;
attribute vec4 position;
attribute vec4 color;
varying vec4 vertColor;
void main() {
gl_Position = transform * position;
vertColor = color;
}
colorfrag.glsl:
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 vertColor;
void main() {
gl_FragColor = vertColor;
}
For starters I would try :
Vertex:
#version 410 core
layout(location = 0) in vec3 in_vertex;
layout(location = 3) in vec4 in_color;
out vec4 color;
void main()
{
const mat4x4 m=mat4x4 // RGBA matrix
(
0.3588, 0.7044, 0.1368, 0.0,
0.2990, 0.5870, 0.1140, 0.0,
0.2392, 0.4696, 0.0912 ,0.0,
0.0 , 0.0 , 0.0 ,1.0
);
const vec4 o=vec4(0.0,0.0,0.0,0.0); // offset
color = (m * in_color) + o; // transformation
gl_Position = vec4(in_vertex,1.0);
}
Fragment:
#version 410 core
in vec4 color;
out vec4 out_color;
void main()
{
out_color=color;
}
Just change the #version, layout and input attributes/uniforms to meet your needs (currently it use default nVidia attribute locations for fixed pipeline)
Now to convert image for example just render textured quad on <-1,+1> vertex coordinate x,y range.
If your matrices or colors change inside fragment (for example as a result of some proceduraly generated stuff) than just move the transformation to fragment shader instead.
You can also change the const to uniform (and move it above main) so you can pass custom parameters on the run ...
In case you need a GLSL start example see:
complete GL+GLSL+VAO/VBO C++ example

GLSL ES1.0 and passing texture-unit indices to the fragment shader?

Trying to translate a vertex/frag shader from glsl 330 to glsl es1.0
(Basically taking a step back since the original app was written for a desktop version of OpenGL3.0, but webGL2.0 is still not fully supported by some browsers, like IE or Safari; to my knowledge).
I understand 1.0 is using attribute/varying versus in/out, but I am having an issue that I cannot use integers with varying. There is an array of per-vertex integer values representing a texture unit index for that vertex. I do not see a way to convey that information to the fragment shader. If I send the values as floats it will start interpolating. Right ?
#version 330 //for openGL 3.3
//VERTEX shader
//---------------------------------------------------------------------------------
//uniform variables stay constant for the whole glDraw call
uniform mat4 ProjViewModelMatrix;
uniform mat4 NormalsMatrix;
uniform vec4 DefaultColor;
uniform vec4 LightColor;
uniform vec3 LightPosition;
uniform float LightIntensity;
uniform bool ExcludeFromLight;
//---------------------------------------------------------------------------------
//non-uniform variables get fed per vertex from the buffers
layout (location=0) in vec3 VertexCoord;
layout (location=1) in vec4 VertexColor;
layout (location=2) in vec3 VertexNormal;
layout (location=3) in vec2 VertexUVcoord;
layout (location=4) in int vertexTexUnit;
//---------------------------------------------------------------------------------
//Output variables to fragment shader
out vec4 thisColor;
out vec2 vertexUVcoord;
flat out int TexUnitIdx; // <------ PROBLEM
out float VertLightIntensity;
//---------------------------------------------------------------------------------
void main ()
{ /* ... blah ... */ }
The accompanied fragment shader that needs translation looks like this
#version 330 //for openGL 3.3
//FRAGMENT shader
//---------------------------------------------------------------------------------
//uniform variables
uniform bool useTextures; //If no textures, don't bother reading the TextureUnit array
uniform vec4 AmbientColor; //Background illumination
uniform sampler2D TextureUnit[6]; //Allow up to 6 texture units per draw call
//---------------------------------------------------------------------------------
//non-uniform variables
in vec2 vertexUVcoord;
in vec4 thisColor;
flat in int TexUnitIdx; // <------ PROBLEM
in float VertLightIntensity;
//---------------------------------------------------------------------------------
//Output color to graphics card
out vec4 pixelColor;
//---------------------------------------------------------------------------------
void main ()
{ /* ... blah ... */ }
There are no integer based attributes in GLSL ES 1.0
You can pass in floats (and supply as unsigned bytes) of course. Pass in false for normalize flag when calling gl.vertexAttribPointer
An other hand, neither GLSL ES 1.0 nor GLSL ES 3.00 allow indexing an array of samplers.
From the spec
12.30 Dynamic Indexing
...
Indexing of arrays of samplers by constant-index-expressions is supported in GLSL ES 1.00. A constant-index-expression
is an expression formed from constant-expressions and certain loop indices, defined for
a subset of loop constructs. Should this functionality be included in GLSL ES 3.00?
RESOLUTION: No. Arrays of samplers may only be indexed by constant-integral-expressions.
"Should this functionality be included in GLSL ES 3.00?" means should Dynamic indexing of samplers be included in GLES ES 3.00
I quoted the GLSL ES 3.00 spec since it references the GLSL ES 1.0 spec as well.
So, you have to write code so that your indies are constant-index-expressions.
attribute float TexUnitNdx;
...
uniform sampler2D TextureUnit[6];
vec4 getValueFromSamplerArray(float ndx, vec2 uv) {
if (ndx < .5) {
return texture2D(TextureUnit[0], uv);
} else if (ndx < 1.5) {
return texture2D(TextureUnit[1], uv);
} else if (ndx < 2.5) {
return texture2D(TextureUnit[2], uv);
} else if (ndx < 3.5) {
return texture2D(TextureUnit[3], uv);
} else if (ndx < 4.5) {
return texture2D(TextureUnit[4], uv);
} else {
return texture2D(TextureUnit[5], uv);
}
}
vec4 color = getValueFromSamplerArray(TexUnitNdx, someTexCoord);
or something like that. It might be faster to arrange your ifs into a binary search.

Strange and annoying GLSL error

My vertex shader looks as follows:
#version 120
uniform float m_thresh;
varying vec2 texCoord;
void main(void)
{
gl_Position = ftransform();
texCoord = gl_TexCoord[0].xy;
}
and my fragment shader:
#version 120
uniform float m_thresh;
uniform sampler2D grabTexture;
varying vec2 texCoord;
void main(void)
{
vec4 grab = vec4(texture2D(grabTexture, texCoord.xy));
vec3 colour = vec3(grab.xyz * m_thresh);
gl_FragColor = vec4( colour, 0.5 );
}
basically i am getting the error message "Error in shader -842150451 - 0<9> : error C7565: assignment to varying 'texCoord'"
But I have another shader which does the exact same thing and I get no error when I compile that and it works!!!
Any ideas what could be happening?
For starters, there is no sensible reason to construct a vec4 from texture2D (...). Texture functions in GLSL always return a vec4. Likewise, grab.xyz * m_thresh is always a vec3, because a scalar multiplied by a vector does not change the dimensions of the vector.
Now, here is where things get interesting... the gl_TexCoord [n] GLSL built-in you are using is actually a pre-declared varying. You should not be reading from this in a vertex shader, because it defines a vertex shader output / fragment shader input.
The appropriate vertex shader built-in variable in GLSL 1.2 for getting the texture coordinates for texture unit N is actually gl_MultiTexCoord<N>
Thus, your vertex and fragment shaders should look like this:
Vertex Shader:
#version 120
//varying vec2 texCoord; // You actually do not need this
void main(void)
{
gl_Position = ftransform();
//texCoord = gl_MultiTexCoord0.st; // Same as comment above
gl_TexCoord [0] = gl_MultiTexCoord0;
}
Fragment Shader:
#version 120
uniform float m_thresh;
uniform sampler2D grabTexture;
//varying vec2 texCoord;
void main(void)
{
//vec4 grab = texture2D (grabTexture, texCoord.st);
vec4 grab = texture2D (grabTexture, gl_TexCoord [0].st);
vec3 colour = grab.xyz * m_thresh;
gl_FragColor = vec4( colour, 0.5 );
}
Remember how I said gl_TexCoord [n] is a built-in varying? You can read/write to this instead of creating your own custom varying vec2 texCoord; in GLSL 1.2. I commented out the lines that used a custom varying to show you what I meant.
The OpenGL® Shading Language (1.2) - 7.6 Varying Variables - pp. 53
The following built-in varying variables are available to write to in a vertex shader. A particular one should be written to if any functionality in a corresponding fragment shader or fixed pipeline uses it or state derived from it.
[...]
varying vec4 gl_TexCoord[]; // at most will be gl_MaxTextureCoords
The OpenGL® Shading Language (1.2) - 7.3 Vertex Shader Built-In Attributes - pp. 49
The following attribute names are built into the OpenGL vertex language and can be used from within a vertex shader to access the current values of attributes declared by OpenGL.
[...]
attribute vec4 gl_MultiTexCoord0;
The bottom line is that gl_MultiTexCoord<N> defines vertex attributes (vertex shader input), gl_TexCoord [n] defines a varying (vertex shader output, fragment shader input). It is also worth mentioning that these are not available in newer (core) versions of GLSL.

converting GLSL #130 segment to #330

I have the following piece of shader code that works perfectly with GLSL #130, but I would like to convert it to code that works with version #330 (as somehow the #130 version doesn't work on my Ubuntu machine with a Geforce 210; the shader does nothing). After several failed attempts (I keep getting undescribed link errors) I've decided to ask for some help. The code below dynamically changes the contrast and brightness of a texture using the uniform variables Brightness and Contrast. I have implemented it in Python using PyOpenGL:
def createShader():
"""
Compile a shader that adjusts contrast and brightness of active texture
Returns
OpenGL.shader - reference to shader
dict - reference to variables that can be passed to the shader
"""
fragmentShader = shaders.compileShader("""#version 130
uniform sampler2D Texture;
uniform float Brightness;
uniform float Contrast;
uniform vec4 AverageLuminance;
void main(void)
{
vec4 texColour = texture2D(Texture, gl_TexCoord[0].st);
gl_FragColor = mix(texColour * Brightness,
mix(AverageLuminance, texColour, Contrast), 0.5);
}
""", GL_FRAGMENT_SHADER)
shader = shaders.compileProgram(fragmentShader)
uniform_locations = {
'Brightness': glGetUniformLocation( shader, 'Brightness' ),
'Contrast': glGetUniformLocation( shader, 'Contrast' ),
'AverageLuminance': glGetUniformLocation( shader, 'AverageLuminance' ),
'Texture': glGetUniformLocation( shader, 'Texture' )
}
return shader, uniform_locations
I've looked up the changes that need to made for the new GLSL version and tried changing the fragment shader code to the following, but then only get non-descriptive Link errors:
fragmentShader = shaders.compileShader("""#version 330
uniform sampler2D Texture;
uniform float Brightness;
uniform float Contrast;
uniform vec4 AverageLuminance;
in vec2 TexCoord;
out vec4 FragColor;
void main(void)
{
vec4 texColour = texture2D(Texture, TexCoord);
FragColor = mix(texColour * Brightness,
mix(AverageLuminance, texColour, Contrast), 0.5);
}
""", GL_FRAGMENT_SHADER)
Is there anyone that can help me with this conversion?
I doubt that raising the shader version profile will solve any issue. #version 330 is OpenGL-3.3 and according to the NVidia product website the maximum OpenGL version supported by the GeForce 210 is OpenGL-3.1, i.e. #version 140
I created no vertex shader cause I didn't think I'd need one (I wouldn't know what I should make it do). It worked before without any vertex shader as well.
Probably only as long as you didn't use a fragment shader or before you were attempting to use a texture. The fragment shader needs input variables, coming from a vertex shader, to have something it can use as texture coordinates. TexCoord is not a built-in variable (and with higher GLSL versions any builtin variables suitable for the job have been removed), so you need to fill that with value (and sense) in a vertex shader.
the glGetString(GL_VERSION) on the NVidia machine reads out OpenGL version 3.3.0. This is Ubuntu, so it might be possible that it differs with the windows specifications?
Do you have the NVidia propriatary drivers installed? And are they actually used? Check with glxinfo or glGetString(GL_RENDERER). OpenGL-3.3 is not too far from OpenGL-3.1 and in theory OpenGL major versions map to hardware capabilities.