-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4f06413
commit d5df2b3
Showing
3 changed files
with
187 additions
and
195 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { Object3D } from 'three' | ||
|
||
export interface STLExporterOptionsBinary { | ||
binary: true | ||
} | ||
|
||
export interface STLExporterOptionsString { | ||
binary?: false | ||
} | ||
|
||
export interface STLExporterOptions { | ||
binary?: boolean | ||
} | ||
|
||
export class STLExporter { | ||
constructor() | ||
|
||
parse(scene: Object3D, options: STLExporterOptionsBinary): DataView | ||
parse(scene: Object3D, options?: STLExporterOptionsString): string | ||
parse(scene: Object3D, options?: STLExporterOptions): string | DataView | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import { Vector3 } from 'three' | ||
|
||
/** | ||
* Usage: | ||
* const exporter = new STLExporter(); | ||
* | ||
* // second argument is a list of options | ||
* const data = exporter.parse( mesh, { binary: true } ); | ||
* | ||
*/ | ||
|
||
class STLExporter { | ||
parse(scene, options = {}) { | ||
options = Object.assign( | ||
{ | ||
binary: false, | ||
}, | ||
options, | ||
) | ||
|
||
const binary = options.binary | ||
|
||
// | ||
|
||
const objects = [] | ||
let triangles = 0 | ||
|
||
scene.traverse(function (object) { | ||
if (object.isMesh) { | ||
const geometry = object.geometry | ||
|
||
const index = geometry.index | ||
const positionAttribute = geometry.getAttribute('position') | ||
|
||
triangles += index !== null ? index.count / 3 : positionAttribute.count / 3 | ||
|
||
objects.push({ | ||
object3d: object, | ||
geometry: geometry, | ||
}) | ||
} | ||
}) | ||
|
||
let output | ||
let offset = 80 // skip header | ||
|
||
if (binary === true) { | ||
const bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4 | ||
const arrayBuffer = new ArrayBuffer(bufferLength) | ||
output = new DataView(arrayBuffer) | ||
output.setUint32(offset, triangles, true) | ||
offset += 4 | ||
} else { | ||
output = '' | ||
output += 'solid exported\n' | ||
} | ||
|
||
const vA = new Vector3() | ||
const vB = new Vector3() | ||
const vC = new Vector3() | ||
const cb = new Vector3() | ||
const ab = new Vector3() | ||
const normal = new Vector3() | ||
|
||
for (let i = 0, il = objects.length; i < il; i++) { | ||
const object = objects[i].object3d | ||
const geometry = objects[i].geometry | ||
|
||
const index = geometry.index | ||
const positionAttribute = geometry.getAttribute('position') | ||
|
||
if (index !== null) { | ||
// indexed geometry | ||
|
||
for (let j = 0; j < index.count; j += 3) { | ||
const a = index.getX(j + 0) | ||
const b = index.getX(j + 1) | ||
const c = index.getX(j + 2) | ||
|
||
writeFace(a, b, c, positionAttribute, object) | ||
} | ||
} else { | ||
// non-indexed geometry | ||
|
||
for (let j = 0; j < positionAttribute.count; j += 3) { | ||
const a = j + 0 | ||
const b = j + 1 | ||
const c = j + 2 | ||
|
||
writeFace(a, b, c, positionAttribute, object) | ||
} | ||
} | ||
} | ||
|
||
if (binary === false) { | ||
output += 'endsolid exported\n' | ||
} | ||
|
||
return output | ||
|
||
function writeFace(a, b, c, positionAttribute, object) { | ||
vA.fromBufferAttribute(positionAttribute, a) | ||
vB.fromBufferAttribute(positionAttribute, b) | ||
vC.fromBufferAttribute(positionAttribute, c) | ||
|
||
if (object.isSkinnedMesh === true) { | ||
object.applyBoneTransform(a, vA) | ||
object.applyBoneTransform(b, vB) | ||
object.applyBoneTransform(c, vC) | ||
} | ||
|
||
vA.applyMatrix4(object.matrixWorld) | ||
vB.applyMatrix4(object.matrixWorld) | ||
vC.applyMatrix4(object.matrixWorld) | ||
|
||
writeNormal(vA, vB, vC) | ||
|
||
writeVertex(vA) | ||
writeVertex(vB) | ||
writeVertex(vC) | ||
|
||
if (binary === true) { | ||
output.setUint16(offset, 0, true) | ||
offset += 2 | ||
} else { | ||
output += '\t\tendloop\n' | ||
output += '\tendfacet\n' | ||
} | ||
} | ||
|
||
function writeNormal(vA, vB, vC) { | ||
cb.subVectors(vC, vB) | ||
ab.subVectors(vA, vB) | ||
cb.cross(ab).normalize() | ||
|
||
normal.copy(cb).normalize() | ||
|
||
if (binary === true) { | ||
output.setFloat32(offset, normal.x, true) | ||
offset += 4 | ||
output.setFloat32(offset, normal.y, true) | ||
offset += 4 | ||
output.setFloat32(offset, normal.z, true) | ||
offset += 4 | ||
} else { | ||
output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n' | ||
output += '\t\touter loop\n' | ||
} | ||
} | ||
|
||
function writeVertex(vertex) { | ||
if (binary === true) { | ||
output.setFloat32(offset, vertex.x, true) | ||
offset += 4 | ||
output.setFloat32(offset, vertex.y, true) | ||
offset += 4 | ||
output.setFloat32(offset, vertex.z, true) | ||
offset += 4 | ||
} else { | ||
output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n' | ||
} | ||
} | ||
} | ||
} | ||
|
||
export { STLExporter } |
This file was deleted.
Oops, something went wrong.