recently I created a panoramic viewer with a reflecting glass sphere in the centre:
As a next step I tried to make the sphere transparent and refracting instead of reflecting. Struggled for hours and finally found out that there was a simple solution:
Simply use THREE.EquirectangularRefractionMapping instead of THREE.EquirectangularReflectionMapping:
However there is one issue left: When looking at real glass spheres, e. g. here:
it’s obvious that my virtual version is not really realistic. On the real sphere there is some reflection on top.
Is there a way to simulate this effect too?
Best regards - Ulrich
Hi Mugen87, thanks for these hints, I modified my code accordingly.
Regarding the flipping: This is just the effect I intended to achieve. A real glass sphere does it the same way. Have a look at the photos on Pinterest.
My latest version:
Any ideas how to make the refracting version more realistic? I mean the faint bright light on top. I suspect I would have to add another sphere with a solid surface and some light. However I don’t know how to combine both.
One solution may be screen-space-reflection + screen-space-refraction.
There are already many implementations listed below, but I’m making my own implementation suit with latest three.js and can use with WebGL1, now just screen-space-reflection, intend to make screen-space-refraction next.
Hi gonnavis and thanks for this info. Seems to be a complex subject and I’m not shure if my skills are sufficient to dive into.
When I look at real photos of a glass sphere closely it seems to me that there is a combination of refraction and reflection: In the center the sphere is transparent while near to the border the background is reflected. Just like the surface of the virtual water: When the viewing angle is large, it’s transparent and when the angle is small the water is reflecting. Not shure if it’s possible to simulate this by use of three.js.
In contrast, shining light was fairly easy. The illuminated surface could be merged with the refraction or reflection but this was not what was in my mind and was visible on the photos of real spheres.
Even more, if you combine what @Mugen87 and @gonnavis said (maybe except SSR) you should be able to create a realistic glass ball like in the pinterest you linked.
You don’t need opacity / transparency at all, the ball you linked is 100% opaque refraction (the reflections you see on it are not transparency, it’s a reflection environment mapping, transparency will result in a flat reflection.)
It should be quite simple to create a fragment shader that mixes refraction envmap with reflection envmap (same example, just toggle the switch on the right, it’s just 2 textures with different mapping).
If you’d like edges to fade to some color opaque (ie. fresnel) you can also mix in fresnel shader.
Yeah, you’re right, I probably messed up the sliders… (But mind - the only realistic value for opacity is 1.0. Even a bubble should refract edges afair, since it’s a curved surface. Transparency kinda breaks the effect of realistic surface.)
(1) @seanwasere approach, ie. 2 spheres + 2 env is the easiest and looks quite realistic enough. In a super-simplified version it technically needs just 3-4 params for materials (just don’t use opacity, that’s what envMaps and cubemap cameras are for. )
(2) As little as it makes sense I tried the experimental SSR branch, since I have it locally - but because it’s post-processing, reflections affect the rendered lights and it just looked a bit awkward. (the white light-dots on glass surface disappeared etc.)
(3) Fresnel shader looks by far the best - but first, it works only with cube map textures, second, it doesn’t seem to be affected by scene lights which kills the purpose.
But it’d still be best to do a custom shader, since none of these could do the focused light effect on the other side of the ball (at least dynamically, and it could be easily calculated from sun position and IOR) :
Many thanks for the numerous answers and information. Unfortunately, as I’m a novice to threejs, I was not able to understand all of this completely. @seanwasere Your latest demo is looking very fine. I intented to download it and fiddle but when using the downloading function of my browser it didn’t download the modules being imported. I tried Opera, Chrome, Firefox, Edge.
Best regards - Ulrich
That’s caused by your requirement for the reflection to be flipped - not much can be done about that, unless you’ll involve real raytracing Mugen mentioned earlier.
Gotchu, so first of all - there’s a bit of magic happening with these materials that make them look ok - that includes never touching transmission: .99. Otherwise you’ll render body colour and reflections of the external sphere.
To make the edge show more / less, you can add envMapIntensity and set it to anything from 0.0 to infinity (technically you’re only allowed to set it between 0.0 - 1.0, but rules are there to be broken. Setting intensity above 1.0 basically counters the fact that we set transmission to nearly 1.0):
// Add refraction (inner sphere)
new THREE.SphereBufferGeometry(2, 32, 32),
// Add reflection (half-transparent outer sphere)
new THREE.SphereBufferGeometry(2 + Number.MIN_VALUE, 32, 32),
envMapIntensity: 2.0, // <- Changing this changes the fake fresnel effect
transmission: .99, // <- Changing this will reveal that it's just fake fresnel, so lets never do that
If you’d change transmission or opacity (or going too high with envMapIntensity) on either sphere you’ll start seeing this reflections also in the middle of the sphere, and it’s not good:
I wouldn’t judge it that fast. GLSL is very simple - it’s the math that can make shaders complex. Here’s an example of a shader that creates a real Fresnel effect: