Using a video as a light cookie only shows first frame

I’m trying to use a video as a spot light cookie, but I can only get the first frame to display. If I use the same texture instance on a different piece of geometry I can see the video is playing fine on there, it’s just not updating on the cookie projection. Also, the cookie scale seems to have no effect.

The code I’m using is mainly taken from the example here https://playcanvas.com/editor/scene/1345100 which I can see is working (unless I fork the project, in which case not working at all) so I’m at a loss.

Any suggestions gratefully received.

const args = {
    ...opts,
    affectLightmapped: true,
    affectDynamic: true,
    normalOffsetBias: 0.2,
    color: getColourOpt(opts),
    falloffMode: LIGHTFALLOFF_INVERSESQUARED,
  };
  const light = entity.addComponent('light', args) as LightComponent;

const setupVideoTexture = () => {
    try {
         video.play();
      }
    } catch (e) {
      // If video is no longer loaded then skip
      console.warn('Unable to load video', e);
    }
  };

  const videoUpload = () => {
    if (videoTexture) {
      videoTexture.upload();
    }
  };

  const destroyVideo = () => {
    videoTexture.destroy();
    video.remove();
  };

  const video = document.createElement('video');
  video.id = 'light_cookie_vid' + Date.now();
  video.loop = true;

  // muted attribute is required for videos to autoplay
  video.muted = true;

  // critical for iOS or the video won't initially play, and will go fullscreen when playing
  video.playsInline = true;

  // needed because the video is being hosted on a different server url
  video.crossOrigin = 'anonymous';

  // autoplay the video
  video.autoplay = true;

  // iOS video texture playback requires that you add the video to the DOMParser
  // with at least 1x1 as the video's dimensions
  var style = video.style;
  style.width = '1px';
  style.height = '1px';
  style.position = 'absolute';
  style.opacity = '0';
  style.zIndex = '-1000';
  style.pointerEvents = 'none';
  document.body.appendChild(video);

  // Create a texture to hold the video frame data
  const videoTexture = new Texture(app.graphicsDevice, {
    format: PIXELFORMAT_R8_G8_B8,
    minFilter: FILTER_LINEAR_MIPMAP_LINEAR,
    magFilter: FILTER_LINEAR,
    addressU: ADDRESS_CLAMP_TO_EDGE,
    addressV: ADDRESS_CLAMP_TO_EDGE,
    mipmaps: true,
  });
  videoTexture.setSource(video);

  video.addEventListener('canplaythrough', setupVideoTexture);

  video.src = spotOpts.cookieURL;
  document.body.appendChild(video);
  video.load();

  app.scene.lighting.cookiesEnabled = true;
  light.cookie = videoTexture;
  light.cookieScale = new Vec2(1.777777, 1);

  app.on('destroy', function () {
    app.off('update', videoUpload);
    video.removeEventListener('canplaythrough', setupVideoTexture);

    destroyVideo();
  });

  app.on('update', videoUpload);

Hi … yes, this is currently not support for the clustered lighting. I’ve created a ticket here to implement this: Clustered lighting cookie renderer should support changes to the texture. · Issue #4926 · playcanvas/engine · GitHub

The easiest workaround for now is to disable the clustered lighting. The older lighting system supports this.

1 Like

That’s great, thanks for the info and the very rapid response…much appreciated!