Want viewer.exe reads the alpha channel, not the first channel, for OBJ material map_d texture

41 views
Skip to first unread message

Eric Haines

unread,
Oct 25, 2021, 1:12:33 PM10/25/21
to G3D Users
I'll repeat that long title: I want to modify my code so that viewer.exe reads the alpha channel, not the first channel, for the OBJ material map_d texture

Long title, but that's what I want to do. Some clue as to how to do this in viewer.exe would be appreciated!

The problem is this: map_d is required by a number of DCC apps, such as Blender and Cinema 4D. If I feed them an RGBA texture, they properly understand that the alpha channel of that texture should be used when applied with the OBJ material's "map_d sunflower_front.png" material setting.

You can see (and test) for yourself by downloading http://www.realtimerendering.com/erich/minecraft/public/mineways/downloads/_material_test.zip

See _separate_alpha_view.jpg for how things should look. This is generated from jgrtx.obj, and it works because the alpha channel has just a single channel, in jgrtx-Alpha.png.

Now see _ind_view.jpg - this view is wrong in a number of ways, because for the map_d textures it's using RGBA textures and viewer.exe looks at sunflower_front.png and does not properly extract the alpha channel but instead grabs the red channel, I believe.

I want to at least fix my viewer.exe, which I distribute with Mineways. I'm upgrading Mineways to properly emit map_d textures, but I'd rather not have G3D fail when viewing these files. G3D is great, it's incredibly wonderful otherwise at displaying Mineways scenes (as you can see in the JPEGs).

Any help appreciated (and I hope G3D will incorporate this fix itself, but at the minimum I want to do it myself).

Thanks,

Eric

Eric Haines

unread,
Oct 25, 2021, 1:53:13 PM10/25/21
to G3D Users
Followup:

I added poppy_good and poppy_bad to make the comparison easier. If you comment out "map_d" in poppy_bad, it works, but that's the wrong behavior: viewer.exe should get the A channel from map_d's texture.

And, I figured out a fix! Here it is, in Texture.cpp

shared_ptr<Texture> Texture::loadTextureFromSpec(const Texture::Specification& s) {
    shared_ptr<Texture> t;    

    if (s.alphaFilename.empty()
        // Eric's fix: if filename == alphaFilename, just call here - then the alpha is properly taken from the file.
        // This should also be faster, since only one image file is read.
        || s.filename == s.alphaFilename) {
        t = Texture::fromFile(s.filename, s.encoding, s.dimension, s.generateMipMaps, s.preprocess, s.assumeSRGBSpaceForAuto);
    } else {
        t = Texture::fromTwoFiles(s.filename, s.alphaFilename, s.encoding, s.dimension, s.generateMipMaps, s.preprocess, s.assumeSRGBSpaceForAuto, false);
    }

    if ((s.filename == "<white>" || s.filename.empty()) && (! s.encoding.readMultiplyFirst.isOne() || ! s.encoding.readAddSecond.isZero())) {
        t->m_name = String("Color4") + (s.encoding.readMultiplyFirst + s.encoding.readAddSecond).toString();
        t->m_appearsInTextureBrowserWindow = false;
    }

    if (! s.name.empty()) {
        t->m_name = s.name;
    }

    return t;
}

I highly recommend this change. It says "if the RGB texture and Alpha texture are the same texture, open that and assume alpha is meant as alpha."

Note that this is not an entirely robust fix: if someone (goofily) feeds in an RGB texture for map_Kd and then an RGBA texture for map_d, expecting G3D to use the alpha channel from this texture, then it will fail. Where you want to check for 4 channels in RGBA is in fromTwoFiles().

Basically:

        t = Texture::fromTwoFiles(s.filename, s.alphaFilename, s.encoding, s.dimension, s.generateMipMaps, s.preprocess, s.assumeSRGBSpaceForAuto, false);

says "false" at the end. If it said "true" it would work. I suspect a better fix would be to, in fromTwoFiles(), do something like:

    bool hasAlpha = useAlpha;
    ...
                 if (alphaStride == 4) {
                    hasAlpha = true;
                }
and then test hasAlpha instead of useAlpha in the remaining code.

Basically, if there are 4 channels in the alpha map, use the alpha channel. It seems hard to argue that you really want the red channel when RGBA is available.

Anyway, I've put my fixed Texture.cpp here: http://www.realtimerendering.com/erich/minecraft/public/mineways/downloads/Texture.cpp - I hope you'll consider adding this second change to G3D, making it compatible with Blender, Cinema 4D, and Sketchfab, to name a few. The "match the name" fix I give first is optional, though the code for it should be faster. The "set hasAlpha" fix is more solid, I think, though a tad slower, I would guess.

Eric Haines

Eric Haines

unread,
Jan 9, 2023, 6:40:08 PM1/9/23
to g3d-...@googlegroups.com
I reported this bug and quick fix in October 2021. Getting the latest G3D, I see the problem is still there, so I'll try again, shorter this time. I give a one-line fix, though I suspect there's a better way.

The test files and Texture.cpp fix I'm using are at https://erich.realtimerendering.com/download/g3d_bug/g3d_lantern_test.zip

If you load lantern_single_material.obj using G3D's viewer.exe app, you get the right answer:

lantern_single_texture.jpg

If you load lantern.obj, you get semitransparent lanterns, etc.:

lantern.jpg

Note that Microsoft's (slow) "3D Viewer" does display this model lantern.obj correctly (though without the cool "make the texels blocky" feature G3D secretly supports):

image.png

I made a small fix to Texture.cpp, line 1172 on:

    // Eric's fix: if filename == alphaFilename, just call here - then the alpha is properly taken from the file.
    // This should also be faster, since only one image file is read.
    //was: if (s.alphaFilename.empty()) {
    if (s.alphaFilename.empty() || s.filename == s.alphaFilename) {

As explained in the original longer report, the problem is that if an alpha file is passed in, G3D's fromTwoFiles assumes the first channel in the alpha texture is the alpha channel. But my alpha texture has four channels, RGBA. It is reasonable to assume that if an alpha texture has four channels, the fourth, not the first, is alpha.

Original long report follows, which explains more and gives other ideas for fixing the code. You are the experts, not me, so I expect you'll figure out a more robust "figure what the user wants" fix yourself.

Thanks,

Eric

--
You received this message because you are subscribed to a topic in the Google Groups "G3D Users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/g3d-users/ZyhjZsvsno4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to g3d-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/g3d-users/0ad7f739-eab0-431c-a4ed-5f64ea3543d9n%40googlegroups.com.

Eric Haines

unread,
Feb 10, 2023, 1:27:02 PM2/10/23
to G3D Users

Ping on this one. Any chance of it being fixed? Should I bother to log bugs?
Reply all
Reply to author
Forward
0 new messages