tentone / nunuStudio

Web powered cross-platform 3D, WebXR game engine.
https://nunustudio.org
MIT License
2.13k stars 320 forks source link

Unable to load VideoTextures dynamically #422

Open helzapps opened 4 years ago

helzapps commented 4 years ago

VideoTexture assigned to standard materials emissiveMap throw WebGL error

Description

function loadVideos() { var materialNames = ["video_left"]; //,"plane_center","plane_right" var videoNames = ["video1.mp4"]; //,"video2.mp4","video3.mp4" for (var index = 0; index < videoNames.length; index++) { var matName = materialNames[index]; var vName = videoNames[index]; var texture = new VideoTexture(new VideoStream(../videos/${vName})); var material = program.getMaterialByName(matName); material.emissiveMap = texture; material.emissive.setHex(0xFFFFFF); } }


 - Published for web
 - Attempted to load web page (using MAMP)

Expected Results: To see my `video1.mp4` playing on the plane on the left hand side
Actual Results: Video is not playing. Received several warnings in the console and 
>WebGL: INVALID_VALUE: tex(Sub)Image2D: video visible size is empty
>[.WebGL-0x7fbf81073600]RENDER WARNING: texture bound to texture unit 0 is not renderable. It might be non-power-of-2 or have incompatible texture filtering (maybe)?
...
>WebGL: too many errors, no more errors will be reported to the console for this context.

##### Version
 - 0.98.12 (2020-07-25T14:15:20.001Z)

##### Platform
 - Web Version [X]
 - Windows [ ]
 - Linux [ ]
helzapps commented 4 years ago

Archive.zip Here is a sample project for ease in recreating. Note, the videos folder was intentionally left empty as the videos I'm testing with cannot yet be shared in the public domain as they are property of my clients. So to make it work just add any video and name it video1.mp4.

helzapps commented 4 years ago

Ok, so I'm newer to Web Development (been doing native iOS for 10 years) and I learned that you cannot preload videos for video tags unless the user interacts with the screen (click or touch).

I noticed with our full site in updates that we are making to embed it into a mobile app that for relaunches I wanted to load right into the booth without the user having to do anything. When I did this, video textures wouldn't load, just like this bug. But if the user tapped through like normal on initial launch, they loaded just fine.

So I essentially had to just add a simple interim page where the user clicked Enter Booth and voila, the videos were there on the walls/textures as expected. So I've rezipped up the package (sans videos folder, so to make it work just unzip, add a videos folder with three videos named video1.mp4, video2, etc).

Run the page, click enter booth and working as expected now. If anything you could change this from a bug to a feature request to update the default web exports index.html with a start or run button so if someone is doing such an example tutorial as the video one, they don't run into this issue thinking it doesn't work. I'll leave it to you @tentone to change or close.

Thanks for all the help! Hope you're having a good weekend.

VideoTexturLoadUpdate.zip

tentone commented 4 years ago

Hello

Thanks a lot i was having a pretty hard time debuging this since it seemed to be working correctly here.

The message you referred WebGL: INVALID_VALUE: tex(Sub)Image2D: video visible size is empty... is actually a usual warning that happens when we try to render a texture that has not finished uploading to the GPU usually it shows up for a couple of frames and then goes away.

I will see if i can overcome this issue by attaching some click event to the canvas, and only display the videos/audio after the canvas has been touched witch is something that user usually does right away.

Thanks a lot once again. You have been of great help.

denkerinteraktivgmbh commented 4 years ago

Hi, we had issues with this as well and ended up with adding the video file as an DOMelement first. Make sure that is has the attribute muted=true. Then the video will start playing without any user interaction needed.

        var video = document.createElement("video");
    let id = "led_video";
    video.id = id;
    video.crossOrigin = "anonymous";
    video.src = "http://localhost/video.mp4";
    document.body.appendChild(video);
    var video = document.querySelector("#"+id);
    video.style.width= "1px";
    video.style.height = "auto";
    video.style.position = "absolute";
    video.preload = 'auto';
    video.autoload = true;
    video.setAttribute('playsinline', 'true');
    video.loop = true;
    video.autoplay=true;
    video.muted = true;
    var texture = new THREE.VideoTexture(video);
    var material = program.getMaterialByName("video_material");
    material.emissiveMap = texture;
    material.emissive.setHex(0xFFFFFF);
MaxTechCodes commented 1 year ago

hello, I found the proper video streaming method taking care of first user interaction issue and disposal. Please set Library Mode as 'Evaluate' for the script.

let texture, material, video2; const videoLink = 'https://............ .mp4'. // your video hyperlink

function initialize() { // TODO ADD CODE addVideo();

}

function update(delta) { // TODO ADD CODE

}

function dispose() { if(document.getElementById('led_video')){ program.division.removeChild(video); texture.dispose(); } }

function addVideo(){ video2 = document.createElement("video"); let id = "led_video"; video2.id = id; video2.crossOrigin = "anonymous"; video2.src = videoLink video2.style.width= "1px"; video2.style.height = "auto"; video2.style.position = "absolute"; video2.preload = 'auto'; video2.autoload = true; video2.setAttribute('playsinline', 'true'); video2.loop = true; video2.autoplay=true; video2.pause(); video2.muted = false; program.division.appendChild(video2); texture = new THREE.VideoTexture(video2); material = program.getMaterialByName("standardVideo2"); // your video texture reference material.map = texture; program.canvas.addEventListener("click", playNow);

}

function playNow(){ if(video2.paused) video2.play();

}