Preface
I've created a super contrived example of what I want to create of using 3js geometry and video. I'm certain it wont need html5 video but the demo uses it for visiblity.
Here is a live code hosted by
codepen.io
Problem:
I'm super new to webGL and associated libraries(3js).
Question:
How do I map a video onto a sphere using 3js?
JS
// renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// camera
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 500;
// scene
var video, texture;
video = document.getElementById( 'video' );
var scene = new THREE.Scene();
texture = new THREE.VideoTexture( video );
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
//sphere
var sphere = new THREE.Mesh(new THREE.SphereGeometry(150, 100, 100), new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
renderer.render(scene, camera);
HTML
<!--sphere gets placed here -->
<div id="container"></div>
<!-- example video -->
<video id="video" width="400" src="http://avideos.5min.com//415/5177415/517741401_4.mp4#t=20"autoplay muted loop></video>
here's what I've assimilated from other posts I've found:
// setting up the renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var container = document.createElement('div');
document.body.appendChild( container );
container.appendChild( renderer.domElement );
// creating a new scene
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 100, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
var camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.target = new THREE.Vector3(0, 0, 0);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
scene.add(camera);
var video = document.getElementById( 'myVideo' );
//sorry, not 100% sure why this is necessary -eg why the renderer doesn't automatically update the video texture in render()
videoImageContext = videoImage.getContext( '2d' );
// background color if no video present
videoImageContext.fillStyle = '#000000';
videoImageContext.fillRect( 0, 0, videoImage.width, videoImage.height );
videoTexture = new THREE.Texture( video );
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
var movieMaterial = new THREE.MeshBasicMaterial( { map: videoTexture,overdraw: true } );
// the geometry on which the movie will be displayed;
// movie image will be scaled to fit these dimensions.
var sphere = new THREE.SphereGeometry(100, 100, 40);
sphere.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
var movieScreen = new THREE.Mesh( sphere, movieMaterial );
scene.add(movieScreen);
render();
function render(){
requestAnimationFrame(render);
if ( video.readyState === video.HAVE_ENOUGH_DATA )
{
videoImageContext.drawImage( video, 0, 0 );
if ( videoTexture )
videoTexture.needsUpdate = true;
}
// calling again render function
renderer.render(scene, camera);
}
Related
I'm trying to add light and see its changes in a simple scene in threejs but no matter the intensity or the color I set for the light, I see no change. Actually, if I don't include the light code, nothing changes as well, so why is HemisphereLight not working in my case?
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 200, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var planeGeometry = new THREE.PlaneGeometry(25, 60, 20, 20);
var planeMaterial = new THREE.MeshBasicMaterial({color:"green"})
var plane = new THREE.Mesh( planeGeometry, planeMaterial );
var light = new THREE.HemisphereLight(0xffffff, 0x000000, 2);
scene.add(light);
scene.add(plane);
plane.rotateZ(Math.PI/2)
camera.position.z = 10;
scene.background = new THREE.Color(0xffffff);
var render = function (time) {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
What version of Three.JS do you use?
I made a JSFiddle with your code, using only Javascript and Three.js version 105 and everything worked, when I used Three.JS version r54, it indeed didn't work.
Sorry that I ask this question like this, can't comment yet haha.
I'll remove this if asked
You can check what version you're using with:
console.log(THREE. REVISION)
<script src="https://threejs.org/build/three.js"></script>
<script type="module">
console.log(THREE. REVISION)
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 200, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var planeGeometry = new THREE.PlaneGeometry(25, 60, 20, 20);
var planeMaterial = new THREE.MeshBasicMaterial({color:"green"})
var plane = new THREE.Mesh( planeGeometry, planeMaterial );
var light = new THREE.HemisphereLight(0xffffff, 0x000000, 2);
scene.add(light);
scene.add(plane);
plane.rotateZ(Math.PI/2)
camera.position.z = 10;
scene.background = new THREE.Color(0xffff00);
var render = function (time) {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
</script>
All of this goes into 1 HTML File.
I’ve went through similar questions on this site, and I have seen all the things that are recommended. Like, camera positioning (not inside the mesh), calling the render function, setting the (ambient) light. Each and every thing I’ve found so far in the forum I’ve tried, but nothing is working.
Can anyone please look at this fiddle and guide me as to what I am doing wrong?
https://jsfiddle.net/4mxybs5h/1/
// HTML
<main>
<div id="threeContainer">
hi
<canvas #canvas id="canvas"></canvas>
</div>
</main>
// JS
//this.animate(null);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
boxGeometry = new THREE.BoxGeometry(2, 2, 2);
material = new THREE.MeshBasicMaterial({color: 0xff0000});
mesh = new THREE.Mesh( boxGeometry, material );
canva = document.getElementById("canvas");
renderer = new THREE.WebGLRenderer({antialias: true, canvas: canva });
startScene();
animate();
function startScene() {
//let scene = new THREE.Scene();
//let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
let light = new THREE.AmbientLight( 0xffaaff );
scene.add( mesh );
light.position.set(10,10,10)
scene.add( light );
camera.position.set(500, 500, 500);
mesh.castShadow = true;
mesh.receiveShadow = true;
//this.renderer.setClearColor('#E5E5E5')
renderer.setClearColor(0xEEEEEE);
//this.renderer.setSize(window.innerWidth, window.innerHeight)
//this.renderer.render(this.scene, this.camera)
//this.renderer.setAnimationLoop(this.animate.bind(this))
//document.body.appendChild(this.renderer.domElement)
// window.addEventListener('resize', () => {
// this.renderer.setSize(window.innerWidth, window.innerHeight)
// this.camera.aspect = window.innerWidth / innerHeight
// this.camera.updateProjectionMatrix();
// })
}
function animate() {
camera.aspect = window.innerWidth / innerHeight
camera.updateProjectionMatrix();
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
//this.mesh.rotation.y += 1;
//document.body.appendChild(this.renderer.domElement)
renderer.render(scene, camera);
}
I feel like it must be something small or obvious, but I am not able to be figure out. Any help is appreciated.
You're not seeing anything because you're setting the camera way off.
Inside the startScene function, change the following:
// From
camera.position.set(500, 500, 500);
// TO
camera.position.set(0, 0, 5);
Applying the above gives:
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
boxGeometry = new THREE.BoxGeometry(2, 2, 2);
material = new THREE.MeshBasicMaterial({color: 0xff0000});
mesh = new THREE.Mesh( boxGeometry, material );
canva = document.getElementById("canvas");
renderer = new THREE.WebGLRenderer({antialias: true, canvas: canva });
startScene();
animate();
function startScene() {
let light = new THREE.AmbientLight( 0xffaaff );
scene.add( mesh );
light.position.set(10,10,10)
scene.add( light );
camera.position.set(0, 0, 5);
mesh.castShadow = true;
mesh.receiveShadow = true;
renderer.setClearColor(0xEEEEEE);
}
function animate() {
camera.aspect = window.innerWidth / innerHeight
camera.updateProjectionMatrix();
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
renderer.render(scene, camera);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<main>
<div id="threeContainer">
<canvas #canvas id="canvas"></canvas>
</div>
</main>
I am working in a three.js project. In the project I have to show all edges of geometries even those edges are intersecting with other objects' surfaces.
Here is the snippet code that illustrates my problem.
var camera, scene, renderer, material, stats, group, wireframeMaterial;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer({antialias: true, alpha:true,clearAlpha:0,clearColor: 0xff0000});
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
// Create scene.
scene = new THREE.Scene();
group=new THREE.Group()
// Create material
material = new THREE.MeshBasicMaterial();
wireframeMaterial=new THREE.LineBasicMaterial( { color: 0x000000, side:THREE.FrontSide ,transparent:false,opacity:1,linewidth: 1 })
// Create cube and add to scene.
var geometry = new THREE.BoxGeometry(200, 200, 200);
var mesh1 = new THREE.Mesh(geometry, material);
group.add(mesh1);
var geometry2 = new THREE.BoxGeometry(100,100,100);
var mesh2 = new THREE.Mesh(geometry2, material);
group.add(mesh2);
mesh2.position.fromArray([0,150,0])
var edges = new THREE.EdgesGeometry( geometry );
var line = new THREE.LineSegments( edges, wireframeMaterial );
mesh1.add( line );
var edges2 = new THREE.EdgesGeometry( geometry2 );
var line2 = new THREE.LineSegments( edges2, wireframeMaterial );
mesh2.add( line2 );
scene.add(group)
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
}
function animate() {
requestAnimationFrame(animate);
group.rotation.x += 0.005;
group.rotation.y += 0.01;
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
body {
padding: 0;
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>
In fiddle code you can see there are two cubes top of each other. I want bottom edges of small cube to become visible. One solution is making mesh basic material transparent. However in that situation edges that are behind cubes it self will be visible too which is not allowed in the project.
So are there any alternative solution for this issue?
Found a good solution, you need to use the polygonOffset parameters of the basic material.
var material = new THREE.MeshBasicMaterial({
polygonOffset: true,
polygonOffsetFactor: 1, // positive value pushes polygon further away
polygonOffsetUnits: 1
});
Found it on this question: three.js EdgesHelper showing certain diagonal lines on Collada model
EdgesGeometry will render the hard edges only.
WireframeGeometry will render all edges.
var camera, scene, renderer, material, stats, group, wireframeMaterial;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer({antialias: true, alpha:true,clearAlpha:0,clearColor: 0xff0000});
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
// Create scene.
scene = new THREE.Scene();
group=new THREE.Group()
// Create materials
var material = new THREE.MeshBasicMaterial({
polygonOffset: true,
polygonOffsetFactor: 1, // positive value pushes polygon further away
polygonOffsetUnits: 1
});
var wireframeMaterial= new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 2 } );
// Create cube and add to scene.
var geometry = new THREE.BoxGeometry(200, 200, 200);
var edges = new THREE.EdgesGeometry(geometry);
var line = new THREE.LineSegments( edges, wireframeMaterial );
var mesh = new THREE.Mesh(geometry, material);
group.add(mesh, line);
var geometry2 = new THREE.BoxGeometry(100,100,100);
var wire = new THREE.EdgesGeometry(geometry2);
var line2 = new THREE.LineSegments( wire, wireframeMaterial );
var mesh2 = new THREE.Mesh(geometry2, material);
line2.position.fromArray([0,150,0]);
mesh2.position.fromArray([0,150,0]);
group.add(mesh2, line2);
scene.add(group)
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
// Add stats to page.
stats = new Stats();
document.body.appendChild( stats.dom );
}
function animate() {
requestAnimationFrame(animate);
group.rotation.x += 0.005;
group.rotation.y += 0.01;
renderer.render(scene, camera);
stats.update();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
<script type="text/javascript" src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/mrdoob/stats.js/r17/build/stats.min.js"></script>
I'd like to be able to view performance stats like on this page while developing my three.js project. But I'm getting the error
"TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not >of type 'Node'."
Here's the code:
var container, camera, scene, axis, renderer, geometry, cylinder1, material1, mesh1, stats;
function init() {
container = document.getElementById( 'canvas' );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 10000);
camera.position.z = 1000;
scene.add(camera);
var axis = new THREE.Vector3(1, 0, 0);
var rad = THREE.Math.degToRad(90);
var axesHelper = new THREE.AxesHelper( 500 );
scene.add( axesHelper );
cylinder1 = new THREE.CylinderGeometry(275, 275, 50, 100);
material1 = new THREE.MeshBasicMaterial( {color: 'orange', wireframe: true} );
mesh1 = new THREE.Mesh(cylinder1, material1);
mesh1.rotateOnAxis(axis, rad);
mesh1.position.set(0,0,25);
scene.add(mesh1);
renderer = new THREE.WebGLRenderer({alpha: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var stats = new Stats();
stats.showPanel( 1 );
document.body.appendChild( stats.dom );
animate();
} init();
function animate() {
stats.begin();
requestAnimationFrame(animate);
renderer.render(scene, camera);
stats.end();
}
You can view the issue live on codepen.
stats.domElement not stats.dom.
I've tried practically everything and the code seems to be perfectly valid. I've tried changing the threejs version, changing from MeshPhongMaterial to MeshBasicMaterial and back, and tried copy pasting code from online. However I still get the same result. CubeCamemra.js works perfectly for me on this ->> http://blog.romanliutikov.com/post/58910953451/dynamic-reflections-in-three-js, but when I try to implement it locally, it renders black. Please tell me if I am missing anything important. Thanks in advance!
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
camera.position.z = 5;
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.TrackballControls(camera);
var cubeCamera = new THREE.CubeCamera(0.1, 1000, 256); // parameters: near, far, resolution
cubeCamera.renderTarget.minFilter = THREE.LinearMipMapLinearFilter; // mipmap filter
scene.add(cubeCamera);
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(0.5, 30, 30),
new THREE.MeshBasicMaterial({
envMap: cubeCamera.renderTarget,
color: 0x00ffff
})
);
//sphere.position.y = 3;
scene.add(sphere);
var cube = new THREE.Mesh(new THREE.CubeGeometry(1,1,1),new THREE.MeshNormalMaterial());
scene.add(cube);
cube.position.y = 3;
function render() {
requestAnimationFrame(render);
sphere.visible = false;
cubeCamera.updateCubeMap(renderer, scene);
sphere.visible = true;
renderer.render(scene,camera);
controls.update();
}
render();
http://puu.sh/aqcib/6c2b15d6ca.png -- pic of whats happening