Three.js issue creating meshes outside of loader's load() function - javascript

I had difficulty exporting more than one texture using Blender's Three.js add-on, so had planned to work around it be separating the parts into separate meshes, but then came across the unexpected problem of the code not working when I created the meshes outside of the load() function. I've supplied an example below using a single model with a single mesh. The following works fine:
<!DOCTYPE html>
<html lang="en">
<head>
<title>working</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="js/build/three.min.js"></script>
<script src="js/loaders/ColladaLoader.js"></script>
<script src="js/Detector.js"></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container;
var camera, scene, renderer, objects;
var scaleAdj = 100;
init();
animate();
function init()
{
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 );
camera.position.set( 0, 500, 0 );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xcce0ff, 10, 10000 );
var loader = new THREE.JSONLoader();
loader.load( 'cube.json', function ( geometry, materials )
{
var faceMaterial = new THREE.MultiMaterial( materials );
for ( var i = 0; i < 250; i ++ )
{
var x = ( ( i % 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
var z = ( Math.floor( i / 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
mesh = new THREE.Mesh( geometry, faceMaterial );
var s = THREE.Math.randFloat( 0.5, 2 ) * scaleAdj;
mesh.scale.set( s, s, s );
mesh.position.set( x, scaleAdj, z );
mesh.rotation.y = THREE.Math.randFloat( -0.25, 0.25 );
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
scene.add( mesh );
}
} );
scene.add( new THREE.AmbientLight( 0xffffff ) );
// ground
var textureLoader = new THREE.TextureLoader();
var groundTexture = textureLoader.load( "texture.jpg" );
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.repeat.set( 40, 40 );
groundTexture.anisotropy = 16;
var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: groundTexture } );
var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
mesh.position.y = 0;
mesh.rotation.x = - Math.PI / 2;
mesh.receiveShadow = true;
scene.add( mesh );
// Renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( scene.fog.color );
container.appendChild( renderer.domElement );
// Events
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
But this doesn't (I've annotated which sections contain the differences):
<!DOCTYPE html>
<html lang="en">
<head>
<title>not working</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="js/build/three.min.js"></script>
<script src="js/loaders/ColladaLoader.js"></script>
<script src="js/Detector.js"></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
//--------------- difference number 1
var obj_geometry;
var obj_material;
//-----------------------------------
var container;
var camera, scene, renderer, objects;
var scaleAdj = 100;
init();
animate();
function init()
{
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 );
camera.position.set( 0, 500, 0 );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xcce0ff, 10, 10000 );
//-------------------difference number 2--------------------
var loader = new THREE.JSONLoader();
loader.load( 'cube.json', function ( geometry, material )
{
obj_geometry = geometry;
obj_material = material;
});
var faceMaterial = new THREE.MultiMaterial( obj_material);
for ( var i = 0; i < 250; i ++ )
{
var x = ( ( i % 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
var z = ( Math.floor( i / 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
mesh = new THREE.Mesh( obj_geometry, faceMaterial);
var s = THREE.Math.randFloat( 0.5, 2 ) * scaleAdj;
mesh.scale.set( s, s, s );
mesh.position.set( x, 0, z );
mesh.rotation.y = THREE.Math.randFloat( -0.25, 0.25 );
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
scene.add( mesh );
}
//--------------------------------------
scene.add( new THREE.AmbientLight( 0xffffff ) );
// ground
var textureLoader = new THREE.TextureLoader();
var groundTexture = textureLoader.load( "texture.jpg" );
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.repeat.set( 40, 40 );
groundTexture.anisotropy = 16;
var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: groundTexture } );
var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
mesh.position.y = 0;
mesh.rotation.x = - Math.PI / 2;
mesh.receiveShadow = true;
scene.add( mesh );
// Renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( scene.fog.color );
container.appendChild( renderer.domElement );
// Events
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
Here is a copy of the contents of the cube.json file:
{
"uvs":[[0,0,1,0,1,1,0,1]],
"faces":[43,0,1,2,3,0,0,1,2,3,0,1,2,3,43,4,7,6,5,0,0,1,2,3,4,5,6,7,43,0,4,5,1,0,0,1,2,3,0,4,7,1,43,1,5,6,2,0,0,1,2,3,1,7,6,2,43,2,6,7,3,0,0,1,2,3,2,6,5,3,43,4,0,3,7,0,0,1,2,3,4,0,3,5],
"normals":[0.577349,-0.577349,-0.577349,0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,-0.577349,0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,0.577349,0.577349,0.577349,0.577349],
"metadata":{
"generator":"io_three",
"type":"Geometry",
"normals":8,
"vertices":8,
"uvs":1,
"version":3,
"materials":1,
"faces":6
},
"vertices":[1,-1,-1,1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1,0.999999,1,1,-1,1,1,-1,1,-1],
"materials":[{
"DbgName":"Material",
"colorSpecular":[0.5,0.5,0.5],
"DbgIndex":0,
"mapDiffuseWrap":["RepeatWrapping","RepeatWrapping"],
"mapDiffuse":"texture.jpg",
"shading":"phong",
"depthTest":true,
"opacity":1,
"transparent":false,
"colorDiffuse":[0.64,0.64,0.64],
"mapDiffuseAnisotropy":1,
"blending":"NormalBlending",
"depthWrite":true,
"visible":true,
"specularCoef":50,
"mapDiffuseRepeat":[1,1],
"colorEmissive":[0,0,0],
"wireframe":false,
"DbgColor":15658734
}],
"name":"CubeGeometry"
}
And here is an attached texture which could be used.
It might just be a trivial problem for some of the posters on here, and if so, thanks in advance for just letting me know what it is. If not, then the answer could be useful to a lot more people, and thanks for any help you can give on it.

You cant do this, asynchronously:
var obj_geometry; // === undefined
var myMesh = new THREE.Mesh( obj_geometry ); //because undefined, same as calling new THREE.Mesh();
obj_geometry = geometry;//does nothing, mesh has no idea about this happening
obj_material = material;
When you construct a mesh, you've given it undefined for geometry, so i think it just calls new Geometry() inside the constructor. This mesh has been created with a unique isntance of empty Geometry and has nothing to do with your obj_geometry.
The solution here is to do:
var obj_geometry = new THREE.Geometry();
var myMesh = new THREE.Mesh( obj_geometry ); //holds a reference to an empty "proxy"
then onLoad
loader.load( 'url' , function( geom ) {
obj_geometry.merge(geom); //"FILL PREVIOUSLY CREATED GEOMETRY WITH DATA"
obj_geometry.vertsNeedUpdate = true; // there's a few flags like this you need to turn on
}
OR
var myMesh = new THREE.Mesh();
loader.load( 'url', function( geom ) {
myMesh.geometry = geom; //"PUT THE JUST CREATED GEOMETRY IN THE RIGHT PLACE"
//myOtherMesh.geometry = geom; //if you have more places where this needs to end up
//myThirdMesh.geometry = geom; //gets very cumbersome
}
Both are pretty cumbersome and not very intuitive :( i really dislike this part of three.js.

Thanks to help from pailhead, pointing out the asynchronous issue I made the following modification to the code and found that it worked. Surprisingly the count that I added doesn't seem to raise above 0, but I am assuming that it was because it was quite a close run thing.
<!DOCTYPE html>
<html lang="en">
<head>
<title>asynchronous working</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="build/three.min.js"></script>
<script>
//--------------- difference number 1
var obj_geometry;
var obj_material;
var loaded = false;
//-----------------------------------
var container;
var camera, scene, renderer, objects;
var scaleAdj = 100;
init();
animate();
function init()
{
container = document.createElement( 'div' );
document.body.appendChild( container );
//-----an info display
info = document.createElement( 'div' );
info.id = "info";
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
container.appendChild(info);
//-----------------
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 );
camera.position.set( 0, 500, 0 );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xcce0ff, 10, 10000 );
//-------------------difference number 2--------------------
var loader = new THREE.JSONLoader();
loader.load( 'cube.json', function ( geometry, material )
{
obj_geometry = geometry;
obj_material = material;
loaded = true;
});
var notLoadedCount = 0;
var processor = setInterval(function()
{
if(!loaded)
{
notLoadedCount++;
}
else
{
var faceMaterial = new THREE.MultiMaterial( obj_material);
for ( var i = 0; i < 250; i ++ )
{
var x = ( ( i % 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
var z = ( Math.floor( i / 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
mesh = new THREE.Mesh( obj_geometry, faceMaterial);
var s = THREE.Math.randFloat( 0.5, 2 ) * scaleAdj;
mesh.scale.set( s, s, s );
mesh.position.set( x, 0, z );
mesh.rotation.y = THREE.Math.randFloat( -0.25, 0.25 );
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
scene.add( mesh );
info.innerHTML= '*not loaded count = ' + notLoadedCount;
}
clearInterval(processor);
}
}, 100);
//--------------------------------------
scene.add( new THREE.AmbientLight( 0xffffff ) );
// ground
var textureLoader = new THREE.TextureLoader();
var groundTexture = textureLoader.load( "texture.jpg" );
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.repeat.set( 40, 40 );
groundTexture.anisotropy = 16;
var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: groundTexture } );
var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
mesh.position.y = 0;
mesh.rotation.x = - Math.PI / 2;
mesh.receiveShadow = true;
scene.add( mesh );
// Renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( scene.fog.color );
container.appendChild( renderer.domElement );
// Events
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
Thanks for the help with this, hopefully it helps others too. If there are any problems with this resolution that anybody notices, please let me know. Thanks.

Related

Generate a mesh from points Three.js

I'm trying to generate a mesh from points. I've read here the way to generate the mesh is,
var mesh = new THREE.ConvexGeometry( vertices_array );
In this example they've declared the vertices_array like below
var vertices = new THREE.DodecahedronGeometry( 10 ).vertices;
What I need to understand is, how to define the vertices_array for points created using THREE.BufferGeometry with the code below.
Thank you very much
<!DOCTYPE html>
<html lang="en">
<head>
<title>Three.js</title>
<meta charset="utf-8">
<script src="js/three.js"></script>
<script src="js/TrackballControls.js"></script>
<script src="js/WebGL.js"></script>
<script src="js/ConvexGeometry.js"></script>
<script src="js/QuickHull.js"></script>
</head>
<body>
<script>
if ( WEBGL.isWebGLAvailable() === false ) {
document.body.appendChild( WEBGL.getWebGLErrorMessage() );
}
var camera, scene, renderer, controls;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45.0, window.innerWidth / window.innerHeight, 5, 3500 );
camera.position.z = 2500;
controls = new THREE.TrackballControls( camera, renderer.domElement );
createScene();
}
function createScene() {
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x000000 );
var geometry = new THREE.BufferGeometry();
var positions = [];
for ( var i = 0; i < 20; i ++ ) {
for ( var j = 0; j < 20; j ++ ) {
var y = j;
var x = i;
var z = 0;
positions.push( new THREE.Vector3(x, y, z) );
//positions.push( x, y, z );
}
}
//geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
//var material = new THREE.PointsMaterial( {color: 0xFF0000} );
//points = new THREE.Points( geometry, material );
//scene.add( points );
var meshMaterial = new THREE.MeshBasicMaterial( {color: 0xffffff,} );
var meshGeometry = new THREE.ConvexBufferGeometry( positions );
var mesh = new THREE.Mesh( meshGeometry, meshMaterial );
scene.add( mesh );
}
function animate( time ) {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}
</script>
</body>
</html>

How to render multiple videos on a sphere using three.js

Three.js is new to me, so I am a bit stuck on this.
I read the answer to this question: Using multiuple textures on a sphere [Three.js]
The answer suggests the user to use a cube to load the textures on, instead of sphere.That being done, the cube can be expanded to a sphere.
var geometry = new THREE.BoxGeometry( 1, 1, 1, 8, 8, 8 );
for ( var i in geometry.vertices ) {
var vertex = geometry.vertices[ i ];
vertex.normalize().multiplyScalar(radius);
}
var materialArray = [];
var faceMaterial = new THREE.MeshLambertMaterial({
color: sphereColor,
transparent: true,
opacity: 0.4
});
for (var i = 0; i < 6; i++) {
materialArray.push(faceMaterial);
}
var material = new THREE.MeshFaceMaterial(materialArray);
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );
Will the same thing work for videos? If I wish to play six videos on a sphere, should I load the 'video' texture onto the six faces of the cube and then expand it to a sphere.
EDIT:
I have the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - equirectangular video panorama</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px; width: 100%;
color: #ffffff;
padding: 5px;
font-family:Monospace;
font-size:13px;
font-weight: bold;
text-align:center;
}
a {
color: #ffffff;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="three.js"></script>
<script>
var camera, scene, renderer;
var texture_placeholder,
isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0,
distance = 500;
init();
animate();
function init() {
var container, mesh;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
//var geometry = new THREE.SphereBufferGeometry( 500, 60, 40 );
//geometry.scale( - 1, 1, 1 );
var geometry = new THREE.BoxBufferGeometry( 1,1,1,32,32,32 );
geometry.scale( - 1, 1, 1 );
for ( var i in geometry.vertices ) {
var vertex = geometry.vertices[ i ];
vertex.normalize().multiplyScalar(distance);
}
//var video = document.createElement( 'video' );
//video.width = 640;
//video.height = 360;
//video.autoplay = true;
//video.loop = true;
//video.src = "pano.webm";
var path = "vids/";
var format = '.mp4';
var urls = [
path + 'Row1Col1' + format, path + 'Row1Col2' + format,
path + 'Row1Col3' + format, path + 'Row2Col1' + format,
path + 'Row2Col2' + format, path + 'Row2Col3' + format
];
var reflectionCube = new THREE.CubeTextureLoader().load( urls );
reflectionCube.minFilter = THREE.LinearFilter;
reflectionCube.format = THREE.RGBFormat;
//var texture = new THREE.VideoTexture( video );
//texture.minFilter = THREE.LinearFilter;
//texture.format = THREE.RGBFormat;
//var material = new THREE.MeshBasicMaterial( { map : texture } );
//mesh = new THREE.Mesh( geometry, material );
//scene.add( mesh );
var materialArray = [];
var faceMaterial = new THREE.MeshLambertMaterial({
color: 0xffff00,
transparent: true,
opacity: 0.4
});
for (var i = 0; i < 6; i++) {
materialArray.push(faceMaterial);
}
var material = new THREE.MeshFaceMaterial(materialArray);
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );
//End of what I have added
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
document.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove( event ) {
if ( isUserInteracting === true ) {
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp( event ) {
isUserInteracting = false;
}
function onDocumentMouseWheel( event ) {
// WebKit
if ( event.wheelDeltaY ) {
distance -= event.wheelDeltaY * 0.05;
// Opera / Explorer 9
} else if ( event.wheelDelta ) {
distance -= event.wheelDelta * 0.05;
// Firefox
} else if ( event.detail ) {
distance += event.detail * 1.0;
}
}
function animate() {
requestAnimationFrame( animate );
update();
}
function update() {
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );
camera.position.x = distance * Math.sin( phi ) * Math.cos( theta );
camera.position.y = distance * Math.cos( phi );
camera.position.z = distance * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( camera.target );
/*
// distortion
camera.position.copy( camera.target ).negate();
*/
renderer.render( scene, camera );
}
</script>
</body>
However, it does not work. After I host it on the web there's just a black screen. Can you tell me where am I going wrong?
Based on some of my recent findings working with 360 videos in threejs (I am also new to threejs), you could be seeing the black screen due to the overall resolution being too high. If each video is at 4k resolution, then you are trying to display a 24k res video. I start encountering issues where I get black screen after 5.7k, even on higher end equipment and 100+ mbps network speeds.

THREE.js rotation on loaded file

I've been playing around with this ThreeJS library for a couple of weeks now, and using inspiration from others, I've made a canvas that displays an external .stl-file.
My only problem is I can't seem to apply any transformations to it. I can move the camera around just fine, but I can't get even the most simple transformations to work. I'm not best with JavaScript, so I might have missed some essential parts.
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - STL</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/loaders/STLLoader.js"></script>
<script src="js/Detector.js"></script>
<script src="dat.gui.js"></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container;
var rotationSpeed;
var camera, cameraTarget, scene, renderer;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 15 );
camera.position.set( -3, 1, 3 );
cameraTarget = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0x72645b, 2, 15 );
// Ground
var plane = new THREE.Mesh( new THREE.PlaneGeometry( 40, 40 ), new THREE.MeshPhongMaterial( { ambient: 0x999999, color: 0x999999, specular: 0x101010 } ) );
plane.rotation.x = -Math.PI/2;
plane.position.y = -0.5;
scene.add( plane );
plane.receiveShadow = true;
// ASCII file
var loader = new THREE.STLLoader();
loader.addEventListener( 'load', function ( event ) {
var geometry = event.content;
var material = new THREE.MeshPhongMaterial( { ambient: 0xff5533, color: 0xff5533, specular: 0x111111, shininess: 200 } );
var model = new THREE.Mesh( geometry, material );
model.position.set( 0, 0.05, 0 );
model.rotation.set( Math.PI / 2.0, - Math.PI / 1.5, 0 );
model.scale.set( 0.01, 0.01, 0.01 );
model.castShadow = true;
model.receiveShadow = true;
scene.add( model );
} );
loader.load( './models/stl/ascii/cover.stl' );
// Lights
scene.add( new THREE.AmbientLight( 0x777777 ) );
addShadowedLight( 1, 1, 1, 0xffffff, 1.35 );
addShadowedLight( 0.5, 1, -1, 0xffaa00, 1 );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( scene.fog.color, 1 );
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapCullFace = THREE.CullFaceBack;
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function addShadowedLight( x, y, z, color, intensity ) {
var directionalLight = new THREE.DirectionalLight( color, intensity );
directionalLight.position.set( x, y, z )
scene.add( directionalLight );
directionalLight.castShadow = true;
// directionalLight.shadowCameraVisible = true;
var d = 1;
directionalLight.shadowCameraLeft = -d;
directionalLight.shadowCameraRight = d;
directionalLight.shadowCameraTop = d;
directionalLight.shadowCameraBottom = -d;
directionalLight.shadowCameraNear = 1;
directionalLight.shadowCameraFar = 4;
directionalLight.shadowMapWidth = 1024;
directionalLight.shadowMapHeight = 1024;
directionalLight.shadowBias = -0.005;
directionalLight.shadowDarkness = 0.15;
}
/* var controls = new function()
{
this.rotationSpeed = 0.2;
}
var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed',0,1);
*/
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
var timer = Date.now() * 0.0005;
camera.lookAt( cameraTarget );
//THIS LINE DOESN'T WORK
//model.position.x = Math.cos( timer );
//model.position.z = Math.sin( timer );
renderer.render( scene, camera );
}
</script>
</body>
</html>
The last lines before the render() function just gives me a black, blank page.
Even things like model.position.x += 0.02; kills it
I could find the mistake here , but sorry some how not able to port your code to JSFIDDLE
Here is the problem I found,
model variable is not declared in the global scope. It is initialized locally in the init() function and you are trying the manipulate that variable with in the render function, where it does not have any scope.
So the solution is Just declare the variable model before calling the init() function just like other variables that you are declaring there by adding this below line.
var model;

Three.js, no shadow rendered (.stl files)

I'm using three.js and I'm trying to make a good viewer for .stl files.
But I have a big problem with the shadow, for some files it's ok and for some other it's just horrible. (Most of the time, it's stl file that come from Blender that don't work).
Here are the two different render with a "normal" file and the same file import/export with Blender.
Images : http://imageup.fr/uploads/1367501292.jpeg & http://imageup.fr/uploads/1367501311.jpeg
Here is the code:
<script src="scripts/three.min.js"></script>
<script src="three/js/loaders/STLLoader.js"></script>
<script src="three/js/Detector.js"></script>
<script src="three/js/controls/TrackballControls.js"></script>
<div id='3d' style='width:400px;height:300px;margin:auto;position:relative;border:5px solid white;border-radius:5px;'>
<script>
var modele = document.getElementById('modele3d').value;
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, cameraTarget, scene, renderer;
init();
animate();
function init() {
container = document.getElementById('3d');
camera = new THREE.PerspectiveCamera( 45, 400 / 300, 0.1, 10000 );
camera.position.set( 200, 200, 200 );
cameraTarget = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0x1875cd, 0, 100000 );
var material = new THREE.MeshPhongMaterial( { ambient: 0xaeadad, color: 0xfefcfc, specular: 0x111111, shininess: 200} );
var loader = new THREE.STLLoader();
loader.addEventListener( 'load', function ( event ) {
var geometry = event.content;
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 0, 0 );
mesh.rotation.set( - Math.PI / 2, 0, 0 );
// Recherche et envoi des tailles //
geometry.computeBoundingBox();
var largeur = (mesh.geometry.boundingBox.max.x)-(mesh.geometry.boundingBox.min.x);
var hauteur = (mesh.geometry.boundingBox.max.y)-(mesh.geometry.boundingBox.min.y);
var profondeur = (mesh.geometry.boundingBox.max.z)-(mesh.geometry.boundingBox.min.z);
var tailles = largeur + " " + hauteur + " " + profondeur;
var prix = document.getElementById('prototype_prix').value;
if(prix==0){
document.getElementById('prototype_taille1').value = Math.round(largeur);
document.getElementById('prototype_taille2').value = Math.round(hauteur);
document.getElementById('prototype_taille3').value = Math.round(profondeur);
document.getElementById('prototype_taille1_base').value = largeur;
document.getElementById('prototype_taille2_base').value = hauteur;
document.getElementById('prototype_taille3_base').value = profondeur;
}
geometry.computeBoundingSphere();
var radius = mesh.geometry.boundingSphere.radius;
mesh.position.set( 0, -radius/2, 0 );
var d = 300/(2*radius);
mesh.scale.set( d, d, d );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
} );
loader.load( 'images/'+modele);
// Lights
scene.add( new THREE.AmbientLight( 0x777777 ) );
addShadowedLight( 1, 1, 1, 0xffffff, 0.8 );
addShadowedLight( 0.5, 1, -1, 0xfcd891, 0.6 );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false } );
renderer.setSize( 400, 300);
renderer.setClearColor( scene.fog.color, 1 );
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.physicallyBasedShading = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapCullFace = THREE.CullFaceBack;
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
// Trackball
enhanced_control = new THREE.TrackballControls(camera,renderer.domElement);
}
function addShadowedLight( x, y, z, color, intensity ) {
var directionalLight = new THREE.DirectionalLight( color, intensity );
directionalLight.position.set( x, y, z );
scene.add( directionalLight );
directionalLight.castShadow = true;
directionalLight.shadowCameraVisible = true;
directionalLight.shadowCameraNear = 0;
directionalLight.shadowCameraFar = 20;
directionalLight.shadowMapWidth = 1024;
directionalLight.shadowMapHeight = 1024;
directionalLight.shadowBias = -0.005;
directionalLight.shadowDarkness = 0.15;
}
function onWindowResize() {
camera.aspect = 400 / 300;
renderer.setSize( 400, 300);
}
function animate() {
requestAnimationFrame( animate );
enhanced_control.update();
render();
}
function render() {
var timer = Date.now() * 0.0005;
camera.lookAt( cameraTarget );
renderer.render( scene, camera );
}
</script>
<p style='position:relative;margin-top:-310px;margin-left:3px;float:left;color:white;text-shadow:1px 1px 1px #135da4'>Rendu 3D :</p>
</div>
I hope you can help me, I have already passed a lot of time trying to make the render works :s

How can I make my text labels face the camera at all times? Perhaps using sprites?

I'm looking at two examples, one is canvas interactive objects and the other is mouse tooltip. I tried combining the two to generate text labels on each individual cube and here's what I have so far.
However, the text moves with the rotating cubes and the text appears backwards or sideways at times.
How can I make the text fixed in a sprite like in the mouse tooltip (http://stemkoski.github.io/Three.js/Mouse-Tooltip.html) example? I tried to incorporate the sprite but I kept getting errors. I'm not sure how to do it. Could you explain how I can go by it?
Thanks.
Here's my code so far:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - interactive - cubes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/stats.min.js"></script>
<script>
var container, stats;
var camera, scene, projector, renderer;
var projector, mouse = { x: 0, y: 0 }, INTERSECTED;
var particleMaterial;
var currentLabel = null;
var objects = [];
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'three.js - clickable objects';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 0, 300, 500 );
scene = new THREE.Scene();
var geometry = new THREE.CubeGeometry( 100, 100, 100 );
for ( var i = 0; i < 10; i ++ ) {
var object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, opacity: 0.5 } ) );
object.position.x = Math.random() * 800 - 400;
object.position.y = Math.random() * 800 - 400;
object.position.z = Math.random() * 800 - 400;
object.scale.x = Math.random() * 2 + 1;
object.scale.y = Math.random() * 2 + 1;
object.scale.z = Math.random() * 2 + 1;
object.rotation.x = Math.random() * 2 * Math.PI;
object.rotation.y = Math.random() * 2 * Math.PI;
object.rotation.z = Math.random() * 2 * Math.PI;
object.label = "Object " + i;
scene.add( object );
objects.push( object );
}
var PI2 = Math.PI * 2;
particleMaterial = new THREE.ParticleCanvasMaterial( {
color: 0x000000,
program: function ( context ) {
context.beginPath();
context.arc( 0, 0, 1, 0, PI2, true );
context.closePath();
context.fill();
}
} );
projector = new THREE.Projector();
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) {
if ( intersects[ 0 ].object != INTERSECTED )
{
// restore previous intersection object (if it exists) to its original color
if ( INTERSECTED ) {
INTERSECTED.material.color.setHex( INTERSECTED.currentHex ); }
// store reference to closest object as current intersection object
INTERSECTED = intersects[ 0 ].object;
// store color of closest object (for later restoration)
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
// set a new color for closest object
INTERSECTED.material.color.setHex( 0xffff00 );
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 40px Arial";
context1.fillStyle = "rgba(255,0,0,0.95)";
context1.fillText(INTERSECTED.label, 0, 50);
// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;
var material1 = new THREE.MeshBasicMaterial( {map: texture1, side:THREE.DoubleSide } );
material1.transparent = true;
var mesh1 = new THREE.Mesh(
new THREE.PlaneGeometry(canvas1.width, canvas1.height),
material1
);
mesh1.position = intersects[0].point;
if (currentLabel)
scene.remove(currentLabel);
scene.add( mesh1 );
currentLabel = mesh1;
}
else // there are no intersections
{
// restore previous intersection object (if it exists) to its original color
if ( INTERSECTED ) {
console.log("hello");
INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
}
// remove previous intersection object reference
// by setting current intersection object to "nothing"
INTERSECTED = null;
mesh1 = null;
mesh1.position = intersects[0].point;
scene.add( mesh1 );
}
//var particle = new THREE.Particle( particleMaterial );
//particle.position = intersects[ 0 ].point;
//particle.scale.x = particle.scale.y = 8;
//scene.add( particle );
}
/*
// Parse all the faces
for ( var i in intersects ) {
intersects[ i ].face.material[ 0 ].color.setHex( Math.random() * 0xffffff | 0x80000000 );
}
*/
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
var radius = 600;
var theta = 0;
function render() {
theta += 0.1;
camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
</script>
</body>
Billboarding is easy. All you have to do, in your case, is add this inside your render loop:
if ( currentLabel ) currentLabel.lookAt( camera.position );

Categories

Resources