Dynamic Reflections

The dynamic reflections works fine on threejs v124 but breaks in v135(black object). Can anyone let me know if there are any dependencies deprecated. I am using cubecamera.renderTarget.texture to set the envmap of gltf object.



I am using a directional light and point light in both the cases. The only difference between both is the version of threejs. @Mugen87

Please share your code so it’s clear what you are doing. Ideally, you share it as a live example.

I’m using a init pipeline done by 8thwall:

You can check it out at: three.js: Realtime Reflections | 8th Wall Playground | 8th Wall

import * as THREE from "three";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";

window.THREE = THREE;

export const initScenePipelineModule = () => {
const { XR8 } = window; 
  let renderer_ = null
  const camTexture_ = new THREE.Texture()
  const loader = new GLTFLoader()
  const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256, {
    format: THREE.RGBFormat,
    generateMipmaps: true,
    minFilter: THREE.LinearMipmapLinearFilter,
    encoding: THREE.sRGBEncoding,
  const refMat = new THREE.MeshBasicMaterial({
    side: THREE.DoubleSide,
    color: 0xffffff,
    map: camTexture_,
  // cubemap scene
  const cubeMapScene = new THREE.Scene()
  const cubeCamera = new THREE.CubeCamera(1, 1000, cubeRenderTarget)
  const sphere = new THREE.SphereGeometry(100, 15, 15)
  const sphereMesh = new THREE.Mesh(sphere, refMat)
  sphereMesh.scale.set(-1, 1, 1)
  sphereMesh.rotation.set(Math.PI, -Math.PI / 2, 0)
  // Populates a cube into an XR scene and sets the initial camera position.
  const initXrScene = ({scene, camera, renderer}) => {
    // Enable shadows in the renderer.
    renderer.shadowMap.enabled = true
    renderer.outputEncoding = THREE.sRGBEncoding
    // Add some light to the scene.
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
    directionalLight.position.set(0, 10, 0)
    directionalLight.castShadow = true
    // Add some light to the scene.
    const ambientLight = new THREE.AmbientLight(0xffffff, 1)
    // GLTF Model
      (gltf) => {
        gltf.scene.traverse((o) => {
          if (o.isMesh) {
            o.material.envMap = cubeRenderTarget.texture
            o.castShadow = true
        gltf.scene.position.set(0, 0.5, 0)
        gltf.scene.scale.set(3, 3, 3)
    // Add a plane that can receive shadows.
    const planeGeometry = new THREE.PlaneGeometry(2000, 2000)
    planeGeometry.rotateX(-Math.PI / 2)
    const planeMaterial = new THREE.ShadowMaterial()
    planeMaterial.opacity = 0.5
    const plane = new THREE.Mesh(planeGeometry, planeMaterial)
    plane.receiveShadow = true
    // Set the initial camera position relative to the scene we just laid out. This must be at a
    // height greater than y=0.
    camera.position.set(0, 2, 2)
  // Return a camera pipeline module that adds scene elements on start.
  return {
    // Camera pipeline modules need a name. It can be whatever you want but must be unique within
    // your app.
    name: 'threejsinitscene',
    // onStart is called once when the camera feed begins. In this case, we need to wait for the
    // XR8.Threejs scene to be ready before we can access it to add content. It was created in
    // XR8.Threejs.pipelineModule()'s onStart method.
    onStart: ({canvas}) => {
      const {scene, camera, renderer} = XR8.Threejs.xrScene()  // Get the 3js scene from XR8.Threejs
      renderer_ = renderer
      initXrScene({scene, camera, renderer})  // Add objects set the starting camera position.
      // Sync the xr controller's 6DoF position and camera paremeters with our scene.
        {origin: camera.position, facing: camera.quaternion}
      // prevent scroll/pinch gestures on canvas
      canvas.addEventListener('touchmove', (event) => {
      // Recenter content when the canvas is tapped.
        'touchstart', (e) => {
          e.touches.length === 1 && XR8.XrController.recenter()
        }, true
    onUpdate: () => {
      const {scene, camera, renderer} = XR8.Threejs.xrScene()
      cubeCamera.update(renderer, cubeMapScene)
    onProcessCpu: ({frameStartResult}) => {
      const {cameraTexture} = frameStartResult
      // force initialization
      const {scene, camera, renderer} = XR8.Threejs.xrScene()  // Get the 3js scene from XR8.Threejs
      const texProps = renderer.properties.get(camTexture_)
      texProps.__webglTexture = cameraTexture

From r132 up to r136, CubeCamera could not be combined with PBR materials. I suggest you upgrade to r137 or even better to the latest version r141.

When doing so, you have to remove this line though:

because THREE.RGBFormat has been removed with r137.

Thanks @Mugen87 for the suggestion of upgrading. The example seems to work fine now in v137 but a few other things break in my custom pipeline. Will look into it. Are there any significant changes in how lights are added to the scene from v135 → v137?

Also, the reflections work fine in v137 but not in v141. Just a heads up for your investigation.

Migration Guide:

There should be no breaking changes in context of classic punctual lights. However, there might be a migration task if you are using a HDR workflow (meaning you use a HDR environment map for lighting your scene).