WebGL GLSL Shader: accessing texture2D overrides other texture - glsl

I have a very disturbing problem with glsl in WebGL.
This shader works as expected:
uniform sampler2D tColor;
uniform sampler2D tNormal;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( tColor, vUv );
}
But this one behaves total different:
uniform sampler2D tColor;
uniform sampler2D tNormal;
varying vec2 vUv;
void main() {
vec4 test = texture2D( tNormal, vUv );
gl_FragColor = texture2D( tColor, vUv );
}
By accessing the tNormal texture, the tColor texture is overridden. How is this possible?

I have seen similar behavior in the past, and it's almost always because I'm binding my textures improperly. The most recent incident was caused when I attempted to bind my textures like so:
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
gl.uniform1i(colorUniform, gl.TEXTURE0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, normalTexture);
gl.uniform1i(normalUniform, gl.TEXTURE1);
When the correct syntax is actually:
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
gl.uniform1i(colorUniform, 0); // 0 to indicate texture unit 0!
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, normalTexture);
gl.uniform1i(normalUniform, 1); // 1 to indicate texture unit 1!
This is a fairly common mistake, and unfortunately WebGL doesn't actually throw an error on the first code snippet (a subject of recent discussion in the WebGL mailing list) and it can appear to work in limited cases, so it's easy to mistakenly think that it's valid code.
I don't know if this is your specific problem, but it's probably the best advice I can provide without further details.

Related

ARB Assembly to GLSL

I have an NVidia example that uses an ARB Assembly shader:
!!ARBfp1.0
TEX result.color, fragment.texcoord, texture[0], RECT;
END
Now I would like to translate that into a GLSL shader. This is what I've come up with:
uniform sampler2D tex;
void main(void)
{
vec4 col = texture2D ( tex, gl_TexCoord[0] );
gl_FragColor = vec4(col.r, col.g, col.b, col.a);
}
I was hoping to see no change in the resulting rendering, but sadly I only get a black texture.
I've already made sure that the tex sampler is set correctly. Also my GLSL code compiles with no errors. For debugging I tried to make my shader even simpler:
void main(void)
{
gl_FragColor = vec4(1,0,0,1);
}
This gives me a red texture. Thus my basic setup seems to be OK.
Pay attention to the 4th parameter of TEX. It says RECT, so the sampler needs to have sampler2DRect type.
uniform sampler2DRect tex;
void main(void) {
gl_FragColor = texture2DRect(tex, gl_TexCoord[0]);
}

Translate ARB assembly to GLSL?

I'm trying to translate some old OpenGL code to modern OpenGL. This code is reading data from a texture and displaying it. The fragment shader is currently created using ARB_fragment_program commands:
static const char *gl_shader_code =
"!!ARBfp1.0\n"
"TEX result.color, fragment.texcoord, texture[0], RECT; \n"
"END";
GLuint program_id;
glGenProgramsARB(1, &program_id);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_id);
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(gl_shader_code ), (GLubyte *) gl_shader_code );
I'd simply like to translate this into GLSL code. I think the fragment shader should look something like this:
#version 430 core
uniform sampler2DRect s;
void main(void)
{
gl_FragColor = texture2DRect(s, ivec2(gl_FragCoord.xy), 0);
}
But I'm not sure of a couple of details:
Is this the right usage of texture2DRect?
Is this the right usage of gl_FragCoord?
The texture is being fed with a pixel buffer object using GL_PIXEL_UNPACK_BUFFER target.
I think you can just use the standard sampler2D instead of sampler2DRect (if you do not have a real need for it) since, quoting the wiki, "From a modern perspective, they (rectangle textures) seem essentially useless.".
You can then change your texture2DRect(...) to texture(...) or texelFetch(...) (to mimic your rectangle fetching).
Since you seem to be using OpenGL 4, you do not need to (should not ?) use gl_FragColor but instead declare an out variable and write to it.
Your fragment shader should look something like this in the end:
#version 430 core
uniform sampler2D s;
out vec4 out_color;
void main(void)
{
out_color = texelFecth(s, vec2i(gl_FragCoord.xy), 0);
}
#Zouch, thank you very much for your response. I took it and worked on this for a bit. My final cores were very similar to what you suggested. For the record the final vertex and fragment shaders I implemented were as follows:
Vertex Shader:
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;
out vec2 UV;
uniform mat4 MVP;
void main()
{
gl_Position = MVP * vec4(vertexPosition_modelspace, 1);
UV = vertexUV;
}
Fragment Shader:
#version 330 core
in vec2 UV;
out vec3 color;
uniform sampler2D myTextureSampler;
void main()
{
color = texture2D(myTextureSampler, UV).rgb;
}
That seemed to work.

no uniform with name 'u_proj' in shader

I wrote a pair of shaders to display the textures as greyscale instead of full color. I used these shaders with libGDX's built in SpriteBatch class and it worked. Then when I tried to use it with the built in SpriteCache class it didn't work. I looked at the SpriteCache code and saw that it set some different uniforms that I tried to take into account but I seem to have gone wrong somwhere.
The SpriteCache class in libGDX sets the following uniforms:
customShader.setUniformMatrix("u_proj", projectionMatrix);
customShader.setUniformMatrix("u_trans", transformMatrix);
customShader.setUniformMatrix("u_projTrans", combinedMatrix);
customShader.setUniformi("u_texture", 0);
This is my vertex shader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_proj;
uniform mat4 u_projTrans;
uniform mat4 u_trans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = a_position* u_proj * u_trans;
}
and this is the fragment shader:
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform u_projTrans;
void main() {
vec4 color = texture2D(u_texture, v_texCoords).rgba;
float gray = (color.r + color.g + color.b) / 3.0;
vec3 grayscale = vec3(gray + 0* u_projTrans[0][0]);
gl_FragColor = vec4(grayscale, color.a);
}
The error I get is:
Exception in thread "LWJGL Application" java.lang.IllegalArgumentException: no uniform with name 'u_proj' in shader
...
com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:206)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)ackends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:206)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
I guess do any of you guys know why this isn't working? There is a uniform with the name u_proj.
Thank you all!
What Reto Koradi said was true I had forgotten to put a mat4 tag before u_projTrans, that helped me.
Then what Tenfour04 said was a huge help too! I hadn't known about:
if (!shader.isCompiled()) throw new GdxRuntimeException("Couldn't compile shader: " + shader.getLog());
What helped me most in the long run was finding that glsl, when compiling, would do away with unused imports and that if you weren't able to trick the compiler into thinking that unused imports were used being used the shader would compile and then crash on runtime.
In libgdx there is a static "pedantic" variable that you can set. If it is set to false the application won't crash if variables are sent to the shader that the shader isn't using, they will simply be ignored. The code in my libgdx program looked something like this:
ShaderProgram.pedantic = false;
Thanks for your help all! I hope this can help someone in the future
Make sure that you check the success of your shader compilation/linking. Your fragment shader will not compile:
uniform u_projTrans;
This variable declaration needs a type. It should be:
uniform mat4 u_projTrans;
You can use the following calls to test for errors while setting up your shader programs:
glGetShaderiv(shaderId, GL_COMPILE_STATUS, ...);
glGetShaderInfoLog(shaderId, ...);
glGetProgramiv(programId, GL_LINK_STATUS, ...);
glGetProgramInfoLog(programId, ...);

How to access automatic mipmap level in GLSL fragment shader texture?

How do I determine what mipmap level was used when sampling a texture in a GLSL fragment shader?
I understand that I can manually sample a particular mipmap level of a texture using the textureLod(...) method:
uniform sampler2D myTexture;
void main()
{
float mipmapLevel = 1;
vec2 textureCoord = vec2(0.5, 0.5);
gl_FragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
Or I could allow the mipmap level to be selected automatically using texture(...) like
uniform sampler2D myTexture;
void main()
{
vec2 textureCoord = vec2(0.5, 0.5);
gl_FragColor = texture(myTexture, textureCoord);
}
I prefer the latter, because I trust the driver's judgment about appropriate mipmap level more than I do my own.
But I'd like to know what mipmap level was used in the automatic sampling process, to help me rationally sample nearby pixels. Is there a way in GLSL to access the information about what mipmap level was used for an automatic texture sample?
Below are three distinct approaches to this problem, depending on which OpenGL features are available to you:
As pointed out by Andon M. Coleman in the comments, the solution in OpenGL version 4.00 and above is simple; just use the textureQueryLod function:
#version 400
uniform sampler2D myTexture;
in vec2 textureCoord; // in normalized units
out vec4 fragColor;
void main()
{
float mipmapLevel = textureQueryLod(myTexture, textureCoord).x;
fragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
In earlier versions of OpenGL (2.0+?), you might be able to load an extension, to similar effect. This approach worked for my case. NOTE: the method call is capitalized differently in the extension, vs. the built-in (queryTextureLod vs queryTextureLOD).
#version 330
#extension GL_ARB_texture_query_lod : enable
uniform sampler2D myTexture;
in vec2 textureCoord; // in normalized units
out vec4 fragColor;
void main()
{
float mipmapLevel = 3; // default in case extension is unavailable...
#ifdef GL_ARB_texture_query_lod
mipmapLevel = textureQueryLOD(myTexture, textureCoord).x; // NOTE CAPITALIZATION
#endif
fragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
If loading the extension does not work, you could estimate the automatic level of detail using the approach contributed by genpfault:
#version 330
uniform sampler2D myTexture;
in vec2 textureCoord; // in normalized units
out vec4 fragColor;
// Does not take into account GL_TEXTURE_MIN_LOD/GL_TEXTURE_MAX_LOD/GL_TEXTURE_LOD_BIAS,
// nor implementation-specific flexibility allowed by OpenGL spec
float mip_map_level(in vec2 texture_coordinate) // in texel units
{
vec2 dx_vtc = dFdx(texture_coordinate);
vec2 dy_vtc = dFdy(texture_coordinate);
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
float mml = 0.5 * log2(delta_max_sqr);
return max( 0, mml ); // Thanks #Nims
}
void main()
{
// convert normalized texture coordinates to texel units before calling mip_map_level
float mipmapLevel = mip_map_level(textureCoord * textureSize(myTexture, 0));
fragColor = textureLod(myTexture, textureCoord, mipmapLevel);
}
In any case, for my particular application, I ended up just computing the mipmap level on the host side, and passing it to the shader, because the automatic level-of-detail turned out to be not exactly what I needed.
From here:
take a look at the OpenGL 4.2 spec chapter 3.9.11 equation 3.21. The mip map level is calculated based on the lengths of the derivative vectors:
float mip_map_level(in vec2 texture_coordinate)
{
vec2 dx_vtc = dFdx(texture_coordinate);
vec2 dy_vtc = dFdy(texture_coordinate);
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
return 0.5 * log2(delta_max_sqr);
}

OpenGL shaders: uniform variables count incorrect

I want to do bump/normal/parallax mapping but for this purpose I need multitexturing - use 2 textures at a time - one for the color and one for the height map. But this task accomplishment appeared absurdly problematic.
I have the following code for the vertex shader:
#version 330 core
/* 0: in
* 1: out
* 2: uniform
*/
// 0: in
layout (location = 0) in vec3 v_vertexPos;
layout (location = 1) in vec2 v_vertexTexCoord;
// 1: out
out vec2 f_vertexTexCoord;
// 2: uniform
uniform mat4 vertexMvp = mat4( 1.0f );
void main()
{
f_vertexTexCoord = v_vertexTexCoord;
gl_Position = vertexMvp * vec4( v_vertexPos, 1.0f );
}
and the following for the fragment one:
#version 330 core
/* 0: in
* 1: out
* 2: uniform
*/
// 0: in
in vec2 f_vertexTexCoord;
// 1: out
layout (location = 0) out vec4 f_color;
// 2: uniform
uniform sampler2D cTex;
uniform sampler2D hTex;
// #define BUMP
void main()
{
vec4 colorVec = texture2D( cTex, f_vertexTexCoord );
#ifdef BUMP
vec4 bumpVec = texture2D( hTex, f_vertexTexCoord );
f_color = vec4( mix( bumpVec.rgb, colorVec.rgb, colorVec.a), 1.0 );
#else
f_color = texture2D( cTex, f_vertexTexCoord );
#endif
}
The shaders get compiled and attached to the shader program. The program is then linked and then used. The only reported active uniform variables by glGetActiveUniform are the vertex shader's uniform vertexMvp and the fragment one's cTex. hTex is not recognized and querying for its location the result is -1. The GL_ARB_multitexture OpenGL extension is supported by the graphics card ( supports OpenGL version up to 4.3 ).
Tested the simple multitexturing example provided here which has only fragment shader defined, using the stock vertex one. This example works like a charm.
Any suggestions?
"GLSL compilers and linkers try to be as efficient as possible. Therefore, they do their best to eliminate code that does not affect the stage outputs. Because of this, a uniform defined in a shader file does not have to be made available in the linked program. It is only available if that uniform is used by code that affects the stage output, and that the uniform itself can change the output of the stage.
Therefore, a uniform that is exposed by a fully linked program is called an "active" uniform; any other uniform specified by the original shaders is inactive. Inactive uniforms cannot be used to do anything in a program." - OpenGL.org
Since BUMP is not defined in your fragment shader, hTex is not used in your code, so is not an active uniform. This is expected behavior.