I’m trying to add a video element to three.js / editor, but I can’t do it. Is it possible to add a video texture without getting involved in adding new elements to HTML? For example, using a link?
let video, videoTexture, movieScreen;
video = 'URL TO VIDEO';
videoTexture = new THREE.VideoTexture(video);
videoTexture.needsUpdate = true;
const videoMaterial = new THREE.MeshBasicMaterial({ map: videoTexture, side: THREE.DoubleSide });
const planeGeometry = new THREE.PlaneGeometry( video.videoWidth, video.videoHeight, 4, 4 );
videoElem = new THREE.Mesh(planeGeometry, videoMaterial);
this.add(videoElem);
I don’t think it’s going to work that way. But I don’t understand how to make this code work. Thank you all for your help!
I also tried to add videomaterial to the editor… it’s complicated than I thought, since you need to understand the structure/architecture of the editor code.
create a MeshVideoMaterial.js in editor/js/
import * as THREE from 'three';
class MeshVideoMaterial extends THREE.MeshBasicMaterial {
constructor(parameters = {}) {
// Create the video element
const video = document.createElement('video');
video.src = 'http://localhost:8083/editor/images/video.MOV'; //fixed video as example
video.loop = true;
video.style.display = 'none'; // Hide the video element
document.body.appendChild(video);
// Wait for the video to load and play
video.play();
editor.renderActive = true; //ugly hack
// Create the VideoTexture
const texture = new THREE.VideoTexture(video);
texture.needsUpdate = true;
super({ userData: {type:"videomaterial"}, map: texture, ...parameters });
}
}
export { MeshVideoMaterial };
in the Sidebar.Material.js:
import { MeshVideoMaterial } from './MeshVideoMaterial.js';
//add this line in the materialClasses object:
'MeshVideoMaterial': MeshVideoMaterial
//and this line in the meshMaterialOptions object:
'MeshVideoMaterial': 'MeshVideoMaterial'
//and somewhere define the play and pause buttons to showup in the sidebar:
const playButton = new UIButton('Play').onClick(() => {
editor.selected.material.map.image.play();
editor.renderActive = true; //ugly flag for renderer later
});
const pauseButton = new UIButton('Pause').onClick(() => {
editor.selected.material.map.image.pause()
editor.renderActive = false; //ugly flag for renderer later
});
container.add(playButton);
container.add(pauseButton);
now in the Viewport.js:
//since I didn't know how to push tasks to the renderloop..
//more ugly hacks; add this somewhere:
setInterval(() => {
if(editor.renderActive){
render();
}
}, 10);
Selectable MeshVideoMaterial (but since the type is MeshbasicMaterial, after selection the selected type will still show MeshBasicMaterial):
You may have to wait until the user has clicked once, in order to begin playing the video…
Which might be what causes the perception that it has to be added to the dom…
To serialize it, you can stick the url in the texture.userData and rebuild the video after loading…
You don’t need, maybe you can access the video data alao directly on the video element, but the example you send is doing it exactly like I am doing it, check the code in your link.
I mean paste this script into an object script in the editor:
function init(){
let video = document.createElement( 'video' );
video.id = "video"
video.setAttribute("crossOrigin","anonymous");
video.setAttribute("src", "../examples/textures/sintel.mp4");
video.play();
let texture = new THREE.VideoTexture(video);
this.material.map = texture;
}
and it will replace the material with the sintel video.
I think the workaround with the video script is nice - but in the end I would like to have a simple to use solution for the endusers… being able to select the video in the map option of the material would be still nice.
also how would I push the update() function into the useFrame or the animation loop?
else { // or you could also detect the exact video type
reader.addEventListener('load', function (event) {
const video = document.createElement('video');
video.addEventListener('loadeddata', function () {
const videoTexture = new THREE.VideoTexture(this);
videoTexture.sourceFile = file.name;
videoTexture.needsUpdate = true;
cache.set(hash, videoTexture);
scope.setValue(videoTexture);
if (scope.onChangeCallback) scope.onChangeCallback(videoTexture);
}, false);
// Assuming the loaded file is a video
video.src = URL.createObjectURL(file);
video.play(); // Start playback immediately (optional)
video.loop = true;
}, false);
reader.readAsDataURL(file);
}
on the line 167 in editor/js/libs/ui.three.js
final question is: how to make this run in the “play” mode of the editor?