Glossy spheres in Three.js
A simple trick to improve the quality of your Three.js scenes
Recently I’ve been on mr.doob’s website and I’ve been amazed by all his experiments.
I hadn’t (and for the most part, still haven’t) idea how to achieve such a level of quality with Three.js, therefore I decided to dive into his code and try to learn one cool thing at a time.
I haven’t found any clear explanation about this topic on the internet, so here it is! Hopefully this will save a couple hours to someone :)
(here you can find part 2 on animations with alpha textures and here another post on real-time reflections)
Glossy effect
Among the cool things from mr.doob’s screne was the photo realistic glossy effect of his materials, I decided to exploring the code from there.
What I want to achieve:
(I’m going to talk about the material, not lights and background).
First of all, set this options in your WebGLRenderer
renderer.gammaInput = true;
renderer.gammaOutput = true;
To achieve that nice glossiness we have to use a THREE.MeshStandardMaterial, the new physically accurate material in Three.js.
var material = new THREE.MeshStandardMaterial({color: “#000”, roughness: 0});
At this point we have this:
We’re not quite there yet.
In order to have a believable glossy effect we need a reflex of something. The fastest way to create a reflex is to fake it with a texture. (an heavier solution would be to use real-time reflections)
Here’s the texture:
Let’s add it to our material as an environment map. (You can read more about the topic here)
var envMap = new THREE.TextureLoader().load('envMap.png');
envMap.mapping = THREE.SphericalReflectionMapping;
material.envMap = envMap;
And that’s what we’ve got now:
Here’s our glossy ball! Pretty cool, I’d say :)
Now if you feel fancy it’s possible to add some nice roughness to the material simply by using another texture. First of all let’s change the material’s roughness from 0 to 1, and then add the new texture.
Here’s the texture:
var material = new THREE.MeshStandardMaterial({color: “#000”, roughness: 1});var roughnessMap = new THREE.TextureLoader().load('roughnessMap.png');
roughnessMap.magFilter = THREE.NearestFilter;
material.roughnessMap = roughnessMap;
Et voilà! that’s pretty close to what mr.doob has on his website, not considering light and background.
Complete example:
var geometry = new THREE.SphereGeometry(30, 64, 64);
var material = new THREE.MeshStandardMaterial({ color: “#000”, roughness: 1 });
var envMap = new THREE.TextureLoader().load(‘envMap.png’);
envMap.mapping = THREE.SphericalReflectionMapping;
material.envMap = envMap;var roughnessMap = new THREE.TextureLoader().load(‘roughnessMap.png’);
roughnessMap.magFilter = THREE.NearestFilter;
material.roughnessMap = roughnessMap;roughnessMap.magFilter = THREE.NearestFilter;
material.roughnessMap = roughnessMap;var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Here’s a codepen for you to play around with (the textures are loaded as data uri, to avoid references external to the codepen).
Note: it won’t be so easy to achieve this effect in something other than a sphere. But probably mapping a different environment map with a different technique could help.
If you want real reflections from the environment of your mesh, take a look at CubeCamera.
Where can you find me?
Follow me on Twitter: https://twitter.com/psoffritti
My website/portfolio: pierfrancescosoffritti.com
My GitHub account: https://github.com/PierfrancescoSoffritti
My LinkedIn account: linkedin.com/in/pierfrancescosoffritti/en