-
-
Save jcarletto27/e271bbb7639c4bed2427 to your computer and use it in GitHub Desktop.
/** | |
* Based on https://github.com/mrdoob/three.js/blob/a72347515fa34e892f7a9bfa66a34fdc0df55954/examples/js/exporters/STLExporter.js | |
* Tested on r68 and r70 | |
* @author jcarletto / https://github.com/jcarletto27 | |
* @author kjlubick / https://github.com/kjlubick | |
* @author kovacsv / http://kovacsv.hu/ | |
* @author mrdoob / http://mrdoob.com/ | |
*/ | |
THREE.STLExporter = function () {}; | |
THREE.STLExporter.prototype = { | |
constructor : THREE.STLExporter, | |
parse : (function () { | |
var vector = new THREE.Vector3(); | |
var normalMatrixWorld = new THREE.Matrix3(); | |
return function (scene) { | |
var output = ''; | |
output += 'solid exported\n'; | |
scene.traverse(function (object) { | |
if (object instanceof THREE.Mesh) { | |
var geometry = object.geometry; | |
var matrixWorld = object.matrixWorld; | |
var mesh = object; | |
if (geometry instanceof THREE.Geometry) { | |
var vertices = geometry.vertices; | |
var faces = geometry.faces; | |
normalMatrixWorld.getNormalMatrix(matrixWorld); | |
for (var i = 0, l = faces.length; i < l; i++) { | |
var face = faces[i]; | |
vector.copy(face.normal).applyMatrix3(normalMatrixWorld).normalize(); | |
output += '\tfacet normal ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n'; | |
output += '\t\touter loop\n'; | |
var indices = [face.a, face.b, face.c]; | |
for (var j = 0; j < 3; j++) { | |
var vertexIndex = indices[j]; | |
if (mesh.geometry.skinIndices.length == 0) { | |
vector.copy(vertices[vertexIndex]).applyMatrix4(matrixWorld); | |
output += '\t\t\tvertex ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n'; | |
} else { | |
vector.copy(vertices[vertexIndex]); //.applyMatrix4( matrixWorld ); | |
// see https://github.com/mrdoob/three.js/issues/3187 | |
boneIndices = []; | |
boneIndices[0] = mesh.geometry.skinIndices[vertexIndex].x; | |
boneIndices[1] = mesh.geometry.skinIndices[vertexIndex].y; | |
boneIndices[2] = mesh.geometry.skinIndices[vertexIndex].z; | |
boneIndices[3] = mesh.geometry.skinIndices[vertexIndex].w; | |
weights = []; | |
weights[0] = mesh.geometry.skinWeights[vertexIndex].x; | |
weights[1] = mesh.geometry.skinWeights[vertexIndex].y; | |
weights[2] = mesh.geometry.skinWeights[vertexIndex].z; | |
weights[3] = mesh.geometry.skinWeights[vertexIndex].w; | |
inverses = []; | |
inverses[0] = mesh.skeleton.boneInverses[boneIndices[0]]; | |
inverses[1] = mesh.skeleton.boneInverses[boneIndices[1]]; | |
inverses[2] = mesh.skeleton.boneInverses[boneIndices[2]]; | |
inverses[3] = mesh.skeleton.boneInverses[boneIndices[3]]; | |
skinMatrices = []; | |
skinMatrices[0] = mesh.skeleton.bones[boneIndices[0]].matrixWorld; | |
skinMatrices[1] = mesh.skeleton.bones[boneIndices[1]].matrixWorld; | |
skinMatrices[2] = mesh.skeleton.bones[boneIndices[2]].matrixWorld; | |
skinMatrices[3] = mesh.skeleton.bones[boneIndices[3]].matrixWorld; | |
//this checks to see if the mesh has any morphTargets - jc | |
if (mesh.geometry.morphTargets !== 'undefined') { | |
morphMatricesX = []; | |
morphMatricesY = []; | |
morphMatricesZ = []; | |
morphMatricesInfluence = []; | |
for (var mt = 0; mt < mesh.geometry.morphTargets.length; mt++) { | |
//collect the needed vertex info - jc | |
morphMatricesX[mt] = mesh.geometry.morphTargets[mt].vertices[vertexIndex].x; | |
morphMatricesY[mt] = mesh.geometry.morphTargets[mt].vertices[vertexIndex].y; | |
morphMatricesZ[mt] = mesh.geometry.morphTargets[mt].vertices[vertexIndex].z; | |
morphMatricesInfluence[mt] = mesh.morphTargetInfluences[mt]; | |
} | |
} | |
var finalVector = new THREE.Vector4(); | |
if (mesh.geometry.morphTargets !== 'undefined') { | |
var morphVector = new THREE.Vector4(vector.x, vector.y, vector.z); | |
for (var mt = 0; mt < mesh.geometry.morphTargets.length; mt++) { | |
//not pretty, but it gets the job done - jc | |
morphVector.lerp(new THREE.Vector4(morphMatricesX[mt], morphMatricesY[mt], morphMatricesZ[mt], 1), morphMatricesInfluence[mt]); | |
} | |
} | |
for (var k = 0; k < 4; k++) { | |
if (mesh.geometry.morphTargets !== 'undefined') { | |
var tempVector = new THREE.Vector4(morphVector.x, morphVector.y, morphVector.z); | |
} else { | |
var tempVector = new THREE.Vector4(vector.x, vector.y, vector.z); | |
} | |
tempVector.multiplyScalar(weights[k]); | |
//the inverse takes the vector into local bone space | |
//which is then transformed to the appropriate world space | |
tempVector.applyMatrix4(inverses[k]) | |
.applyMatrix4(skinMatrices[k]); | |
finalVector.add(tempVector); | |
} | |
output += '\t\t\tvertex ' + finalVector.x + ' ' + finalVector.y + ' ' + finalVector.z + '\n'; | |
} | |
} | |
output += '\t\tendloop\n'; | |
output += '\tendfacet\n'; | |
} | |
} | |
} | |
}); | |
output += 'endsolid exported\n'; | |
return output; | |
}; | |
} | |
()) | |
}; | |
function saveSTL(scene, name) { | |
var exporter = new THREE.STLExporter(); | |
var stlString = exporter.parse(scene); | |
var blob = new Blob([stlString], { | |
type : 'text/plain' | |
}); | |
saveAs(blob, name + '.stl'); | |
} | |
var exporter = new THREE.STLExporter(); | |
var exportString = function (output, filename) { | |
var blob = new Blob([output], { | |
type : 'text/plain' | |
}); | |
var objectURL = URL.createObjectURL(blob); | |
var link = document.createElement('a'); | |
link.href = objectURL; | |
link.download = filename || 'data.json'; | |
link.target = '_blank'; | |
link.click(); | |
}; |
STL Export is working but only the base size is getting exported.
Hi! I updated your code. I include support of BufferGeometry and support of AMD, common.js and ES6 modules. Also I published npm package and added you to contributors in package.json. https://github.com/atnartur/three-STLexporter
Hi! All I get is scene.traverse is not a function
...
Do you have any idea why?
(using revision 81)
I've modified the OBJ Exporter to incorporate bones, and morph data like this one, only it uses bufferGeometry instead of the standard Geometry type
https://gist.github.com/jcarletto27/35b19f811c657ec73b0238d78413f88d
atnartur's version converts the BufferGeometry to geometry which loses all the bone and morph data, this version works with them directly. Either version should work depending on your needs.
I manipulate the positions of my meshes before exporting, but they all appear centered in the output STL.
Any way to get the proper positions in the STL?
Thanks
could some one help, i'm trying to make poser, where i have a fbx file send to three js and then via transform controller i i create poses, and i want to export the result . i tried this code and still did not work
when we try to export the 3D Scene loaded via threejs json loader to STL The scale/size is not outputting (we are applying blendshapes/morph targets)