google-ar / sceneform-android-sdk

Sceneform SDK for Android
https://developers.google.com/sceneform/develop/
Apache License 2.0
1.23k stars 604 forks source link

Transparency issues: Reversed normals when looking through the glass #214

Open EugenioMiolo opened 6 years ago

EugenioMiolo commented 6 years ago

Hi there,

I'm trying to get transparency working properly on assets in sceneform. The asset is exported as FBX and then converted to SFB with a slightly changed fbx_material.sfm file. What seems to complicate things is that the asset always going to be a single mesh, with transparency driven by the alpha channel of the base color. Always. Non transparent assets will come with a white alpha. It worth mentioning that this works fine wtih scenekit, though.

The problem is when looking through the glass the normals are reversed (or double sided is not working). Look at the parts behing the glass in the sceenshots: screenshot_20180720-150013_hello sceneform screenshot_20180720-150038_hello sceneform

And here's the transparency settings in the fbx_material.sfm file.

    requires: [
      "position",
      "color",
      "uv0",
    ],
    shadingModel: "lit",
    blending: "transparent",
    transparency : "twoPassesTwoSides",
    doubleSided: true,
    depthWrite: true,
  },

Edit: I've attached this sample file to take a look. The blue cube is transparent while the red cube is opaque, but the model is a single mesh, and transparency is controlled through alpha channel. Test.zip

Kind regards, Eugenio

peronecode commented 6 years ago

@EugenioMiolo, did you already have tested with the property transparency: "twoPassesOneSide" ?

romainguy commented 6 years ago

@peronecode @EugenioMiolo All that should be needed in this case is doubleSided: true. You should also remove depthWrite: true.

EugenioMiolo commented 6 years ago

Thank you both for the suggestions guys. Unfortunately none of them solves the issue. I forgot to mention that I've tested all sorts of combinations before posting here on the forum.

@peronecode With "twoPassesOneSide" we can't see through the glass, which is weird IMO, since we should just not see the backfaces of the transparent objects.

@romainguy If I remove the line "depthWrite: true", sceneform have some sorting issues. Also, if I don't change the transparency mode with "twoPassesTwoSides", the normals of the red box looks inverted.

This is how it looks removing "depthWrite: true", like this: (the second screenshot shows the issue)

    shadingModel: "lit",
    blending: "transparent",
    transparency : "twoPassesTwoSides",
    doubleSided: true,

screenshot_20180724-093517_hello sceneform screenshot_20180724-093541_hello sceneform screenshot_20180724-093602_hello sceneform

This is what happens if I just set double sided to true and nothing else: (both sorting and inverted normals issues)

    shadingModel: "lit",
    blending: "transparent",
    doubleSided: true,

screenshot_20180724-095415_hello sceneform

The test cubes file is attached to the first post. Please give it a try if you can. Because I'm fairly confident it's a bug in sceneform. I don't think there's any settings combination to get it right. In fact, it's intriguing that "depthWrite" actually makes a difference, since from the Custom Material Reference document it clearly states that it should do nothing on transparent materials:

Enables or disables writes to the depth buffer. Transparent materials (see blending section) never write to the depth buffer even if this property is set to true.

Thanks, Eugenio

romainguy commented 6 years ago

The documentation needs updating, transparent objects can write to the depth buffer by using depthWrite: true now. I misspoke earlier, since you are trying to draw opaque things with your transparents, you'll need depthWrite: true.

peronecode commented 6 years ago

@EugenioMiolo I already try this issue with your model and get the same result. @romainguy Doesn't matter what property I use, the result is not the expected.

romainguy commented 6 years ago

doubleSided works properly in my tests. @EugenioMiolo could you by any chance send me the glass table asset from your 1st post? The Test.FBX file you sent crashes Blender and other converters I've tried. Thanks!

EugenioMiolo commented 6 years ago

@romainguy Here you go (also attached the .sfm I use to convert): Models.zip

Thank you! Eugenio

romainguy commented 6 years ago

I can see that SceneKit renders the object as expected with write and depth test enabled.

peronecode commented 6 years ago

@romainguy There is a solution to work around this issue? I'm using ARCore with SceneForm and all of my clients expect the quality for this Android Apps.

EugenioMiolo commented 6 years ago

Thanks a lot for investigating that @romainguy. So there isn't exactly a workaround for that ATM, right? IMO it needs a proper solution since as you said, it works fine with SceneKit after all. I wonder how transparency works in Sketchfab for example. I don't have these kind of issues there.

disable depth testing on the skybox/camera stream (depth testing is on as an optimization by default). The problem with this is that transparency will only work with the background, not with the object itself (you won't see the object through itself).

I guess that this would lead to an even bigger problem. Because the object would look opaque against itself, which is currently what I get when set "TwoPassesOneSide" transparency mode.

In my head, with the settings I had in the first post, sceneform should give the correct result.

1-Enable double sided to draw both sides of the faces (with double sided on, culling must be off). 2-Sort all faces from furthest to closest from the camera, so depthWrite should be true. 3-Set TwoPassesTwoSides to draw first the backside, and then the front side of the faces.

In theory looks like it should work.

EDIT: What @peronecode said is rather important, because clients want to offer their products in both iOS and Android, and expect the quality to be as close as possible between apps.

Regards, Eugenio

romainguy commented 6 years ago

For what it's worth Sceneform behaves here the same as Unity (with or without the new HDRP).

romainguy commented 6 years ago

Looks like the rendering engine is doing the right thing. Here's a screenshot with blending: transparent, depthWrite: true and nothing else.

screen shot 2018-07-24 at 4 36 29 pm

screen shot 2018-07-24 at 4 38 06 pm

And it works pretty well with doubleSided: true as well:

screen shot 2018-07-24 at 4 38 52 pm

romainguy commented 6 years ago

Looks like there could be an asset import bug that changes the normals. In the screenshots above the object renders properly without doubleSided: true. Note that this test apps uses a different asset loading mechanism than Sceneform.

peronecode commented 6 years ago

@romainguy I already tried all @EugenioMiolo materials configurations for solving this issue, but, always get the same results. How can I solve this?

Thanks for helping in this post, it's so difficult to me to understand.

romainguy commented 6 years ago

The renderer works as expected which makes me believe it might be an asset import issue. Other folks from Sceneform will need to take a look at this problem.

peronecode commented 6 years ago

@romainguy This is so helpful for my internal issues. I'm very grateful for your answers about all this discussion. But now, the question is: Is this a bug which will be fixed and released in next release?

gdamoreira commented 6 years ago

Hi @romainguy, I'm facing an similar issue, you have a workaround for this? For what I read here, there is no solution right now, right?

EugenioMiolo commented 6 years ago

@romainguy Sorry for such a late reply, and thank you for looking in depth into the topic.

Looks like there could be an asset import bug that changes the normals. In the screenshots above the object renders properly without doubleSided: true. Note that this test apps uses a different asset loading mechanism than Sceneform.

Where exactly would be the asset import bug? I mean, we run the FBX through the command line converter that generates the SFB for use with sceneform. The FBX is ok because it works for you, so IMO the converter must be the problem. How did you convert the FBX to SFB to load in sceneform? Either way, looks like something on your end, right? Because ATM I don't know what are my options.

I also noted your screenshots are from an iOS, is that the same sceneform me and others are using? It's important to make sure we try on the same environment.

Kind Regards, Eugenio

romainguy commented 6 years ago

I did not use the FBX to SFB converter in my tests, which is what makes me suspect the converter. I used a different FBX loader that we use only to test the renderer.

My screenshots are not from iOS, but from macOS. I was testing the renderer only to try and isolate the bug (the renderer runs on Android, Windows, Linux and macOS). Since I cannot reproduce the bug in the renderer itself I think it might be in the SFB converter.

EugenioMiolo commented 6 years ago

I did not use the FBX to SFB converter in my tests, which is what makes me suspect the converter. I used a different FBX loader that we use only to test the renderer.

So the conclusion is that this must be a bug, right? Can you test running this FBX through the converter too?

My screenshots are not from iOS, but from macOS. I was testing the renderer only to try and isolate the bug (the renderer runs on Android, Windows, Linux and macOS). Since I cannot reproduce the bug in the renderer itself I think it might be in the SFB converter.

MacOS, that's what I meant :D. I imagined that was the case, and thankfully it's not a limitation of the sceneform renderer.

Kind Regards, Eugenio

romainguy commented 6 years ago

There's definitely a bug somewhere yes :)

ManuelTS commented 5 years ago

Bugfix within a year? Well in 5 days we will know more ;)

Y2JChamp commented 5 years ago

Hi, how did u update sfm file? The IDE shows me it is not good to do it and then doesn't allow to compile