提交 2a90d9d2 编写于 作者: A Adam Leeper

adds binary STL support, example

上级 48325645
......@@ -4,7 +4,11 @@
*
* Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.
*
* Limitations: Currently supports ASCII format only
* Supports both binary and ASCII encoded files, with automatic detection of type.
*
* Limitations: Binary decoding ignores header. There doesn't seem to be much of a use for it.
* There is perhaps some question as to how valid it is to always assume little-endian-ness.
* ASCII decoding assumes file is UTF-8. Seems to work for the examples...
*
* Usage:
* var loader = new THREE.STLLoader();
......@@ -35,7 +39,8 @@ THREE.STLLoader.prototype = {
request.addEventListener( 'load', function ( event ) {
var geometry = scope.parse( event.target.responseText );
var geometry;
geometry = scope.parse( event.target.response );
scope.dispatchEvent( { type: 'load', content: geometry } );
......@@ -56,11 +61,51 @@ THREE.STLLoader.prototype = {
}, false );
request.open( 'GET', url, true );
request.responseType = "arraybuffer";
request.send( null );
},
parse: function ( data ) {
bin2str: function (buf) {
var array_buffer = new Uint8Array(buf);
var str = '';
for(var i = 0; i < buf.byteLength; i++) {
str += String.fromCharCode(array_buffer[i]); // implicitly assumes little-endian
}
return str
},
isASCII: function(buf){
var dv = new DataView(buf);
var str = '';
for(var i = 0; i < 5; i++) {
str += String.fromCharCode(dv.getUint8(i, true)); // assume little-endian
}
return (str.toLowerCase() == 'solid'); // All ASCII stl files begin with 'solid'
},
parse: function (buf) {
if( this.isASCII(buf) )
{
var str = this.bin2str(buf);
console.log("Detected ASCII stl file.");
return this.parseASCII(str);
}
else
{
console.log("Detected Binary stl file.");
return this.parseBinary(buf);
}
},
parseASCII: function ( data ) {
var geometry = new THREE.Geometry();
......@@ -99,6 +144,53 @@ THREE.STLLoader.prototype = {
return geometry;
}
},
parseBinary: function (buf) {
// STL binary format specification, as per http://en.wikipedia.org/wiki/STL_(file_format)
//
// UINT8[80] – Header
// UINT32 – Number of triangles
//
// foreach triangle
// REAL32[3] – Normal vector
// REAL32[3] – Vertex 1
// REAL32[3] – Vertex 2
// REAL32[3] – Vertex 3
// UINT16 – Attribute byte count
// end
//
var geometry = new THREE.Geometry();
var header_length = 80;
var data_offset = 84;
var face_length = 12*4 + 2;
var header = new Uint8Array(buf, 0, header_length);
var num_triangles = new Uint32Array(buf, header_length, 1);
var le = true; // is little-endian? // This might be processor dependent...
for (var i = 0; i < num_triangles[0]; i++) {
var dv = new DataView(buf, data_offset + i*face_length, face_length);
var normal = new THREE.Vector3( dv.getFloat32(0, le), dv.getFloat32(4, le), dv.getFloat32(8, le) );
for(var v = 3; v < 12; v+=3) {
geometry.vertices.push( new THREE.Vector3( dv.getFloat32(v*4, le), dv.getFloat32((v+1)*4, le), dv.getFloat32( (v+2)*4, le ) ) );
}
var len = geometry.vertices.length;
geometry.faces.push( new THREE.Face3( len - 3, len - 2, len - 1, normal ) );
}
geometry.computeCentroids();
geometry.computeBoundingSphere();
return geometry;
}
};
此差异已折叠。
此差异已折叠。
......@@ -24,12 +24,33 @@
}
a { color: skyblue }
</style>
.button { background:#999; color:#eee; padding:0.2em 0.5em; cursor:pointer }
.highlight { background:orange; color:#fff; }
span {
display: inline-block;
width: 60px;
float: left;
text-align: center;
}
</style>
</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank">three.js</a> -
STL loader test by <a href="https://github.com/aleeper">aleeper</a>
<p></p>
<div style="display:inline-block; width:310px; text-align: left" >
<span id="clickBinary" class="button highlight" >Binary</span>
&nbsp- PR2 head from <a href="http://www.ros.org/wiki/pr2_description">www.ros.org</a>
</div>
<p></p>
<div style="display:inline-block; width:310px; text-align: left" >
<span id="clickASCII" class="button" >ASCII</span>
&nbsp- A simple CAD part.
</div>
</div>
<script src="../build/three.min.js"></script>
......@@ -45,7 +66,9 @@
var container, stats;
var camera, scene, renderer, objects;
var camera, scene, renderer, objects = [];
var button_binary, button_ASCII;
init();
animate();
......@@ -55,6 +78,12 @@
container = document.createElement( 'div' );
document.body.appendChild( container );
// Set up buttons
button_binary = document.getElementById('clickBinary');
button_binary.addEventListener( "click", loadBinaryExample, false );
button_ASCII = document.getElementById('clickASCII');
button_ASCII.addEventListener( "click", loadASCIIExample, false );
camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 15 );
camera.position.set( 3, 0.5, 3 );
......@@ -94,21 +123,7 @@
plane.receiveShadow = true;
// Object
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 mesh = new THREE.Mesh( geometry, material );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
} );
loader.load( './models/stl/slotted_disk.stl' );
loadBinaryExample();
// Lights
......@@ -181,7 +196,70 @@
}
//
function loadBinaryExample() {
button_binary.className = "button highlight";
button_ASCII.className = "button";
// Clear out old objects
for(var i = 0; i < objects.length; i++)
scene.remove(objects[i]);
var scale = 2.0;
var material = new THREE.MeshPhongMaterial( { ambient: 0x555555, color: 0xAAAAAA, specular: 0x111111, shininess: 200 } );
loadFile('./models/stl/binary/pr2_head_pan.stl', scale, new THREE.Vector3(0,0,0), new THREE.Vector3(-Math.PI/2, 0, 0), material);
loadFile('./models/stl/binary/pr2_head_tilt.stl', scale, new THREE.Vector3(0.068*scale, 0, 0), new THREE.Vector3(-Math.PI/2, 0.3, 0), material);
}
function loadASCIIExample() {
button_binary.className = "button";
button_ASCII.className = "button highlight";
// Clear out old objects
for(var i = 0; i < objects.length; i++)
scene.remove(objects[i]);
loadFile('./models/stl/ascii/slotted_disk.stl', 1.0, null, new THREE.Vector3(-Math.PI/2, 0, 0));
}
function loadFile( filename, scale, offset, rotate, material ) {
if(scale == null)
scale = 1.0;
if(offset == null)
offset = new THREE.Vector3(0,0,0);
if(rotate == null)
rotate = new THREE.Vector3(0,0,0);
if(material == null)
material = new THREE.MeshPhongMaterial( { ambient: 0xff5533, color: 0xff5533, 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.scale = new THREE.Vector3(scale, scale, scale);
mesh.position = offset;
mesh.rotation = rotate;
mesh.castShadow = true;
mesh.receiveShadow = true;
objects.push(mesh);
scene.add( objects[ objects.length - 1 ] );
} );
loader.load( filename );
}
function animate() {
......@@ -196,8 +274,8 @@
var timer = Date.now() * 0.0005;
camera.position.x = Math.cos( timer ) * 5;
camera.position.z = Math.sin( timer ) * 5;
camera.position.x = Math.cos( timer ) * 3;
camera.position.z = Math.sin( timer ) * 3;
camera.lookAt( scene.position );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册