google / filament

Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WebGL2
https://google.github.io/filament/
Apache License 2.0
17.44k stars 1.84k forks source link

`TransparencyMode::TWO_PASSES_ONE_SIDE` showing back face for certain asset #7688

Closed hannojg closed 4 months ago

hannojg commented 4 months ago

Describe the bug

I can see the back side / back face of an asset which uses "Alpha blend", although I configured TransparencyMode::TWO_PASSES_ONE_SIDE and the asset only is made out of one single mesh.

To Reproduce Steps to reproduce the behavior:

  1. Get the asset coin.glb.txt
  2. Rename coin.glb.txt to coin.glb
  3. Import the glb in blender: Screenshot 2024-03-20 at 22 04 43
  4. You see that it uses opaque blend mode. Change it to "alpha blend": Screenshot 2024-03-20 at 22 04 51
  5. You may see the backface in blender as well. Uncheck the "Show backface" option

    [!NOTE] Interestingly setting this option doesn't change anything of the material specification in the gltf json file when exporting the asset with "show backface" activated vs deactivated. So either gltf isn't supporting it, or it's not an option that applies to the material / model but just to the rendering pipeline?

  6. Now the coin should look correct in blender, export the glb: Screenshot 2024-03-20 at 22 04 56
  7. Import the model in Filament. You should get a similar result as shown in step (5), where you can see the backface (See screenshots below).
  8. Consulting the documentation setting the transparency mode of all materials to TransparencyMode::TWO_PASSES_ONE_SIDE should fix the issue. However it doesn't for this asset, the render output stays the same.

Note: I verified that the code setting TransparencyMode::TWO_PASSES_ONE_SIDE works, because it works for other assets. It just doesn't seem to work for this asset. I checked the normals of the asset, and they look good to me.

Expected behavior A clear and concise description of what you expected to happen.

I expected the coin to show without the back face shining through (especially since alpha is set to value 1), as seen in image step (6).

Screenshots

**Expected** **Actual**

Logs If applicable, copy full logs from your console here. Please do not use screenshots of logs, copy them as text, use gist or attach an uncompressed file.

No logs.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context

Also happens on iOS

romainguy commented 4 months ago

I don't know how you modified Filament for this, but it works just fine when I use twoPassesOneSide. You probably modified Filament/gltiof in the wrong spot. Here it is with an alpha of 0.5:

Screenshot 2024-03-20 at 3 54 19 PM

(note that if your object is double sided, gltfio uses twoPassesTwoSides automatically).

hannojg commented 4 months ago

@romainguy I rendered it in the iOS gltf-viewer application, set doubleSided to false and transparency mode to TransparencyMode::TWO_PASSES_ONE_SIDE. Ifi t helps I can provide a branch with a full reproduction?

Screenshot 2024-03-21 at 10 23 58

romainguy commented 4 months ago

It works when I do what you are doing in gltf_viewer.cpp, make sure there's no asynchronous loading happening. BTW you don't need to set the material instance again on the renderable primitive.

hannojg commented 4 months ago

Hm, I haven't modified any other code than the one shown, so I don't understand why its working in your env and not in mine (I load the resources with resourceLoader->loadResources(asset);, so no async). If it's not asking too much do you mind trying again with this glb?

coin_alpha.glb.txt

This is the one I exported from blender with alpha blend, and its not working on iOS / android for me 🤔

romainguy commented 4 months ago

Using your asset, with the code changes shown below:

Screenshot 2024-03-21 at 9 38 15 AM

gltf_viewer.cpp

        RenderableManager const& rcm = app.engine->getRenderableManager();
        Slice<Entity> const renderables{
                app.asset->getRenderableEntities(), app.asset->getRenderableEntityCount() };
        for (Entity const e: renderables) {
            auto ri = rcm.getInstance(e);
            size_t const c = rcm.getPrimitiveCount(ri);
            for (size_t i = 0; i < c; i++) {
                MaterialInstance* const mi = rcm.getMaterialInstanceAt(ri, i);
                mi->setDoubleSided(false);
                mi->setTransparencyMode(MaterialInstance::TransparencyMode::TWO_PASSES_ONE_SIDE);
                Material* ma = const_cast<Material *>(mi->getMaterial());
                materials.insert(ma);
            }
        }
hannojg commented 4 months ago

Screenshot 2024-03-21 at 19 15 44

Hm, so weird, I am on the latest changes, added exactly your changes but it's still broken.

Is there any other way how I could check what's different between your and my environment?

hannojg commented 4 months ago

Ah wait I am so sorry, I ran the gltf_viewer app from the wrong directory!

I was on an older commit (a few weeks old). And on the latest main it's actually working correctly 🥳 !

// Edit: Thank you so much for taking the time to test Romain Guy!

hannojg commented 4 months ago

Sorry for the early excitement @romainguy when I use the ubershader its showing the coin incorrectly:

Screenshot 2024-03-21 at 19 39 05

romainguy commented 4 months ago

This feature is not handled by the material itself, so it doesn't matter whether it's the Uber shader or not.

hannojg commented 4 months ago

Are you able to reproduce the difference on your end using the -u parameter @romainguy ?

To me it appears I get two different outputs depending on which material provider used:

Enable ubershaders Disable ubershaders
![Screenshot 2024-03-21 at 19 55 54](https://github.com/google/filament/assets/16821682/71f6f220-2b5a-4691-ab6a-4894b1b14b06) ![Screenshot 2024-03-21 at 19 55 43](https://github.com/google/filament/assets/16821682/7b91a393-b24b-420e-b9ac-e61a0e59bb23)