Three.js - how to wait for a image to be loaded? - javascript

I load an image to show a sprite.
But it seems that the code proceeds before the image is fully load:
dart:web_gl: RENDER WARNING: texture bound to texture unit 0 is not renderable
WebGL - wait for texture to load
But I don't know how to wait for the image to be fully loaded using Threejs.
May I have some help?
The code can be tested here : http://www.planetarium2016.com/sprite.html
Here is my code:
<html>
<head>
<title>My first three.js app</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
camera.position.set(0, 10, 100);
camera.lookAt(new THREE.Vector3(0, 0, 0));
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var material = new THREE.LineBasicMaterial({ color: 0x0000ff });
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(-10, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 10, 0));
geometry.vertices.push(new THREE.Vector3(10, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 0, -10));
var line = new THREE.Line(geometry, material);
scene.add(line);
var loader = new THREE.TextureLoader();
var spriteMap = loader.load("https://codefisher.org/static/images/pastel-svg/256/bullet-star.png");
//+-----------------------------------------------------------+
//| I need here to wait for the image to be fully loaded |
//| This cheat is fool: while (spriteMap.image.width == 0); |
//+-----------------------------------------------------------+
var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff } );
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set(256, 256, 1);
sprite.position.set( 0, 0, 10 );
scene.add( sprite );
//camera.position.z = 2;
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
THREE JS TextureLoader is a little bit old...

I would solve this by using JavaScript promises. I separated your three.js code into two main functions, one for initialization and one for animation with requestAnimationFrame. It's more readable this way especially if you intend to perform an async task:
var scene;
var camera;
var renderer;
var spriteMap;
var loaderPromise = new Promise(function(resolve, reject) {
function loadDone(x) {
console.log("loader successfully completed loading task");
resolve(x); // it went ok!
}
var loader = new THREE.TextureLoader();
loader.load("https://codefisher.org/static/images/pastel-svg/256/bullet-star.png", loadDone);
});
loaderPromise.
then(function(response) {
spriteMap = response; //assign loaded image data to a variable
init(); //initialize the render
requestAnimationFrame( render );
}, function(err) {
console.log(err);
});
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
camera.position.set(0, 10, 100);
camera.lookAt(new THREE.Vector3(0, 0, 0));
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var material = new THREE.LineBasicMaterial({ color: 0x0000ff });
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(-10, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 10, 0));
geometry.vertices.push(new THREE.Vector3(10, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 0, -10));
var line = new THREE.Line(geometry, material);
scene.add(line);
var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff } );
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set(256, 256, 1);
sprite.position.set( 0, 0, 10 );
scene.add( sprite );
}
function render() {
renderer.render(scene, camera);
requestAnimationFrame( render );
}

solution here: https://threejs.org/docs/#api/loaders/TextureLoader
this is the code to solve my problem:
var url = "https://codefisher.org/static/images/pastel-svg/256/bullet-star.png";
var loader = new THREE.TextureLoader();
var spriteMaterial;
loader.load(url,
function(texture)
{
spriteMaterial = new THREE.SpriteMaterial( { map: texture, color: 0x0000ff } );
}
);
var sprite = new THREE.Sprite( spriteMaterial );

var loader = new THREE.TextureLoader();
loader.load(
'img/url/img.png',
function ( map ) {
// map var is your image
},
function ( xhr ) {
if ( xhr.lengthComputable ) {
console.log( 'percent: ' + (xhr.loaded / xhr.total * 100) );
}
},
function ( err ) {
console.log( 'An error happened' );
}
);
THREE 73

Related

Three.js Trackball zoom works rotation does not

The title pretty much says it all. I expect trackerballcontrols to behave like this example but for some reason I cannot rotate the camera only zoom in and out. Ovbiously I would like to be able to rotate the camera. Here's the code.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>FooBarBaz</h1>
<p>LaDeDa</p>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
var objects = [
{
name : "earth",
mesh : new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), new THREE.MeshPhongMaterial()),
init : function(scene){
this.mesh.position.set(0,0,0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate : function(t){return}
},
{
name : "satellite",
mesh : new THREE.Mesh(new THREE.SphereGeometry(0.1, 32, 32), new THREE.MeshPhongMaterial()),
init : function(scene){
this.mesh.position.set(1.5,0,0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate : function(t){this.mesh.position.set(Math.sin(t)*1.5,Math.cos(t)*1.5,0);}
}];
objects.forEach(object => object.init(scene));
var light = new THREE.HemisphereLight(0xf6e86d, 0x404040, 0.5);
scene.add(light);
camera.position.x = 0;
camera.position.y = -5;
camera.position.z = 0;
camera.lookAt(new THREE.Vector3( 0, 0, 0));
var timeStep = 0.01;
var time = 0;
var controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.target.set( 0, 0, 0 );
var render = function () {
time += timeStep;
requestAnimationFrame( render );
objects.forEach(object => object.animate(time));
controls.update();
renderer.render(scene, camera);
}
document.body.appendChild( renderer.domElement );
render();</script>
</body>
</html>
There are two points in your code need adjustment.
You need to append renderer.domElement to body before initializing controls:
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera, renderer.domElement);
Since you make your camera.position on y-axis, and in TrackballControls camera.up is default set to y-axis, this makes your controls unable to work porperly. So what you need to do is to change the default camera.up behaviour:
camera.up = new THREE.Vector3(1, 1, 1);//you can change the values freely ,just dont make it parallel to y-axis
Sorry I'm not a ThreeJS expert, you can refer to this for more information:https://github.com/mrdoob/three.js/issues/10161
So the code below works fine:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>FooBarBaz</h1>
<p>LaDeDa</p>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var objects = [
{
name: "earth",
mesh: new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), new THREE.MeshPhongMaterial()),
init: function (scene) {
this.mesh.position.set(0, 0, 0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate: function (t) { return }
},
{
name: "satellite",
mesh: new THREE.Mesh(new THREE.SphereGeometry(0.1, 32, 32), new THREE.MeshPhongMaterial()),
init: function (scene) {
this.mesh.position.set(1.5, 0, 0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate: function (t) { this.mesh.position.set(Math.sin(t) * 1.5, Math.cos(t) * 1.5, 0); }
}];
objects.forEach(object => object.init(scene));
var light = new THREE.HemisphereLight(0xf6e86d, 0x404040, 0.5);
scene.add(light);
camera.position.x = 0;
camera.position.y = -5;
camera.position.z = 0;
camera.up = new THREE.Vector3(1, 1, 1);
camera.lookAt(new THREE.Vector3(0, 0, 0));
var timeStep = 0.01;
var time = 0;
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
var render = function () {
time += timeStep;
requestAnimationFrame(render);
objects.forEach(object => object.animate(time));
controls.update();
renderer.render(scene, camera);
}
render();</script>
</body>
</html>

How to drag and drop Browsed stl element with three.js

I'm building a Stl viewer/editor. I'm a beginner in JS and i'm supposed to be able to load and move (and eventually scale, rotate) STL file. All i've done here is this : A
3D field where you can upload STL but only if they are at the same place than the file ( you cannot browse an stl place anywhere else) and move camera.
I'm trying to add a drag and drop function but find nothing that is suitable. Found this but it seems to be obsolete function no longer used by three.js.
I find this witch look very good but : the camera don't move and it's not an STL file and i haven't been able to "adapt" it to my code.
Can someone please help me ? As i said i'm a beginner so be as detailed as possible otherwise i wont understand.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>LOAD THE POULE</title>
<style>
body { margin: 0;
background-color: white;
}
canvas { width: 100%; height: 100%; color: blue; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/STLLoader.js"></script>
<script src="js/Detector.js"></script>
<form action="">
<input type="file" id="poule">
</form>
<script>
var camera, scene, renderer;
init();
animate();
function init() {
document.getElementById("poule").addEventListener("change", onFileSelected);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera
(75, window.innerWidth /window.innerHeight, 1, 10000);
camera.position.set(10,20,25);
camera.lookAt(scene.position);
renderer = new THREE.WebGLRenderer();
renderer.setSize ( window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
<!--light-->
var light = new THREE.PointLight(0xffffff);
light.position.set(-100,200,100);
scene.add(light);
var light = new THREE.PointLight(0xffffff);
light.position.set(100,-200,-100);
scene.add(light);
<!--Grid-->
var size = 14, step= 2;
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial({color: 'white'});
for(var i= -size; i<= size; i +=step){
geometry.vertices.push(new THREE.Vector3(- size, 0,i));
geometry.vertices.push(new THREE.Vector3( size, 0,i));
geometry.vertices.push(new THREE.Vector3(i, 0, - size));
geometry.vertices.push(new THREE.Vector3( i, 0, size));
}
var line = new THREE.LineSegments ( geometry, material);
scene.add(line);
<!--cam controls-->
controls = new THREE.OrbitControls(camera, renderer.domElement);
<!--base-->
var plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry( 2*size +5, 2*size +5,0 ),
new THREE.MeshPhongMaterial( { color: 0x424858, specular: 0x101010 } )
);
plane.rotation.x = -Math.PI/2;
plane.position.y = -0.1;
scene.add( plane );
plane.receiveShadow = true;
<!--Cube-->
var sphere = new THREE.SphereGeometry();
var object = new THREE.Mesh
( sphere, new THREE.MeshBasicMaterial
( 0xff0000 ) );
var box = new THREE.BoxHelper( );
scene.add( line );
var mesh = new THREE.Mesh( new THREE.BoxGeometry
( 2*size, 2*size, 2*size ),
new THREE.MeshNormalMaterial() );
var helper = new THREE.BoxHelper( mesh );
helper.material.color.set( 0x00ffff );
scene.add( helper );
helper.position.set(0, size, 0);
animate();
}
function animate(){
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
}
function onFileSelected(event)
{
<!--STL Loader-->
var loader = new THREE.STLLoader();
var material = new THREE.MeshPhongMaterial( {
color: 0xAAAAAA, specular: 0x111111,shininess: 200
} );
poule = event.target.files[0];
console.debug(poule)
loader.load( poule.name, function ( geometry ) {
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 0, 0 );
mesh.rotation.set( - Math.PI / 2, 0, 0 );
mesh.scale.set( 2, 2, 2 );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
});
}
</script>
</body>
</html>
Why would a beginner do this ? I have to..

Modifying curves's arc in a path

I have a simple box following a path created using the CatmullRomCurve3.
I'd like to have all the curves/edges to be more sharp. But I couldn't figure how to achieve this. Also not sure if I'm using the right type of curve for making paths.
<script src="https://ajax.googleapis.com/ajax/libs/threejs/r76/three.min.js"></script>
<header>
<style>
body canvas{
width: 100%,
height: 100%;
margin:0;
padding:0;
}
</style>
</header>
<body>
</body>
<script>
var renderer, camera, scene, controls, box, path, speed = 0,
path_progress = 0,
axis = new THREE.Vector3(),
tangent = new THREE.Vector3(),
up = new THREE.Vector3(1, 0, 0);
function initRenderer(){
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.setClearColor(0x264d73, 1);
}
function initScene(){
scene = new THREE.Scene();
}
function initCamera(){
camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 10000);
camera.position.set(0, 40, 40);
camera.lookAt(scene.position);
scene.add(camera);
//controls = new THREE.OrbitControls( camera , renderer.domElement );
}
function initLights(){
var aLight = new THREE.AmbientLight(0xD0D0D0, 0.5);
scene.add(aLight);
}
////// Initializers ////////////////////////
function add_path(){
path = new THREE.CatmullRomCurve3( [
new THREE.Vector3( 3.4000015258789062, 0, 3.4000015258789062 ),
new THREE.Vector3( 10.600006103515625, 0, 3.4000015258789062 ),
new THREE.Vector3( 10.600006103515625, 0, 10.600006103515625 ),
new THREE.Vector3( 3.4000015258789062, 0, 10.600006103515625 )
]);
path.closed = true;
speed = 0.4 / path.getLength();
var material = new THREE.LineBasicMaterial({
color: 0xff00f0,
});
var geometry = new THREE.Geometry();
var splinePoints = path.getPoints(20);
for (var i = 0; i < splinePoints.length; i++) {
geometry.vertices.push(splinePoints[i]);
}
var line = new THREE.Line(geometry, material);
scene.add(line);
add_box(splinePoints[0]);
}
function add_box( pos ){
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var materials = [
new THREE.MeshBasicMaterial({
color: 0x80bfff,
}),
new THREE.MeshLambertMaterial({
color: 0x80bfff
}),
new THREE.MeshLambertMaterial({
color: 0x001a33
}),
new THREE.MeshLambertMaterial({
color: 0x80bfff
}),
new THREE.MeshLambertMaterial({
color: 0x80bfff
}),
new THREE.MeshLambertMaterial( {
color: 0x80bfff
})
];
var material = new THREE.MeshFaceMaterial( materials );
box = new THREE.Mesh( geometry, material );
box.scale.set( 1, 1, 1 );
box.position.copy( pos ); //// x,y,z ////
box.rotation.set( 0 , 0 , 0 );
scene.add( box );
camera.position.copy( box.position )
camera.position.x += 20;
camera.position.y += 10;
camera.lookAt(box.position);
setInterval( function(){
follow_path();
}, 100);
}
function follow_path(){
if( path !== null ){
if ( path_progress <= 1) {
camera.lookAt(box.position);
var pos = this.path.getPointAt( this.path_progress );
box.position.copy( pos );
tangent = this.path.getTangentAt( this.path_progress ).normalize();
axis.crossVectors( this.up, this.tangent).normalize();
var radians = Math.acos( this.up.dot(this.tangent) );
box.quaternion.setFromAxisAngle( this.axis, radians );
path_progress += speed;
}else{
path_progress = 0;
}
}
}
///// Mouse events ////////
///// Main /////////
function main(){
//console.log(" Initializing: ");
initRenderer(window.innerWidth, window.innerHeight );
initScene();
initCamera(window.innerWidth, window.innerHeight );
initLights();
add_path();
animate();
}
function animate(){
window.requestAnimationFrame( animate );
render_all();
}
function render_all(){
renderer.render(scene, camera);
}
main();
</script>
It seems that setting the path type = 'catmullrom' and setting the tension=0.1 solved the problem.
<script src="https://ajax.googleapis.com/ajax/libs/threejs/r76/three.min.js"></script>
<header>
<style>
body canvas{
width: 100%,
height: 100%;
margin:0;
padding:0;
}
</style>
</header>
<body>
</body>
<script>
var renderer, camera, scene, controls, box, path, speed = 0,
path_progress = 0,
axis = new THREE.Vector3(),
tangent = new THREE.Vector3(),
up = new THREE.Vector3(1, 0, 0);
function initRenderer(){
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.setClearColor(0x264d73, 1);
}
function initScene(){
scene = new THREE.Scene();
}
function initCamera(){
camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 10000);
camera.position.set(0, 40, 40);
camera.lookAt(scene.position);
scene.add(camera);
//controls = new THREE.OrbitControls( camera , renderer.domElement );
}
function initLights(){
var aLight = new THREE.AmbientLight(0xD0D0D0, 0.5);
scene.add(aLight);
}
////// Initializers ////////////////////////
function add_path(){
path = new THREE.CatmullRomCurve3( [
new THREE.Vector3( 3.4000015258789062, 0, 3.4000015258789062 ),
new THREE.Vector3( 10.600006103515625, 0, 3.4000015258789062 ),
new THREE.Vector3( 10.600006103515625, 0, 10.600006103515625 ),
new THREE.Vector3( 3.4000015258789062, 0, 10.600006103515625 )
]);
path.closed = true;
path.type = "catmullrom";
path.tension = 0.1;
speed = 0.4 / path.getLength();
var material = new THREE.LineBasicMaterial({
color: 0xff00f0,
});
var geometry = new THREE.Geometry();
var splinePoints = path.getPoints(20);
for (var i = 0; i < splinePoints.length; i++) {
geometry.vertices.push(splinePoints[i]);
}
var line = new THREE.Line(geometry, material);
scene.add(line);
add_box(splinePoints[0]);
}
function add_box( pos ){
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var materials = [
new THREE.MeshBasicMaterial({
color: 0x80bfff,
}),
new THREE.MeshLambertMaterial({
color: 0x80bfff
}),
new THREE.MeshLambertMaterial({
color: 0x001a33
}),
new THREE.MeshLambertMaterial({
color: 0x80bfff
}),
new THREE.MeshLambertMaterial({
color: 0x80bfff
}),
new THREE.MeshLambertMaterial( {
color: 0x80bfff
})
];
var material = new THREE.MeshFaceMaterial( materials );
box = new THREE.Mesh( geometry, material );
box.scale.set( 1, 1, 1 );
box.position.copy( pos ); //// x,y,z ////
box.rotation.set( 0 , 0 , 0 );
scene.add( box );
camera.position.copy( box.position )
camera.position.x += 20;
camera.position.y += 10;
camera.lookAt(box.position);
setInterval( function(){
follow_path();
}, 100);
}
function follow_path(){
if( path !== null ){
if ( path_progress <= 1) {
camera.lookAt(box.position);
var pos = this.path.getPointAt( this.path_progress );
box.position.copy( pos );
tangent = this.path.getTangentAt( this.path_progress ).normalize();
axis.crossVectors( this.up, this.tangent).normalize();
var radians = Math.acos( this.up.dot(this.tangent) );
box.quaternion.setFromAxisAngle( this.axis, radians );
path_progress += speed;
}else{
path_progress = 0;
}
}
}
///// Mouse events ////////
///// Main /////////
function main(){
//console.log(" Initializing: ");
initRenderer(window.innerWidth, window.innerHeight );
initScene();
initCamera(window.innerWidth, window.innerHeight );
initLights();
add_path();
animate();
}
function animate(){
window.requestAnimationFrame( animate );
render_all();
}
function render_all(){
renderer.render(scene, camera);
}
main();
</script>

Changing z rotation in three.js animation

I need to add an additional function to change the Z rotation value of the teapot from within the updateTeapot function. I saw this answer Three.js camera tilt up or down and keep horizon level, but how do I incorporate a z rotation function within this function?
function updateTeapot() {
if (teapot != null) {
teaPotHeight+=1;
teapot.position.y = teaPotHeight%200;
}
}
(function ( lab3 , $, undefined) {
lab3.init = function(hook) {
// Create a renderer
var WIDTH = 600,
HEIGHT = 500;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(WIDTH, HEIGHT);
hook.append(renderer.domElement);
var scene = new THREE.Scene();
// Create lights
var pointLight =
new THREE.PointLight(0xFFFFFF);
pointLight.position = new THREE.Vector3(-10, 100, 100);
scene.add(pointLight);
// Add ambient light
var ambient = new THREE.AmbientLight( 0x555555 );
scene.add( ambient );
// Create a camera
var VIEW_ANGLE = 65, //65 FOV is most 'natural' FOV
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1, //these elements are needed for cameras to
FAR = 10000; //partition space correctly
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
camera.position.z = 300;
scene.add(camera);
// Create and add controls
var controls = new THREE.TrackballControls( camera );
controls.target.set( 0, 0, 0 );
// Create a cube
var material =
new THREE.MeshLambertMaterial(
{
color: 0x00bbcc
});
var cube = new THREE.Mesh(
new THREE.CubeGeometry(
40, 55, 30),
material);
scene.add(cube);
// Animation
function renderLoop() {
renderer.render(scene, camera);
controls.update();
window.requestAnimationFrame(renderLoop);
updateTeapot();
}
window.requestAnimationFrame(renderLoop);
////////////////////////////////////////////////
var teapot = null;
var teaPotHeight=0;
loader = new THREE.JSONLoader();
loader.load( "models/utah-teapot.json", function( geometry ) {
teapot = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial({
color: 0x00bb00,
side: THREE.DoubleSide
}));
teapot.scale.set( 20, 20, 20 );
teapot.position = new THREE.Vector3(-30, 100, 20);
function updateTeapot() {
if (teapot != null) {
teaPotHeight+=1;
teapot.position.y = teaPotHeight%200;
}
}
//add it to the scene
scene.add(teapot);
});
}
})(window.lab3 = window.lab3 || {} , jQuery)
Add
teapot.rotation.z = numInRadians;

Why doesn't FileReader pass file to loader.load() used by three.js scene?

I'm trying to use FileReader to pass a client side ASCII file to loader.load() but it looks like the file never gets there. The file does appear in the 3D scene if I use loader.load('server path to test_file.stl') instead of loader.load(fileObject).
I included an alert() function to display the file's ASCII text and that tells me the JavaScript is grabbing and processing the file and there is no Chrome security barrier but apparently I'm not properly passing the file to loader.load().
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color:#fea47c;
}
div {
position:relative;
left:200px;
top:0px;
background-color: #eeeeee;
border:1px solid black;
width:550px;
height:550px;
}
canvas {
width:550px;
height:550px;
}
</style>
</head>
<body>
<script src="https://raw.github.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/loaders/STLLoader.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
<input type="file" id="pickfile"></input>
<script>
document.getElementById('pickfile').addEventListener('change', readFile, false);
function readFile (evt)
{
var fileObject = evt.target.files[0];
var reader = new FileReader();
reader.onload = function() {alert(this.result)}; // verifies ASCII file contents were grabbed
reader.readAsText(fileObject)
}
var container, camera, scene, renderer, controls;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var width = container.clientWidth;
var height = container.clientHeight;
camera = new THREE.PerspectiveCamera( 35, width / height, .1 , 10000);
camera.position.set( 0, 0, 600);
scene = new THREE.Scene();
controls = new THREE.TrackballControls( camera , container);
controls.addEventListener( 'change', render );
// object
var loader = new THREE.STLLoader();
loader.addEventListener( 'load', function ( event ) {
var geometry = event.content;
var material = new THREE.MeshLambertMaterial( { ambient: 0xff5533, color: 0xff5533 } );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
} );
loader.load(fileObject);
// lights
scene.add( new THREE.AmbientLight( 0x222222 ) );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
directionalLight.position = camera.position;
scene.add( directionalLight );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( width , height );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function addLight( x, y, z, color, intensity ) {
var directionalLight = new THREE.DirectionalLight( color, intensity );
directionalLight.position.set( x, y, z )
scene.add( directionalLight );
}
function onWindowResize() {
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
render();
}
function render() {
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
</script>
</body>
</html>
Ok, I tried again this morning, and I think the problem was I was trying to view the loaded results from a bad camera angle or something... anyways, here's an example based on https://raw.github.com/mrdoob/three.js/master/examples/webgl_loader_stl.html
The essential part:
Like I mentioned above, loader.load does not have any overload that would take the actual contents of the file (and it's kinda silly to think it would). It will only take a location for the file... you needed something that creates your model from the file contents. That would be loader.parse.
For example, the following handler adds your model to a scene where scene is in scope of readFile:
function readFile(evt)
{
var fileObject = evt.target.files[0];
var reader = new FileReader();
reader.onload = function ()
{
var loader = new THREE.STLLoader();
//alert(this.result)
var geometry = loader.parse(this.result);
var material = new THREE.MeshPhongMaterial(
{
ambient: 0xff5533,
color: 0xff5533,
specular: 0x111111,
shininess: 200
});
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
};
reader.readAsText(fileObject)
}
Whole example:
I'd put this somewhere on the net but as it uses github to host some of the scripts, etc. that's probably not the best idea.
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Monospace;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
#info {
color: #fff;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display:block;
}
#pickfile {
color: #fff;
position: absolute;
top: 40px;
width: 100%;
text-align: center;
z-index: 100;
display:block;
}
a {
color: skyblue
}
</style>
</head>
<body>
<script src="https://raw.github.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/loaders/STLLoader.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/Detector.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/libs/stats.min.js"></script>
<input type="file" id="pickfile"></input>
<script>
document.getElementById('pickfile').addEventListener('change', readFile, false);
function readFile(evt)
{
var fileObject = evt.target.files[0];
var reader = new FileReader();
reader.onload = function ()
{
var loader = new THREE.STLLoader();
//alert(this.result)
var geometry = loader.parse(this.result);
var material = new THREE.MeshPhongMaterial(
{
ambient: 0xff5533,
color: 0xff5533,
specular: 0x111111,
shininess: 200
});
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
};
reader.readAsText(fileObject)
}
if (!Detector.webgl) Detector.addGetWebGLMessage();
var container, stats;
var camera, scene, renderer, objects;
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, 0.5, 3);
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xffffff, 2, 15);
scene.fog.color.setHSV(0.06, 0.2, 0.45);
// Grid
var size = 20,
step = 0.25;
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial(
{
color: 0x000000
});
for (var i = -size; i <= size; i += step)
{
geometry.vertices.push(new THREE.Vector3(-size, -0.04, i));
geometry.vertices.push(new THREE.Vector3(size, -0.04, i));
geometry.vertices.push(new THREE.Vector3(i, -0.04, -size));
geometry.vertices.push(new THREE.Vector3(i, -0.04, size));
}
var line = new THREE.Line(geometry, material, THREE.LinePieces);
line.position.y = -0.46;
scene.add(line);
// 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;
// Object
// 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,
clearColor: 0x111111,
clearAlpha: 1,
alpha: false
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(scene.fog.color, 1);
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.physicallyBasedShading = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapCullFrontFaces = false;
container.appendChild(renderer.domElement);
// stats
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild(stats.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 = 2048;
directionalLight.shadowMapHeight = 2048;
directionalLight.shadowBias = -0.005;
directionalLight.shadowDarkness = 0.15;
}
function onWindowResize()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//
function animate()
{
requestAnimationFrame(animate);
render();
stats.update();
}
function render()
{
var timer = Date.now() * 0.0005;
camera.position.x = Math.cos(timer) * 5;
camera.position.z = Math.sin(timer) * 5;
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
</script>
</body>
</html>
Thanks a lot for your snippet, this made my day
Though I had a problem implementing your solution at this line :
reader.readAsText(fileObject) ;
I changed it to :
reader.readAsArrayBuffer(fileObject) ;
and it works like a charm...
So for the complete code :
1) I have a button in my html to load the .stl file :
select your stl file <br>
<input type="file" id="pickFile" />
2) in my js file :
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var camera, scene, renderer, mesh, controls ;
var group ;
var container = document.getElementById('canvas3D');
// Create default material
material = new THREE.MeshPhongMaterial();
init();
animate();
// file input button
document.getElementById('pickFile').addEventListener('change', openFile, false);
// file load
function openFile (evt) {
var fileObject = evt.target.files[0];
// delete previous objects from scene
while(group.children.length > 0){
group.remove(group.children[0]);
}
var reader = new FileReader();
reader.onload = function ()
{
var loader = new THREE.STLLoader();
// parse the .stl file
var geometry = loader.parse(this.result);
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
group.add(mesh);
};
// --> update here
reader.readAsArrayBuffer(fileObject) ;
};
// and the rest of my three.js code there : init() and animate() functions ...

Categories