Full transparency while fully reflective (Scenekit material)

Dear Scenekit Experts,


I'm trying to get a material resembling clear glass using PBR. It should be 99% transparent while also very reflective.


Here's some sample code I'm using for my material right now:


        lightingModel = .physicallyBased
        metalness.contents = UIColor(white: 1.0, alpha: 1.0)
        diffuse.contents = UIColor(white: 0.2, alpha: 1.0)
        roughness.contents = UIColor(white: CGFloat(0.03), alpha: 1.0)

        transparencyMode = .dualLayer
        isDoubleSided = true
        transparency = 0.2



The problem is that the amount of reflections seem to be affected by the `transparency`, i.e. if I set `transparency = 0.01` the reflections of the scenes environment map are barely visible anymore.
If I on the other hand set `transparency = 0.2` I get some nice reflections, but unfortunately now my whole object is visible, i.e. it looks like a piece of tinted glass (depending on which color I set in `diffuse`).
How can I make it clear , i.e. see-through while still seeing the reflections ?

Replies

Hey there Bersaelor,


Here is a trick that can get you something pretty close to "99% transparent while also very reflective".


1. Create an SCNPlane


2. Set it's first material's diffuse contents to UIColor.black


3. Set it's first material's blendMode to .add


4. Set it's first material's lightingModel = .physicallyBased

This will avoid blending the surface color contribution into the render target, but it'll also cause additive blending to be used for the reflections / highlights visible on the transparent surface. That's not ideal for realistic reflections, particularly if bright highlights are possible in your scene.


One (somewhat clunky) option I've used is to set the surface fragment's red, green, and blue components to 0 using a shader modifier. With this approach, you can eliminate the surface color contribution without affecting the subsequent lighting stage. Be sure to specify

#pragma transparent
if your material properties don't otherwise include transparency.


#pragma arguments

#pragma transparent
#pragma body

_surface.diffuse.a = 0;
_surface.diffuse.rgb *= _surface.diffuse.a;


I'd be interested to hear if there's a simpler "correct" way.

Totally agree on the non-realisticness of my previous solution (and the potential for additive blending issues), but OP was asking for "99% transparent while also very reflective", which is not physically realistic.


If you want to represent realistic, window pane glass in SceneKit, here is what I recommend:


Lighting Model: Physically Based


Diffuse Color: Pick something that is mostly white, but with a very slight green/yellow tint (which is what real window pane glass has)

*If you want your glass to tint it's reflected light a certain color, pick that color here instead


Diffuse Opacity: Somewhere between 8%-15%. Real glass is not completely, or even 99% transparent.


Metalness: Glass is an (imperfect) dielectric, so I suggest a value between 0.1-0.2 (however, if you want to exagerate the reflections on the glass, you can just increase the metalness, again, this would be unrealistic.)


Roughness: Real window pane glass is polished, and therefore is pretty smooth, but again, not perfectly smooth. I suggest a value between 0.05-0.1

*And set the transparency to Dual Layer

*If you have lights that are casting shadows, you will want to make sure your glass material does not write to the depth buffer

I imagine the opacity you'd use is dependent on the thickness of the glass, but yeah, some nonzero value does make sense, especially with regard to imparting a tint. 👍 I'd been doing it in the output stage, but this sounds like a nicer use of the engine.

I agree in that glass is never 100% transparent. The problem I found with reflection is If I set the transparency to 0.2 the overall end result alpha channel will be multiplied by that value.
This will seems to multiply with 0.2 even those fragments with a very strong specular/highlight reflection.
(1) Reality:
(a) Strong reflection in glass makes objects behind the glass invisible
(b) Normal glass without any reflections, adds a little bit of it's tint, depending on thickness, to the color that is visible behind.

Compare an image of a pair of glasses with plexi glass side-protectors from my desk: https://imgur.com/cA5ylB0

Where there is a reflection the glas becomes basically opaque.

(2) SceneKit:
(a) High Opacity: Reflections are beautifully reflecting lights etc, unfortunately one can barely see the object behind the glass.
(b) Low Opacity: Great visibility of objects behind the glass, but now all the reflections are very subdued.
So, what I ended up doing with this is adjusting the alpha-channel of a fragment by the amount of specular lighing that fragment gets:

vec3 light = _lightingContribution.specular;
float alpha = reflectivity * min(1.0, 0.33 * light.r + 0.33 * light.g + 0.33 * light.b);
_output.color.rgb *= min(1.0, (1.5 + 2 * \(minAlpha)) * alpha);
_output.color.a = (0.75 + 0.25 * \(minAlpha)) * alpha;

`
(We put that shader modifier into our release of https://apps.apple.com/app/id1463380262 in case you want to try yourself)
@gchiste I also implemented your tip using `blendMode = .add`, which is a good alternative to the above custom shader in same cases.
I agree though that it doesn't work perfectly under varying lighting conditions.