How to render a non-metal cube more realistically?

I tried LightProbe but the faces of the cube are still with flat color:

In real world, there should be some subtle brightness / hue changing in each face. What are the cheap approaches to make it more realistic?

Do you have an environment map here? (scene.environment or material.envMap) That’s going to be the highest-quality lighting you can get, generally.

A “light probe” in three.js does not automatically capture its surroundings; you have to initialize it with some light information. So knowing you have a light probe in the scene doesn’t tell us much – with a solid color a light probe is the same as an ambient light.

Hey I basically implemented threejs’ lightProbe example with r3f.

export function LightProbTest() {
  const { gl, scene } = useThree();

  const cubeRT = new WebGLCubeRenderTarget(256, {
    encoding: sRGBEncoding, // since gamma is applied during rendering, the cubeCamera renderTarget texture encoding must be sRGBEncoding
    format: RGBAFormat,
  });

  const cubeTexture = useCubeTexture(
    ["px.png", "nx.png", "py.png", "ny.png", "pz.png", "nz.png"],
    { path: "/textures/cube/" }
  );

  cubeTexture.encoding = sRGBEncoding;

  scene.background = cubeTexture;

  const cubeCameraRef = useRef<CubeCamera>();
  const lightProbeRef = useRef<LightProbe>();

  useLayoutEffect(() => {
    cubeCameraRef.current?.update(gl, scene);
    lightProbeRef.current?.copy(
      LightProbeGenerator.fromCubeRenderTarget(gl, cubeRT)
    );

  }, []);

  return (
    <>
      <cubeCamera args={[1, 1000, cubeRT]} ref={cubeCameraRef} />
      <lightProbe ref={lightProbeRef} />
    </>
  );
}

And in the original example the envMap is created via:

const genCubeUrls = function ( prefix, postfix ) {

  return [
    prefix + 'px' + postfix, prefix + 'nx' + postfix,
    prefix + 'py' + postfix, prefix + 'ny' + postfix,
    prefix + 'pz' + postfix, prefix + 'nz' + postfix
  ];

};

const urls = genCubeUrls( 'textures/cube/pisa/', '.png' );

new THREE.CubeTextureLoader().load( urls, function ( cubeTexture ) {

  cubeTexture.encoding = THREE.sRGBEncoding;

  scene.background = cubeTexture;

  cubeCamera.update( renderer, scene );

  lightProbe.copy( LightProbeGenerator.fromCubeRenderTarget( renderer, cubeRenderTarget ) );

  scene.add( new LightProbeHelper( lightProbe, 5 ) );

  render();

} );

There seems to be no updates on scene.environment or material.envMap…?

Not sure what you mean here – the code above does not set scene.environment or material.envMap anywhere that I can see. I’d suggest setting scene.environment in addition to scene.background.

A light probe collapses all lighting information from a cubemap into directional coefficients (“spherical harmonics”) at the probe’s location. Since the faces of a cube are flat, and all parts of a face have the same normal vector, you aren’t going to see subtle changes across the surface of the cube with a single light probe.

1 Like