Video textures fit mode

Hi there,

I’m using video textures on my project, and I’d like to make them fit into the render the same way we would do in CSS with background-size: cover; The videos can be vertical or horizontal, 4:3 or 16:9, any video really.

Here the current code :

var VideoTexture = pc.createScript('videoTexture');


VideoTexture.attributes.add('videoUrl', {
    title: 'Video Url',
    description: 'URL to use if there is video asset selected',
    type: 'string'
});


// initialize code called once per entity
VideoTexture.prototype.initialize = function() {
    var app = this.app;

    // Create HTML Video Element to play the video
    var video = document.createElement('video');
    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
    this.videoTexture = new pc.Texture(app.graphicsDevice, {
        format: pc.PIXELFORMAT_R8_G8_B8,
        minFilter: pc.FILTER_LINEAR_MIPMAP_LINEAR,
        magFilter: pc.ADDRESS_CLAMP_TO_EDGE,
        addressV: pc.ADDRESS_CLAMP_TO_EDGE,
        mipmaps: true
    });
    this.videoTexture.setSource(video);

    video.addEventListener('canplaythrough', function (e) {
      var material = new pc.StandardMaterial();
        material.diffuse = new pc.Color(0, 0, 0, 1);
        material.emissive = new pc.Color(0, 0, 0, 1);
        material.emissiveMap = this.videoTexture;
        material.emissiveIntensity = 1;
        material.update();
        this.entity.render.material = material;
        video.play();
    }.bind(this));

    // set video source
    video.src = this.videoUrl;

    document.body.appendChild(video);
    video.load();

    this.on('destroy', function() {
        this.videoTexture.destroy();
        video.remove();
    }, this);
};

// update code called every frame
VideoTexture.prototype.update = function(dt) {
    // Transfer the latest video frame to the video texture
    this.videoTexture.upload();
};

Any idea on how to proceed ?

What are you trying to fit in? If you are using the texture on a 3D model like a plane, you will have to scale the plane to fit the aspect ratio. You will have to use stencilling to mask it to ‘cover’.

Alternatively, you could try changing the tiling and offset of the texture on the material to achieve the effect which would probably be a lot easier.

I’m indeed only using a plane. Some of them are vertical, some of them horizontal. I won’t be the one putting in the contents. I built a scene that can be updated by others, not in the editor, but through an interface of mine. Once they have uploaded their video, another script in the launcher will fetch the url of the video and use it as the texture’s source. So I can’t really have a fixed tiling on the material because I don’t know exactly what the content is going to be for a specific screen.

You can change the tiling at runtime based on the video aspect ratio. I believe you can get the height/width via HTMLVideoElement: videoWidth property - Web APIs | MDN

Sounds great ! Thanks @yaustar !