VideoTexture on 3D Object - Problem Appear Transparent


I try to render a VideoTexture on a 3D Object. This is for a AR application.
It works with local video but external https video do not work.
Maybe have you an idea?

<!DOCTYPE html>
<html lang="en">
  <title id="bb">My Header</title>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <link type="text/css" rel="stylesheet" href="main.css">

<video id="video" loop crossOrigin="anonymous" webkit-playsinline style="display:none">
  <source src="video.mp4" type="video/mp4">   
  // and set JS variable:
  <div id="info">
    <p id="exciting">The most exciting paragraph on the page. One of a kind!</p>

  <script src="three.js"></script>
  <script src="OBJLoader.js"></script>
  <script src="MTLLoader.js"></script>
  <script src="utils.js"></script>
  <script src="appAR.js"></script>
  <script type="module">

  import * as THREE from './build/three.module.js';
  import { ARButton } from './jsm/webxr/ARButton.js';

  let container;
  let camera, scene, renderer;
  let controller;

  let reticle;
  let mesh, video, texture;

  let hitTestSource = null;
  let hitTestSourceRequested = false;
let videoTexture;
let videoImageContext ;

  function init() {

    container = document.createElement( 'div' );
    document.body.appendChild( container );

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera();
    camera.matrixAutoUpdate = false;

    var updateFcts = [];

        renderer = new THREE.WebGLRenderer( { antialias: true } );

        renderer.autoClear = false;
        renderer.setPixelRatio( window.devicePixelRatio );
        renderer.setSize( window.innerWidth, window.innerHeight );
        renderer.xr.enabled = true;
        container.appendChild( renderer.domElement );


        document.body.appendChild( ARButton.createButton( renderer, { requiredFeatures: [ 'hit-test' ] } ) );


        function onSelect() {

          if ( reticle.visible ) {

  // = 'video';
  // video.type = ' video/ogg; codecs="theora, vorbis" ';
  video = document.getElementById( 'video' );
     texture = new THREE.VideoTexture( video );
    texture.minFilter = THREE.LinearFilter;
    texture.magFilter = THREE.LinearFilter;
    texture.format = THREE.RGBFormat;
    var geometry = new THREE.PlaneBufferGeometry( 2, 1);

    var materialVideo = new THREE.MeshBasicMaterial( { map: texture , side: THREE.DoubleSide } );

    mesh = new THREE.Mesh( geometry, materialVideo);
      mesh.position.setFromMatrixPosition( reticle.matrix );
    scene.add( mesh );;



controller = renderer.xr.getController( 0 );
controller.addEventListener( 'select', onSelect );
scene.add( controller );

reticle = new THREE.Mesh(
  new THREE.RingGeometry( 0.15, 0.2, 32 ).rotateX( - Math.PI / 2 ),
  new THREE.MeshBasicMaterial()
reticle.matrixAutoUpdate = false;
reticle.visible = false;
scene.add( reticle );


        window.addEventListener( 'resize', onWindowResize );


      function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;

        renderer.setSize( window.innerWidth, window.innerHeight );



      function animate() {

        renderer.setAnimationLoop( render );


      function render( timestamp, frame ) {

        if ( frame ) {

          const referenceSpace = renderer.xr.getReferenceSpace();
          const session = renderer.xr.getSession();

          if ( hitTestSourceRequested === false ) {

            session.requestReferenceSpace( 'viewer' ).then( function ( referenceSpace ) {

              session.requestHitTestSource( { space: referenceSpace } ).then( function ( source ) {

                hitTestSource = source;

              } );

            } );

            session.addEventListener( 'end', function () {

              hitTestSourceRequested = false;
              hitTestSource = null;

            } );

            hitTestSourceRequested = true;


          if ( hitTestSource ) {

            const hitTestResults = frame.getHitTestResults( hitTestSource );

            if ( hitTestResults.length ) {

              const hit = hitTestResults[ 0 ];

              reticle.visible = true;
              reticle.matrix.fromArray( hit.getPose( referenceSpace ).transform.matrix );

            } else {

              reticle.visible = false;



    if ( video.readyState === video.HAVE_ENOUGH_DATA ) 
    if ( texture ) 
      texture.needsUpdate = true;

        renderer.render( scene, camera );



      <script src="js/app.js"></script>


Do you have an example or more complete code? Your code doesn’t make sense. You have to set the mesh position from reticle every frame, and also set the camera position, look at etc.
Also, how do you know it’s transparent? can you see it partially?

Maybe these examples from the Collection of examples from will help?

BeginnerExample step4



Thanks for your answer,
I updated the code in my first post, if you have android and chrome you can test the AR app via the link below.

The scenario is when the reticle is on the ground, the user tap the reticle (function onSelect())
to place the “Plane Object Video Texture”.

I see it’s transparent because when you place the object and move the reticle through, you see the border of the object and the real environment through.

Oh, I just saw that you are using THREEx.VideoTexture, I don’t have any idea about that and it’s last published 4 years ago, so I doubt it would work anymore properly.

Why don’t you use the VideoTexture in threejs: three.js docs

I updated my Code with VideoTexture code.
Good news, the video works but only with local video and not with url .
How to make it work with url?

see Projector the video
=> Edit fiddle - JSFiddle - Code Playground basis from Video

VideoTexture works well, but I only arrive to make it works with local video, do you have an idea why https video url do not work?

Not sure about the exact how and when, but browsers sometimes only allow the video to be played after the user interacts with the page. Did you try a ‘play’ button?

I created a GUI play button, and the result is the same Video URL not work.

Thanks you very much for all your examples,

My code from my initial post work, but I only arrive to display video who are stored locally.
I tried this to integrate https url like below but it doesn’t work, nothin display.

<video id="video" loop crossOrigin="anonymous"  playsinline style="display:none" >	
		<source src="" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>	

There is no difference between my code and your examples,
Really stuck now, maybe is it a problem with requesting https without certificate or proxy? My app is served via https…

Isn’t it just a CORS issue (You’re trying to show video’s that are not stored on your own server)?

It’s obviously not a three.js problem then. It makes sense to ask in an appropriate forum.

I use the configuration as described there:
* Local use of the examples

I can load the video locally or from external.

For example from
Just tested again.

The video link simply copied into the browser also works. Everything is ok there.

So the might work also for you, because cross origin is specified in the http headers for this domain:

Cross-Origin-Resource-Policy: cross-origin

This is not the case for the site. I think these example movies can only be used in video textures from the domain itself.

Thanks a lot for your precious help,
I tried the link
and I got this error.

Access to fetch at ‘ ’ from origin has been blocked by CORS policy: Request header field range is not allowed by Access-Control-Allow-Headers in preflight response.

The video link work directly within the web browser, but if I integrate the link inside my app-website it create a CORS error.

My app-website is hosted on Netlify, maybe the problem come from them.

I recommend downloading said resource to your local computer, then upload it from there to your webspace on Netlify and source from there.