Texture mapping acts weird on some images.

Started by
26 comments, last by babaliaris 5 years, 4 months ago

I'm really not certain, and as for the gimp images, I'm pretty sure they are rgba, could be wrong though. Like I said, I'm really no pro when it comes to the inner workings of this stuff, and fortunately, it looks as if you've pretty much solved your problem. Maybe someone with more experience can chime in and thoroughly explain why its behaving this way.

Advertisement

Are you by any chance using OpenGL ES?
In that case, take a look at the documentation of glTexImage2D. Especially the sentence

Quote

By default, these texels are taken from adjacent memory locations, except that after all width texels are read, the read pointer is advanced to the next four-byte boundary.

 

That means after every row the pointer is rounded up to be divisible by 4.

The images from the explosion are exactly 480 pixels wide. Every pixel has 3 color values, which means 480*3 = 1440 bytes, which is divisible by 4. So no adjustment.
The image of the arrows is 115 pixels wide. This makes 115*3 = 345 bytes per line. OpenGL will then pad it by 3 bytes effectively skipping 1 pixel. So the second line will look 1 pixel shifted. The third line will look 2 pixels shifted.

I have already mentioned it but I think you have missed it. If you look at the rendered image you will see 93 pixels missing from the last line, which is the height of the image. If you load an image with 4 components the size of each line is trivially divisible by 4 which means no adjustments.

Curiously enough this alignment of rows seems to be only part of the OpenGL ES standard and not the normal OpenGL.

8 minutes ago, Cararasu said:

Are you by any chance using OpenGL ES?

glGetString(GL_VERSION) reports:

3.3.13541 Core Profile Context 24.20.13019.1008

How can I see if it is OpenGL ES? Does the above information says that I'm using regular openGL?


void life()
{
  while (!succeed())
    try_again();

  die_happily();
}

 

No that's not OpenGL ES.

I just looked it up and it seems that the 4-byte alignment rule also affects normal OpenGL even though it is not mentioned directly in the description of glTexImage2D.

The problem seems to be a common one. They even put it inside the common mistakes section of the OpenGL-wiki:

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads

To fix the issue either make sure that the alignment of each row is always 4 bytes. or call glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before glTexImage2D. The problem with changing the alignment rules is that uploading the texture can be slower than if the alignment is not 4-bytes.

6 minutes ago, Cararasu said:

No that's not OpenGL ES.

I just looked it up and it seems that the 4-byte alignment rule also affects normal OpenGL even though it is not mentioned directly in the description of glTexImage2D.

The problem seems to be a common one. They even put it inside the common mistakes section of the OpenGL-wiki:

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads

To fix the issue either make sure that the alignment of each row is always 4 bytes. or call glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before glTexImage2D. The problem with changing the alignment rules is that uploading the texture can be slower than if the alignment is not 4-bytes.

Thank you so much! That was the issue! Just from curiosity, instead of glPixelStorei(GL_UNPACK_ALIGNMENT, 1) if I always force stb image to use 4 channels (no matter how many channels the source file might have) because RGBA is 4 bytes, will this ever be problematic? In my case now it's working and I can see the image being rendered just fine.


void life()
{
  while (!succeed())
    try_again();

  die_happily();
}

 

Well if you use 4 channels then the size of one row is always divisible by 4 so there can be no issue because of weird line-sizes. An issue might appear if the data pointer returned by "stbi_load" is not divisible by 4. I do not know if stb guarantees a certain alignment, but I would be very surprised if you ever get a pointer that is not at least divisible by 4.

So yeah you should be safe when always using 4 channels.

Additionally, I think most hardware does not store RGB images tightly. They will leave space for a fourth value because of (surprise surprise) 4-byte alignment. That means you do not lose anything in terms of GPU-memory when using RGBA over RBG.
I am not 100% certain about this, so if there is anyone who has more in-depth knowledge feel free to enlighten me?

@Cararasu please take a look on this thread too. Lets have a conversation there as well. I just solved it by forcing 4 channels to be used but I would like to ask you something else too. I'm going to post right now in that thread.


void life()
{
  while (!succeed())
    try_again();

  die_happily();
}

 

This topic is closed to new replies.

Advertisement