-
Notifications
You must be signed in to change notification settings - Fork 596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[HELP] Converting a DDS normal map to jpeg #3525
Comments
What have you tried so far? Did something not work as expected? |
well tried to convert it with no options and got a grey output |
There definitely appears to be some problems with OIIO's interpretation and conversion of that file. I'm not sure what's up with that yet. The input seems to be (according to OIIO) a 2-channel file, but maybe that's not correct. |
could manage to get my normal converted to png with the standalone nvidia tool https://developer.nvidia.com/nvidia-texture-tools-exporter it has some command line stuff in its install dir : they also have nvddsinfo.exe
|
So your DDS file is a two-channel format ("ATI2" aka BC5), i.e. the file only contains X & Y components of the normal map, and whatever uses the texture is expected to compute the Z component from these using math. It's a good question what should the conversion done by OIIO even do. JPEGs can't be two-channel as far as I know, so "something" should get written into the blue channel. But should it be the full "reconstructed z" value? How would OIIO even know that the texture is actually a normal map, and not just "some other" type of two-channel texture? |
JPEG (ok, to be pedantic, the JFIF file format, since "JPEG" itself refers to the compression method and the group that defined it) only supports 1 and 3 channel images. Our JPEG writer, rather than be really brittle, tries to handle this JPEG restriction on number of channels as gracefully as possible. It seems obvious that if you try to write an RGBA or RGB+others image, the JPEG writer should just write the RGB portion and drop the channels it doesn't support. But what should it do with a 2-channel image? Currently, it drops the second and outputs the first as a grayscale JPEG. Perhaps what I was thinking at the time is that a 2-channel image is likely to be Gray+Alpha, and since JFIF files don't have any provision for alpha, drop it and only write the gray, analogous to what we do with the automatic RGBA -> RGB case. But in this case the channels mean something else entirely, and perhaps a better solution would be to write a 3-channel RGB? But I'm not 100% sure how to know that, unless we can assume that ATI2 DDS files are always meant to be 2-channel normal maps? As a further aside, this is a texture map of some kind, and JPEG is a horrible format for texture maps -- first of all, because the JPEG compression will cause data loss and possible artifacts in the images, and second because JPEG/JFIF files don't support MIP mapping, so as far as OIIO is concerned, a JPEG is just an "image", and not a proper "texture." |
In general case you can't assume that ATI2/BC5 DDS files will contain normal maps -- they often contain anything that needs "two uncorrelated channels". That said, my experience is that they more often contain something else than Luminance+Alpha; in fact the dds loader plugin in OIIO indicates the channel list as "R, G" for them. Perhaps when faced with a 2-channel image, the OIIO JPG writer should decide to "downgrade" it to 1 channel only if the channel list has "Y, Alpha". If it's something like "R, G" then it should pad to an all-zeroes blue image. |
I'm not sure it's a "fix" for this issue -- or what a "fix" even means considering there is a lot of ambiguity in what it means to convert this kind of DDS to JPEG -- but I have submitted the following two PRs inspired by this situation, that I suppose help in some small way:
I think that put together, these would make Let me know if you think these effectively should close this issue, or if you think there is something additional that OIIO could reasonably do for these files. |
I think both of these changes make a lot of sense. And yes, taking a ATI2/BC5 normal map (which is already lossy compression) and converting that into a JPG (which introduces more, and different compression artifacts) is not something that makes a lot of sense. At least converting the input to some lossless format (PNG, TIF, TGA, whatever) would be better quality wise. That said, I think the improvements above are useful in more cases. |
I would suggest have a flag like the nvidia texture tool indicating this is to be treated as a normal map |
@yetigit What does that mean? If the flag is supplied, what exactly should we do differently when converting the image from DDS to, say, jpeg? |
- If a DDS pixel format header contains "this is a normal map" flag set, then handle that properly (#3525): - For a DXT5, this means it's a "DXT5nm" format. Normal X & Y components are in green and alpha channel respectively. Compute Z component from those, and the result is a 3-channel tangent space normal map. - For ATI2/BC5 format that also has a "normal map" flag set, compute the Z component automatically too, and result is a 3-channel image. However a bunch of ATI2/BC5 normal maps out there in the wild do not have that bit set, so also have a global "dds:bc5normal" attribute to optionally turn this on. - Fix support of R10G10B10A2 format - was producing garbage data due to code assumption that truncation down to 8 bits never needs to happen. - Fix bit expansion ("too dark") of very low-bit formats, e.g. R3G3B2. Code was simply shifting the bits, instead of properly repeating the high bits into new low bit positions (i.e. a 3-bit "111" needs to become an 8-bit "11111111" and not a "11100000"). - Support "RXGB" (DXT5, with red & alpha swapped) as well as "BC4U" and "BC5U" formats (the latter two are just BC4 and BC5, produced by some older tools). - Support alpha-only (e.g. A8) formats. All this mostly prompted by doing DDS improvements in Blender, and wanting to get Cycles renderer (which uses OIIO) to the same feature parity. See https://developer.blender.org/T101405 and https://developer.blender.org/D16087.
- If a DDS pixel format header contains "this is a normal map" flag set, then handle that properly (AcademySoftwareFoundation#3525): - For a DXT5, this means it's a "DXT5nm" format. Normal X & Y components are in green and alpha channel respectively. Compute Z component from those, and the result is a 3-channel tangent space normal map. - For ATI2/BC5 format that also has a "normal map" flag set, compute the Z component automatically too, and result is a 3-channel image. However a bunch of ATI2/BC5 normal maps out there in the wild do not have that bit set, so also have a global "dds:bc5normal" attribute to optionally turn this on. - Fix support of R10G10B10A2 format - was producing garbage data due to code assumption that truncation down to 8 bits never needs to happen. - Fix bit expansion ("too dark") of very low-bit formats, e.g. R3G3B2. Code was simply shifting the bits, instead of properly repeating the high bits into new low bit positions (i.e. a 3-bit "111" needs to become an 8-bit "11111111" and not a "11100000"). - Support "RXGB" (DXT5, with red & alpha swapped) as well as "BC4U" and "BC5U" formats (the latter two are just BC4 and BC5, produced by some older tools). - Support alpha-only (e.g. A8) formats. All this mostly prompted by doing DDS improvements in Blender, and wanting to get Cycles renderer (which uses OIIO) to the same feature parity. See https://developer.blender.org/T101405 and https://developer.blender.org/D16087.
- If a DDS pixel format header contains "this is a normal map" flag set, then handle that properly (AcademySoftwareFoundation#3525): - For a DXT5, this means it's a "DXT5nm" format. Normal X & Y components are in green and alpha channel respectively. Compute Z component from those, and the result is a 3-channel tangent space normal map. - For ATI2/BC5 format that also has a "normal map" flag set, compute the Z component automatically too, and result is a 3-channel image. However a bunch of ATI2/BC5 normal maps out there in the wild do not have that bit set, so also have a global "dds:bc5normal" attribute to optionally turn this on. - Fix support of R10G10B10A2 format - was producing garbage data due to code assumption that truncation down to 8 bits never needs to happen. - Fix bit expansion ("too dark") of very low-bit formats, e.g. R3G3B2. Code was simply shifting the bits, instead of properly repeating the high bits into new low bit positions (i.e. a 3-bit "111" needs to become an 8-bit "11111111" and not a "11100000"). - Support "RXGB" (DXT5, with red & alpha swapped) as well as "BC4U" and "BC5U" formats (the latter two are just BC4 and BC5, produced by some older tools). - Support alpha-only (e.g. A8) formats. All this mostly prompted by doing DDS improvements in Blender, and wanting to get Cycles renderer (which uses OIIO) to the same feature parity. See https://developer.blender.org/T101405 and https://developer.blender.org/D16087.
How do I convert this kind of normal map here to jpeg using iconvert or oiiotool ?
normaltext.zip
expected output:
The text was updated successfully, but these errors were encountered: