Texture Error --

I’ve been trying to map a texture onto two triangles. After running into issues, I compressed the code into these few segments. The “Texture” at this point is a single red pixel for testing. You can see it in the variable “pixel”. I’ve checked several tutorials, The OpenGL Programming Guide, and even some older code of mine that worked. I feel like there’s a dumb mistake here that I’m just missing.

I expect it to just draw a giant red square on the screen. Instead the actual drawn image is at the bottom of the post. I set glClearColor to a dark green so that the (accidently) black geometry is visible. Does anyone know what I might have done wrong?

I can provide more code as requested, thanks.


	 GLint texUniform = glGetUniformLocation(program, "colorMap");
   	SpriteInvariant.texUniform = texUniform;

	Sprite sprite;
	{

		u8 pixel[4] = { 255, 0, 0, 255};

		 GLuint texture;
		glGenTextures(1, &texture);
		glBindTexture(GL_TEXTURE_2D, texture);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);

		sprite = (Sprite) { 
			.position = (v3) {0,0,-0.5}, 
			.scale = (v3) {1,1,1},
			.rotation = QuatFromEuler(0,0,0),
			.texture = texture
		};
	}

	glClearColor(0,0.1,0,1);
	glClear(GL_COLOR_BUFFER_BIT);
	{
		FrameRenderInfo renderState = frameRenderInfo;
		v2 windowSize = renderState.windowSize;
		r32 aspectRatio = windowSize.x / windowSize.y;

		mat4 cam = MulMat4(
				Mat4FromQuat(renderState.camera.rotation),
				Mat4FromPosition(renderState.camera.position));
		mat4 proj = MulMat4( 
				Mat4FromEuler(0,0,0),
				Mat4FromPerspective(aspectRatio, renderState.camera.fov, renderState.camera.nearPlane, 
					renderState.camera.farPlane));
		mat4 view = InvertMat4(cam);

		glUseProgram(SpriteInvariant.shader);
		glBindVertexArray(SpriteInvariant.vao);

		glUniformMatrix4fv(SpriteInvariant.projectionUniform, 1, GL_FALSE, proj.e);
		glUniformMatrix4fv(SpriteInvariant.viewSpaceUniform, 1, GL_FALSE, view.e);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, sprite.texture);
		glUniform1i(SpriteInvariant.texUniform, sprite.texture);

		mat4 modelSpace = MulMat4s( 3,
				Mat4FromScaleV3(sprite.scale),
				Mat4FromQuat(sprite.rotation),
				Mat4FromPosition(sprite.position)
				);


		glUniformMatrix4fv(SpriteInvariant.modelSpaceUniform, 1, GL_FALSE, modelSpace.e);

		glDrawArrays(GL_TRIANGLES, 0, 6);
	glerror_to_debug(__FILE__,__LINE__);
	}

	SwapBuffers(deviceContext);

Shaders:
Vertex


#version 330 core

in vec3 pos;
in vec2 uv;

uniform mat4 modelSpace;
uniform mat4 viewSpace;
uniform mat4 projection;

out vec4 passPos;
out vec2 passUv;

void main()
{
	vec4 renderPosition = projection * viewSpace * modelSpace * vec4(pos,1f);

	// render position
	//vec4 renderPosition = projection * vec4(pos,1);
	gl_Position = renderPosition;

	// vert uv
	passUv = uv;

	// world position
	vec4 vertWorldPosition = (modelSpace*vec4(pos,1.0f));
	passPos = (vertWorldPosition)/vertWorldPosition.w;
}

Fragment


#version 330 core
in vec4 passPos;
in vec2 passUv;

uniform sampler2D colorMap;

out vec4 color;

void main()
{
	float dist = 1.0f - length(passPos)/256.0f;
	color = texture(colorMap, passUv);//+ vec4(0,passUv.x,passUv.y,1);
}

Right now, this code produces this output:
screen

What happens if you use

color = vec4(0,passUv.x,passUv.y,1);

as output of the fragment shader?

You can also try to use a much larger texture. Just fill your array with the same values until you get to a size of lets say 256x256. Reason for this is, that I am not sure how the magnification filter works on single pixel textures.

Hi ProgrammerX, thanks for you help.

So I looked into this more today and found the issue. I’m gonna describe it in more detail in case someone from the internet comes in with the same issues I had.

I checked that the uv coordinates were working properly in the manner ProgrammerX suggested. I mapped passUv to the green and blue components. It looked like this:
ub
So I concluded that that was not the issue.

In addition, I also became suspicious of the 1 pixel texture. While looking into MipMaps I discovered that mipmaps can only be generated for textures of a size that’s a power of 2. (this is not surprising, actually) I figured this would not be an issue since I was not using mipmaps.

However, because I never used glTexParameter to specify the mag and min filters, they defaulted to ones that require mipmaps.

This meant that the GPU was not able to bind the textures to the shader as a resource. (Or at least that’s what RenderDoc suggests.)
I was very surprised that glGetError() did not report anything about this.

In the end, my immediate problem was solved by either:

  • Changing the texture to be 2x2, and calling glGenerateMipMaps.
    OR
  • Setting glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); and glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); which does not need mipmaps and therefore avoids the issue altogether.

Of course I had one more error, which is that I was calling glActiveTexture(GL_TEXTURE0); which was the wrong slot. I needed to call glActiveTexture(GL_TEXTURE0 + sprite.texture);

The combination of these two issues solved the problem.

This is incorrect. Any size texture can have mipmaps. In earlier versions, textures were required to have power-of-two dimensions, but that is ancient history now (and 1=20 is a power of two).

That isn’t a problem here, as a 1x1 texture only has a single mipmap level, so it always has all mipmap levels defined. For larger textures, you must define additional levels or use a minification filter which doesn’t require mipmaps.

Using a minification filter which requires mipmaps with a texture with some levels undefined isn’t an error; it just results in texture reads returning zero. However, that isn’t an issue for a 1x1 texture, as mentioned above.

If that actually affects the result, you have a (fairly serious) driver bug. 1x1 textures are perfectly valid (and not uncommon).

[QUOTE=AllBetsAreOff;1293501]Of course I had one more error, which is that I was calling glActiveTexture(GL_TEXTURE0); which was the wrong slot. I needed to call glActiveTexture(GL_TEXTURE0 + sprite.texture);

The combination of these two issues solved the problem.[/QUOTE]
Are you sure it wasn’t just the second one?

Hey GClements,

I went back to confirm that the behavior was the way that I though it was, and after doing some more testing today, I have found that you were right on every count.

So that was embarrassing to discover, but thank you for your corrections.