How to Improve Vanilla Three.js Fidelity?

Hey guys, this is something I’ve wanted to ask about for a long time, and I hope someone can fill me in. Why does R3F look better and more visually appealing than vanilla Three.js? Even the basic example of a cube in a scene looks ten times better than vanilla Three.js. Are there any tips one can use to achieve the same level of fidelity in vanilla Three.js?

Can you post an example?

Probably because by default r3f does some nice quality of life configuration of the renderer… like enabling antialising and enabling tonemapping etc.

Given most things are the same here the ref scene looks better than vanilla threejs. Or is it just subjective? Even the OrbitControls have a better feel/smoothness.

R3F does some things for you under the hood. Maybe it is just a matter of differently set initial values or processing. For example, the smoothness in vanilla can be done by enabling damping and using controls’ update method:

let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // <--- add this line

function animation( time ) {
    controls.update(); // <--- and add this line
    mesh.rotation.x += .01
	renderer.render( scene, camera );

I got them to look pretty close by changing some defaults:

1 Like

this will be a long post, summing up some of the defaults and components in the fiber eco system that produce handsome results.

srgb encoding

i think threejs is gamma correct out of the box nowadays …

filmic tonemapping

it should be a recommendation because it gives you more dynamic range, less banding.

renderer.toneMapping = THREE.ACESFilmicToneMapping

photographic envmaps

one of the most important keys. figure out how to render shapes into a environment map and crank their RGB values so that they emit light, that way you can “paint” light, just like a photographer would do. you can start with this tutorial, it translates to vanilla as well. this is how harsh pointlights/spotlights stack up against a photographic envmap:

a component eco system

there are dozens of components in the eco system that improve visuals, for instance soft shadows, reflections, proper refractive materials, a better effect pipeline (using the vanilla postprocessing library) and so on. this makes it very easy to get good looking results.

oop vs fp

you will notice that many or most of these things are not easily available in vanilla. this is solely because there is a fundamental difference between oop and fp: composition.
a class can’t compose, and bind self contained functionality. it requires the environment to conform and the end user to inject dependencies. it has no awareness of its sourroundings and can’t react to changes dynamically.
without this threejs can’t foster an eco system of interoperable parts, and that’s probably the biggest limitation that is has: people can’t share the solutions they found to their particular problems, at least not beyond examples and snippets.
this is what fiber adds to three: whatever you struggle with has been solved and shared.


Some good ideas were presented. Can we leverage post-processing to push the results further? If so what kind of post-processing shader?

use GitHub - pmndrs/postprocessing: A post processing library for three.js. over three/examples/jsm/effect-composer any time. you get better effect selection, and it is much much faster.

basics are ao, preferrably n8ao, and bloom. like so: eager-wave-6kxmtp - CodeSandbox

the difference between ootb, and envmap + soft-shadows + ao + bloom:

all of this is available in vanilla, n8ao for instance you find here GitHub - N8python/n8ao: An efficient and visually pleasing implementation of SSAO with an emphasis on temporal stability and artist control.
soft-shadows are in vanilla-drei GitHub - pmndrs/drei-vanilla: 🍦 drei-inspired helpers for threejs