-
-
Notifications
You must be signed in to change notification settings - Fork 205
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
ax::Image converts gray + alpha PNGs to RGBA. #2230
Conversation
Prior to this commit these textures where mapped to PixelFormat::RG8 textures. This did not work well as some textures, especially monochrome black + transparency, were displayed as green + transparency. This commit instead converts the image to RGBA using libpng's API.
This has to be reverted, it breaks loading of 2 channel images. |
Could you develop a bit? I don't understand if two-channels images and gray+alpha PNGs can't be supported or if I broke something as a side effect of my patch. |
Your changes literally remove the part where gray+alpha is loaded as two channel RG format, and arbitrarily loads it as 4 channel texture. Not to mention it doubles the used memory. Graphics APIs have moved away from assigning purposes to the image/texture channels. Now R means one channel texture, RG - 2, RGB - 3, RGBA - 4, and you choose what each channel represents by interpreting that in the shader or other code. There's no such thing as gray+alpha, it's just a two channel texture: for your project maybe it's gray alpha, for others maybe it's multi channel SDF, etc. |
Thanks for the clarification :) I am well aware of the extra memory usage and about the shift in the interpretation of texture channels in game engine. Now maybe I'm silly but when I edit a grayscale image in my editor, save it as a gray+alpha PNG, and see that libpng labels it as PNG_COLOR_TYPE_GRAY_ALPHA, maybe I can expect it to be displayed, by default, as a grayscale texture with transparency? IMHO other interpretations of the channels should be an opt-in. I don't mind if this commit gets reverted, and I think that #2047 was broken too under your rationale since it would mix the two channels unconditionally when premultiplied alpha is enabled. If you could tell me how I can get a gray+alpha image displayed as a gray+alpha texture, it would be greatly appreciated :) |
I guess the "main" breaking part here is the removal of these lines in the switch: case PNG_COLOR_TYPE_GRAY_ALPHA:
_pixelFormat = backend::PixelFormat::RG8;
break; |
Well, I get what you're saying about what one may expect from "gray+alpha" PNG in normal circumstances, but this is a game engine, not a regular image viewer or editor. Here, you load data that can be interpreted differently by the engine in different circumstances. If you have RGB PNG image, it doesn't mean it contains an actual image. It may be a regular image, a 3D model texture, normal map, masks, terrain heights, or some other 2D data, that just fits this format and is useful to store it like that. So from the perspective of an engine, if I'm loading a two channel texture, I expect it to just load it as a two channel texture, and not convert it to some other format or somehow change the data. From quick glance #2047 seems fine, cause it's an opt in feature and not a default behavior. Just to be clear, I'm not against having some method that could convert two channel RG (aka grey+alpha in this case) to RGBA format (maybe there already is?), but that should be an opt in, not a default. Also, if it gets converted to RGBA anyway, why not just save that PNG as RGBA? Btw, I'm just curious, what is your use case for grey+alpha images? |
I totally agree that the conversion to RGBA is a mistake. I took a shortcut but it was a bad one. As I am writing this I am compiling cpp-test to try to find a correct workaround. Maybe I had another bug because most gray+alpha textures work fine (the ones when I only have white+alpha actually) but one failed (the one where I only have black+alpha).
I use them to draw repeating patterns in the menus (example here, for the bombs/explosions on the background, and the stars in the button), with |
Some additional information about the original bug I tried to solve. Here is a capture of the test Texture2D/5:PNG Test, before #2047: The top-left sprite is test_image_ai88.png, which is a gray+alpha PNG. As you can see it was already incorrectly displayed. I dumped some variables:
Then the same capture but with #2047: This time
The texture goes into ImageMagick upon packaging and its save it as gray+alpha even if the source is RGBA. I could try to avoid this step but I liked the idea of having a small texture file (yet I used a larger memory requirement with this PR, I know… :)). |
@rh101 Yes I can, it's right here in Axmol! See my comment above, the sample file is test_image_ai88.png and the code is at line 435 of cpp-tests/Source/Texture2dTest/Texture2dTest.cpp. |
The simplest way to get the output you require is to use a PNG file in the RGBA format, or alternatively, use an appropriate shader that handles the RG data as gray/alpha. Forcing the conversion from RG to RGBA in the engine code, as this PR has done, is not the way to solve this. The following fragment shader works:
Then setup the sprite so you explicitly pass the required pixel format as
The result is this, which is the correct output (using v2.2.1 of Axmol, without the changes you made in this PR): You can add the custom shader to your own project, and assign it to the sprite via If you want to add this functionality to the engine code, then this is how I personally implemented it for the test output above: Add file Add the following to Add the following to Add the following to
Add the following to
Modify
Also, from a review of the code, there seems to be a very minor mistake in the calculation for the pre-multiplied alpha that was added in #2047, method
should be
|
reverted, thanks |
#2047 introduced support for gray + alpha PNGs by mapping the data directly to PixelFormat::RG8 textures. This did not work well as some textures, especially monochrome black + transparency, were displayed as green + transparency. This commit works around the problem by converting the image to RGBA instead, using libpng's API.