Opengl texture on 2D plane has white noise when rotating in perspective projection

I have a 2D texture on 2D plane. When I rotate this plane in orthographic projection everything is fine but when I rotate it in prespective projection then there is lines of white noise on the plane and it depends on angle of rotation, but if there is no rotation it just start flickering with all black depending on translation. I
It hepends only with textures that are binded in the texture slot > 0, so texture that is binded in 0 slot (glBindTextureUnit) behave fine in both projection!!!.
Left is orthograpic projection, right is perspective projection

Opengl code:

	glGenTextures(1, &t->m_RendererID);
	glBindTexture(GL_TEXTURE_2D, t->m_RendererID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, t->m_width, t->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, t->m_LocalBuffer);
	glBindTexture(GL_TEXTURE_2D, 0);

Fragment shader:

void main() {
	int index = int(tex_index);
	vec3 texColor = texture(u_Texture[index], v_textcoords).rgb;
	gl_FragColor = vec4(texColor,1.0) * out_color;
};

Who knows what causes this problem and how to solve it?

hi, I’m not sure what it takes, but it’s probably delt with under the topic
projective texturing

What is index? It needs to be uniform in OpenGL 3.x and dynamically uniform in 4.x.

I have an array of binded textures that are binded from 0 to 31 texture slot on gpu, so the index points on what is the generated texture id, I did it 'cause it is a batch renderer

That doesn’t answer the question. Is index uniform? If it’s a vertex shader output, is it flat-qualified?

Index is an int that is passed via vertex atrib in vertex shader and u_Texture is a uniform sampler2D u_Texture[32];
index points on the texture in array u_Texture.

That still doesn’t answer the question. If you don’t understand the question, just show the entire fragment shader, including the variable declarations.

Given that you’re explicitly converting tex_index to an int, I’m guessing it isn’t an int. If it’s written by the vertex shader, it at least needs the flat qualifier. And in OpenGL 3.x, that isn’t enough.

For GLSL 3:

For GLSL 4:

For GLSL 3, tex_index must be a uniform variable or an expression involving only uniform variables. For GLSL 4 the restrictions are relaxed somewhat, but not entirely; you still can’t index arrays of samplers with arbitrary expressions. It’s not actually specified that flat-qualified fragment shader inputs are dynamically uniform, but I’ve yet to encounter an implementation where they aren’t.

1 Like

Okay, the latest edit makes it a bit more clear:

For GLSL 3, this isn’t valid. For GLSL 4, it may or may not be. It would be safer to convert the value to an int in the vertex shader, as fragment shader inputs which are integers (or vectors of integers) are implicitly flat-qualified.

1 Like

Correcting myself here; per the spec, it actually needs to be constant. You might get away with a uniform on desktop OpenGL.

Man, you are a genius, thank you very much, I couldn’t find this on the Internet for two days.
Before, I cast float (tex_index) to int in fragment shader as you can see by posted code above.
And now I did what you said. cast float to int in vertex shader with flat prefix and it works perfectly.
Thank you very much.

Nice topic. I am using similar implementation on my learning code.

Unfortunately I’ve got strange artifacts when I am using texture with index even in pair with flat qualified input.

What’s going on here?

image

My vertex shader:

#version 450 core

layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texCoord;
layout(location = 2) in float textureIndex;

out vec2 v_TexCoord;
flat out int v_TextureIndex;

uniform mat4 u_MVP;

void main()
{
    gl_Position = u_MVP * position;
    v_TexCoord = texCoord;

    v_TextureIndex = int(textureIndex);
}

My fragment shader:

#version 450 core

layout(location = 0) out vec4 color;

in vec2 v_TexCoord;
flat in int v_TextureIndex;

uniform sampler2D u_Textures[3];

void main()
{
    vec4 texColor = texture(u_Textures[v_TextureIndex], v_TexCoord);
    color = texColor;
}

By the way changing fragment like this make glitches disappear:

#version 450 core

layout(location = 0) out vec4 color;

in vec2 v_TexCoord;
flat in int v_TextureIndex;

uniform sampler2D u_Textures[3];

void main()
{

    if (v_TextureIndex == 0) {
        vec4 texColor = texture(u_Textures[0], v_TexCoord);
        color = texColor;
    } else if (v_TextureIndex == 1) {
        vec4 texColor = texture(u_Textures[1], v_TexCoord);
        color = texColor;
    } else if (v_TextureIndex == 2) {
        vec4 texColor = texture(u_Textures[2], v_TexCoord);
        color = texColor;
    }
}

In OpenGL 4,

But:

In other words, an expression being constant for all fragments within a triangle (e.g. a flat-qualified fragment shader input) doesn’t necessarily make it “dynamically uniform”. It may or may not be, depending upon the implementation. And if it isn’t, then it isn’t valid as an index into an array of samplers.

In practice, the expression u_Textures[v_TextureIndex] is only evaluated once for each “wavefront” (concurrently-executed group of invocations). If the invocations process fragments from different triangles, v_TextureIndex can have different values and one value will be used for all fragments.

Using conditionals avoids this issue, but creates another: implicit derivatives are undefined in non-uniform control flow. If any of the textures use mipmaps, the mipmap level may not be calculated correctly. You need to calculate the derivatives or level-of-detail outside the conditional and use textureGrad or textureLod instead of texture.

Where possible, it’s preferable to use array textures (sampler2DArray) for this purpose. This entails some loss of flexibility: the layers of an array texture all have the same size and format, and texture parameters (filters, wrap modes) apply to the array texture as a whole.

2 Likes