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 ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With