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..
Related
I am trying to render a 3D model using Three.js on the browser and also trying to add annotations similar to https://sketchfab.com/3d-models/interactive-test-778258c754a74d37a72d3274b80c6ce1 . I am using https://manu.ninja/webgl-three-js-annotations/ as a reference. I tried following the first half of the article which just adds the screen projections but i dont see any annotations in my model.Would really appreciate any help in understanding what i am missing.
HTML code
<html>
<head>
<title>Cube</title>
<style>
body { margin: 0;}
</style>
</head>
<body>
<div class="annotation">
<p><strong>Cube</strong></p>
<p>Sentence about cube</p>
</div>
<canvas id="number" width="64" height="64"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>
<script src="/assets/OrbitControls.js"></script>
<script src="http://rawcdn.githack.com/mrdoob/three.js/r99/examples/js/loaders/GLTFLoader.js"></script>
<script src="/examples/3d-obj-loader/scripts_annotation.js"></script>
</body>
</html>
scripts_annotation.js
//global variables
var camera, scene, renderer, controls;
var sprite, spriteBehindObject, model;
init();
render();
//camera set up and model loading
function init(){
//camera settings
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 2, 2000 );
camera.position.set(700,500,1250);
scene = new THREE.Scene();
//renderer setting
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio(window.devicePixelRatio);
// renderer.setClearColor(0x1E1E1E);
renderer.setClearColor(0xffffff);
renderer.gammaFactor = 2.2;
renderer.gammaOutput = true;
renderer.physicallyCorrectLights = true;
document.body.appendChild( renderer.domElement );
window.addEventListener('resize',onWindowResize, false);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var urls = [ 'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg' ];
var loader = new THREE.CubeTextureLoader().setPath( '/examples/3d-obj-loader/reflections/Park2/' );
var background = loader.load( urls );
var light = new THREE.HemisphereLight( 0xffffff, 0xffffff , 5 );
light.position.set( 0, 1, 0 );
scene.add( light );
//model
// Mesh
const cubeGeometry = new THREE.BoxGeometry(500, 500, 500);
mesh = new THREE.Mesh(
cubeGeometry,
new THREE.MeshPhongMaterial({
color: 0x156289,
emissive: 0x072534,
side: THREE.DoubleSide,
shading: THREE.FlatShading
})
);
const line = new THREE.LineSegments(
new THREE.WireframeGeometry(cubeGeometry),
new THREE.LineBasicMaterial({
color: 0xffffff,
linewidth: 1,
opacity: 0.25,
transparent: true
})
);
scene.add(mesh);
scene.add(line);
}
function onWindowResize(){
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function render(){
requestAnimationFrame( render );
controls.update();
renderer.render(scene, camera);
updateScreenPosition();
}
function updateScreenPosition() {
const vector = new THREE.Vector3(0, 17, 8);
const canvas = renderer.domElement;
vector.project(camera);
vector.x = Math.round((0.5 + vector.x / 2) * (canvas.width / window.devicePixelRatio));
vector.y = Math.round((0.5 - vector.y / 2) * (canvas.height / window.devicePixelRatio));
const annotation = document.querySelector(".annotation");
annotation.style.top = `${vector.y}px`;
annotation.style.left = `${vector.x}px`;
annotation.style.opacity = spriteBehindObject ? 0.25 : 1;
}
Solved this issue by replacing the following line in html file on my local machine
<link rel="stylesheet" href="/examples/3d-obj-loader/Surface_style.scss" type="text/scss"> to <link rel="stylesheet" href="/examples/3d-obj-loader/Surface_style.scss" type="text/css">
This line was the only difference between the codepen and code on my local machine
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
I'm working with three.js and attempting to create procedural texture which can be stored and then applied to objects later in a session.
Ideally, I would like to create these textures only once each.
I would like to be able to sample from existing assets to create new textures.
Within the three.js example, a version of this is shown where the texture is re-rendered every frame. http://threejs.org/examples/webgl_rtt.html
I have created an example of what I hope to achieve here: http://www.forsako.com/ThreeJS/RenderTest.html
Unfortunately, to make this work, I had to re-render the texture each frame.
Is there a way to perform this rendering so that the texture persists over multiple frames until I tell it to be released? Source from my main program follows.
<html>
<head>
<title>Render Test</title>
</head>
<style>
#mycontainer {
background: #000;
width: 800px;
height: 600px;
}
</style>
<body>
<div id="mycontainer"></div>
</body>
<script src="js/three.min.js"></script>
<script src="js/TrackballControls.js"></script>
<script src="js/stats.min.js"></script>
<script src="js/PlaneGeomUV.js"></script>
<script type="text/javascript">
var Renderer, Container, Scene, Camera, Quad1, Quad2, Plane, MaterialRTT, TextureRTT, LightAmb;
var SceneRTT, CameraRTT, Q1RTT, Q2RTT, Q3RTT, Q4RTT, MaterialFromFile, TextureFromFile;
var isRenderingTex = true;
var WidthWin = 800;
var HeightWin = 640;
var WidthTile = 428;
var HeightTile = 683;
Init();
Animate();
function Init(){
var CAngle = 45;
var CAspect = WidthWin / HeightWin;
var CNearCut = 0.1;
var CFarCut = 10000;
// Set up the main rendering object and attach it to an element on the page
Renderer = new THREE.WebGLRenderer();
Renderer.setSize( WidthWin, HeightWin );
Container = document.getElementById( "mycontainer" );
Container.appendChild( Renderer.domElement );
// Set up the textures and materials for rendering
TextureFromFile = THREE.ImageUtils.loadTexture( "Assets/Map_Tiles.png" );
TextureRTT = MakeTex( Renderer, TextureFromFile, WidthTile, HeightTile );
MaterialFromFile = new THREE.MeshBasicMaterial( { color: 0xffffff, map: TextureFromFile } );
MaterialRTT = new THREE.MeshBasicMaterial( { color: 0xffffff, map: TextureRTT } );
MaterialFromFile.side = THREE.DoubleSide;
MaterialRTT.side = THREE.DoubleSide;
// Set up the main renderable scene
Scene = new THREE.Scene();
Plane = new THREE.PlaneGeometry( WidthTile, HeightTile );
Quad1 = new THREE.Mesh( Plane, MaterialFromFile );
Quad1.position.x = WidthTile*0.5;
Scene.add( Quad1 );
Quad2 = new THREE.Mesh( Plane, MaterialRTT );
Quad2.position.x = -WidthTile*0.5;
Scene.add( Quad2 );
LightAmb = new THREE.AmbientLight( 0xffffff );
Scene.add( LightAmb );
Camera = new THREE.PerspectiveCamera( CAngle, CAspect, CNearCut, CFarCut );
Camera.position.z = 1200;
Scene.add( Camera );
// Create controls using the TrackballControls library to easily manipulate our camera
Controls = new THREE.TrackballControls( Camera );
Controls.target = new THREE.Vector3( 0, 0, 0 );
Controls.rotateSpeed = 4.0;
Controls.zoomSpeed = 6.0;
Controls.panSpeed = 1.0;
Controls.noZoom = false;
Controls.noPan = false;
Controls.staticMoving = true;
Controls.dynamicDampingFactor = 0.3;
Controls.keys = [ 65, 83, 68 ];
// Add the Three.js stats object so we can track fps
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
Container.appendChild( stats.domElement );
}
function MakeTex( Renderer_in, Texture_in, Width_in, Height_in ){
var ParamsTex = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
var Tex_out = new THREE.WebGLRenderTarget( WidthWin, HeightWin, ParamsTex );
var tMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff, map: Texture_in } );
// Set up the scene for rendering to texture
SceneRTT = new THREE.Scene();
var tPlane = new THREE.PlaneGeometry( WidthTile*0.5, HeightTile*0.5 );
Q1RTT = new THREE.Mesh( tPlane, tMaterial );
Q1RTT.position.x = WidthTile*0.25;
Q1RTT.position.y = HeightTile*0.25;
SceneRTT.add( Q1RTT );
Q2RTT = new THREE.Mesh( tPlane, tMaterial );
Q2RTT.position.x = -WidthTile*0.25;
Q2RTT.position.y = HeightTile*0.25;
SceneRTT.add( Q2RTT );
Q3RTT = new THREE.Mesh( tPlane, tMaterial );
Q3RTT.position.x = -WidthTile*0.25;
Q3RTT.position.y = -HeightTile*0.25;
SceneRTT.add( Q3RTT );
Q4RTT = new THREE.Mesh( tPlane, tMaterial );
Q4RTT.position.x = WidthTile*0.25;
Q4RTT.position.y = -HeightTile*0.25;
SceneRTT.add( Q4RTT );
tLightAmb = new THREE.AmbientLight( 0xffffff );
SceneRTT.add( tLightAmb );
CameraRTT = new THREE.OrthographicCamera( -Width_in / 2, Width_in / 2, Height_in / 2, -Height_in / 2, 0.1, 10000 );
CameraRTT.position.z = 600;
SceneRTT.add( CameraRTT );
//Renderer.clear();
//Renderer.render( SceneRTT, CameraRTT, Tex_out, true );
return Tex_out;
}
function Animate(){
requestAnimationFrame( Animate );
Controls.update();
stats.update();
Render();
}
function Render(){
Renderer.clear();
if( isRenderingTex ){
Renderer.render( SceneRTT, CameraRTT, TextureRTT, true );
//isRenderingTex = false;
}
Renderer.render( Scene, Camera );
}
</script>
</html>
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 ...
I'm quite new to ThreeJS and I have a small issue (probably wrong usage). I'm trying to create a custom geometry and define the faces normals by myself.
I create one normal in one direction and the other one in the opposite direction, as my Mesh is not 2 sided I expect to see only one of the face, however I can see both of them... Any Idea of what I'm doing wrong ?
Thanks!
<body>
<script src="../build/Three.js"></script>
<script src="js/Stats.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.position.x = 300;
camera.position.y = -1000;
camera.position.z = 1000;
camera.lookAt(new THREE.Vector3(300, 250, 0));
scene.add( camera );
var light, geometry, material;
scene.add( new THREE.AmbientLight( 0x404040 ) );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 0 );
scene.add( light );
material = new THREE.MeshBasicMaterial( { color: 0xFFFF00, wireframe: false, transparent: false, opacity: 1 } );
geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0,0,0));
geometry.vertices.push(new THREE.Vector3(600,0,0));
geometry.vertices.push(new THREE.Vector3(0,-500,0));
geometry.vertices.push(new THREE.Vector3(600,-500,0));
var face;
face = new THREE.Face3(0,2,1);
face.normal.set(0,0,-1);
geometry.faces.push(face);
face = new THREE.Face3(2,3,1);
face.normal.set(0,0,1);
geometry.faces.push(face);
geometry.computeCentroids();
//geometry.computeFaceNormals();
//geometry.computeTangents();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
renderer.render( scene, camera );
</script>
</body>
WebGLRenderer uses the vertex order in which you created the face for defining the orientation instead of the normal. Try doing this:
face = new THREE.Face3(2,1,3);