R3F Lightformers in vanilla three js

Trying to get a basic lightformer setup into vanilla JavaScript

after looking into roomEnvironment.js like mentioned in this thread

the thing i noticed are

  • pmremGenerator takes out hdr cubemap renders of the scene/object passed
  • all light emitting meshes have color rgb values much greater than 1 : demo
  • if you pass a mesh with hdri no data seems to be lost: demo
  • using different shapes and sizes of mesh we can have more creative lighting setups like this r3f demo

Also checked out the lightformer/env editor https://env.pmnd.rs/ looks amazing + awesome UI .


  • checked the drei lightformers.tsx file but pmrem is never mentioned
  • If i update env on animate loop the on phone the fps drops alot
  • how do you change the resolution of pmrem ?

@drcmda how close am i ?

you do not need pmrem.fromScene, just a regular cubecamera that films a virtual THREE.Scene into a THREE.WebGLCubeRenderTarget. i say virtual because it’s not part of the normal scene you render out. the cube-cam-scene contains light formers, softboxes and so on. the texture result of that rendertarget can plug right into your main scene.background and/or .environment.

now every time you call cubecam.update() it will render into the texture again, and if you render every frame you have a realtime environment map. runtime env doesn’t work on all platforms, that’s why all these r3f demos have <PerfMonitor> which makes it static if it detects problems with the fps.


Is this the code for the cube camera being used here ?, want to check the type, encoding ,filter etc

more or less yes, it happens here drei/Environment.tsx at 5faa042c225d370b4cbacbc8f007ab4cafd3fddd · pmndrs/drei · GitHub

in principle it’s just this:

  // This is the scene that receives the lightformers
  const virtualScene = new THREE.Scene()

  const fbo = new THREE.WebGLCubeRenderTarget(resolution)
  fbo.texture.type = THREE.HalfFloatType
  const cam = new THREE.CubeCamera(near, far, fbo)

  scene.environment = fbo.texture

let count = 1
function loop() {
  if (frames === Infinity || count < frames) {
    cam.update(gl, virtualScene)

btw this is a good opportunity to hash out a generic structure for loop access, resize and overall reactivity. maybe something like a base class from which all your primitives inherit.

1 Like