warrenm / GLTFKit2

A glTF 2.0 asset loader and exporter for Objective-C and Swift.
MIT License
150 stars 26 forks source link

The problem with transparency of the model #39

Closed kourion11 closed 9 months ago

kourion11 commented 9 months ago

The problem with transparency of the model and similar to it, as far as I understand when using metacity on a transparent element makes it opaque and fills it. You wrote a solution for a specific model, but unfortunately we have different models coming in and we would like to correct this at the conversion stage. Is there any way to solve this?

Снимок экрана 2023-10-06 в 12 39 05

node.enumerateChildNodes { child, _ in if child.name == "glass" { child.opacity = 0.568 child.geometry?.firstMaterial?.transparencyMode = .dualLayer } }

This helped solve the problem, but only for a specific model unfortunately...

warrenm commented 9 months ago

You're going to need to fix this further up your pipeline, or dig into the code to adapt it to your needs.

The framework maps glTF properties to SceneKit properties as closely as it can, but it's not possible to vary the opacity of a node by setting its base color factor's alpha channel. There's simply nowhere for that information to go in SceneKit.

One possible solution would be to preprocess any textures that need to be transparent by multiplying them by their respective factors. In the Christmas Ball example, this would entail modulating baseColor_1.png by the alpha of its base color factor (0.4681818).

Another possible solution is to adapt the loader to carry information about the base color factor into the SceneKit conversion routine and use shader modifiers to apply it to the corresponding material. This is an intrusive change and one that I've wanted to try for a long time, but haven't gotten around to yet.

In addition to the above suggestions, if you find you get better results from dual-layer blending, you can modify all alpha-blended materials to use it upon import rather than targeting specific materials in specific assets. Just iterate over the materials in the GLTFSceneSource before performing conversion:

let source = GLTFSCNSceneSource(asset: asset)
for material in source.materials {
    if material.blendMode == .alpha {
        material.transparencyMode = .dualLayer
    }
}

To be clear, setting the transparency mode by itself won't solve your issues with opacity; it's a supplemental suggestion that may improve image quality after fixing your alpha channel woes.

warrenm commented 9 months ago

Okay, I have some maybe-good news for you. I implemented better handling of base color factor modulation via shader modifiers, and the Christmas Ball asset looks better by default, without having to do any runtime modifications.

You should be aware that macOS Sonoma 14.0 (and iOS 17.0, I think) have a bug in SceneKit that affects transparency, so you may notice differences in how assets render on these OS versions.

In the meantime, you should find that things look better as of ce58ae6 if you want to give it a try.

kourion11 commented 9 months ago

Thank you!

warrenm commented 9 months ago

Do you consider this issue resolved, or is there more to do here?

warrenm commented 9 months ago

This issue will be automatically closed in seven days if no further reply is received.

warrenm commented 9 months ago

Closing.