truly-daunting
truly-daunting

Reputation: 75

Video texture playing but showing black

I'm trying to create a video texture. My code will add the video to my scene, however my cube is just black. The video is there somewhere as I can hear the audio playing in my browser. I'm new to three.js so I'm not sure what I'm doing wrong. I have a camera and three lights. I can see the other objects in my scene and their textures are visible. My code is adapted from here. Here is my HTML code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <script src="libraries/three.js"></script>
    <script src="libraries/OBJLoader2.js"></script>
    <script src="libraries/OrbitControls.js"></script>
    <script src="libraries/MtlLoader.js"></script>
    <script src="libraries/DDSLoader.js"></script>
</head>

<body>
<script src="libraries/main.js"></script>
</body>
</html>

And here is my main.js code:

//global variables
var renderer;
var scene;
var camera;
var cameraControl;
var loader;
var updateFcts  = [];

function createRenderer() {
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
}

function createCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth /window.innerHeight, 0.1, 1000);
camera.position.x = 0;
camera.position.y = 100;
camera.position.z = 450;
camera.lookAt(scene.position);
cameraControl = new THREE.OrbitControls(camera);
}

var THREEx = THREEx || {}
THREEx.VideoTexture = function(url){
var video   = document.createElement('video');
video.width = 320;
video.height    = 240;
video.autoplay  = true;
video.loop  = true;
video.src   = url;
this.video  = video;
var texture = new THREE.Texture( video );
this.texture    = texture;
this.update = function(){
    if( video.readyState !== video.HAVE_ENOUGH_DATA )   return;
    texture.needsUpdate = true;     
}
  this.destroy  = function(){
    video.pause()
  }
}

function createVideo() {
var videoTexture= new THREEx.VideoTexture('models/textures/video.mp4')
var video   = videoTexture.video;
updateFcts.push(function(delta, now){
    videoTexture.update(delta, now)
});
var geometry    = new THREE.CubeGeometry(10,50,10);
var material    = new THREE.MeshBasicMaterial({
    map : videoTexture.texture,
    side: THREE.DoubleSide
});
var mesh    = new THREE.Mesh( geometry, material );
scene.add( mesh );
updateFcts.push(function(delta, now){
    mesh.rotation.x += 1 * delta;
    mesh.rotation.y += 2 * delta;       
});
}

function createLight() {
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(10, 40, 20);
spotLight.shadowCameraNear = 20;
spotLight.shadowCameraFar = 50;
spotLight.castShadow = true;
scene.add(spotLight);
var ambient = new THREE.AmbientLight( 0x444444 );
ambient.castShadow = true;
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0.5, 0.5 ).normalize();
scene.add( directionalLight );
}

function init() {
scene = new THREE.Scene();
createRenderer();
createCamera();
createLight();
createVideo();
document.body.appendChild(renderer.domElement);
render();
}

 function render() {
cameraControl.update();
renderer.render(scene, camera);
requestAnimationFrame(render);
}

init();

Upvotes: 1

Views: 4156

Answers (2)

Maciej Wakuła
Maciej Wakuła

Reputation: 133

I have encountered a similar issue: rendering camera source to a texture results in a black object (black texture). In my case it was caused by not setting texture.needsUpdate = true. So my own code is something like:

updateTexture = function(videoDomElement){
    var cameraTexture = new THREE.Texture(videoDomElement);
    cameraTexture.needsUpdate = true;
    var material = new THREE.MeshLambertMaterial({map: cameraTexture});
    material.needsUpdate = true;
    existingObject.material = material;
}

Upvotes: 2

Davide Necchi
Davide Necchi

Reputation: 796

You have to create a canvas for the video so you can use it for build texture. Also you have to refresh every frame in render loop.

var renderer;
var scene;
var camera;
var cameraControl;
var loader;
var updateFcts = [];
var video;
var videoImageContext;
var videoTexture;

function createRenderer() {
    renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0x111111, 1.0);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
}

function createCamera() {
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.x = 0;
    camera.position.y = 100;
    camera.position.z = 450;
    camera.lookAt(scene.position);
    cameraControl = new THREE.OrbitControls(camera);
}

var THREEx = THREEx || {}
THREEx.VideoTexture = function(url) {
    video = document.createElement('video');

    video.autoplay = true;
    video.loop = true;
    video.src = url;
    video.load();
    video.play();

    videoImage = document.createElement('canvas');
    videoImage.width = 320;
    videoImage.height = 240;
    videoImageContext = videoImage.getContext('2d');
    videoImageContext.fillStyle = '#000000';
    videoImageContext.fillRect(0, 0, videoImage.width, videoImage.height);

    this.texture = new THREE.Texture(videoImage);
    this.texture.minFilter = THREE.LinearFilter;
    this.texture.magFilter = THREE.LinearFilter; 

    this.destroy = function() {
        video.pause()
    }
}

function createVideo() {
    videoTexture = new THREEx.VideoTexture('myvideo.mp4')
    updateFcts.push(function(delta, now) {
        videoTexture.update(delta, now)
    });
    var geometry = new THREE.CubeGeometry(10, 50, 10);
    var material = new THREE.MeshBasicMaterial({
        map: videoTexture.texture,
        side: THREE.DoubleSide
    });
    var mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
    updateFcts.push(function(delta, now) {
        mesh.rotation.x += 1 * delta;
        mesh.rotation.y += 2 * delta;
    });
}

function createLight() {
    var spotLight = new THREE.SpotLight(0xffffff);
    spotLight.position.set(10, 40, 20);
    spotLight.shadowCameraNear = 20;
    spotLight.shadowCameraFar = 50;
    spotLight.castShadow = true;
    scene.add(spotLight);
    var ambient = new THREE.AmbientLight(0x444444);
    ambient.castShadow = true;
    scene.add(ambient);
    var directionalLight = new THREE.DirectionalLight(0xffeedd);
    directionalLight.position.set(0, 0.5, 0.5).normalize();
    scene.add(directionalLight);
}

function init() {
    scene = new THREE.Scene();
    createRenderer();
    createCamera();
    createLight();
    createVideo();
    document.body.appendChild(renderer.domElement);
    render();
}

function render() {
    cameraControl.update();
    if (video.readyState === video.HAVE_ENOUGH_DATA) {
        videoImageContext.drawImage(video, 0, 0);
        if (videoTexture)
            videoTexture.texture.needsUpdate = true;
    }
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

init();

I have changed the THREEx.VideoTexture function and render loop and tested with r75 and works!

Upvotes: 0

Related Questions