I recently had to remind myself how texture coordinates work in D3D and OpenGL. It’s actually pretty simple, but I found a lot of conflicting advice out there. Some people say UV coordinates are handled differently in OpenGL and D3D, some say they are the same. Some say you need to vertically flip your textures when they are loaded. The problem is that the advice often works even if the explanation is incorrect.
There are two things to consider:
- Which way up your textures are stored in memory
- Which way up your UV corrdinates are
The convention for D3D is:
- Textures are top down in memory. The first byte of the texture memory is the top-left of the image
- The UV Coordinates are top down. (0,0) is the top left of the texture
The convention for OpenGL is:
- Textures are bottom up in memory. So the first byte of the texture memory is the top-left of the image
- The UV Coordinates are bottom up. (0,0) is the bottom left of the texture
If you don’t believe me that textures are stored bottom up in OpenGL, look at the documentation for glTexImage2D. It explicitly states that “The first element corresponds to the lower left corner of the texture image”. You can’t get clearer than that.
I’ve seen people say that UV’s definitely work the same in D3D and OpenGL because they have never had to flip their UVs when going between D3D and OpenGL. I’ve also seen people say that you need to flip the image in OpenGL to get it to work (most images are stored top down).
If it really was the case that data was treated differently in D3D and OpenGL then somewhere before the data got to the actual hardware something would have to flip the texture data or UV coordinates, which would be crazy. So the driver must always treat the data the same way, so why the confusion?
The important thing to notice is that if both your texture is upside down, and your UV coordinates are upside down, then they cancel each other out, and the end result is the same.
In my cross-platform engine which supports D3D and OpenGL, I assume that UV coordinates are top-left, and textures are stored in memory with the first by being the top-left. I do this for both D3D and OpenGL. But “this will be wrong for OpenGL!” I hear people cry. Someone who is used to OpenGL will notice that all textures and UV coordinates are upside down according to the OpenGL convention, and may get offended, but I really don’t care. The alternative would be to flip all textures when they are uploaded (the true OpenGL way) and also flip all UV coordinates as they are loaded. It’s easier to just do nothing and accept that you’re not following the convention. Sorry OpenGL fans, it’s just easier to pick one of the conventions when writing a cross-platform engine.