Skip to content

Instantly share code, notes, and snippets.

@scmanjarrez
Last active April 7, 2022 22:01
Show Gist options
  • Save scmanjarrez/f51ff1c7a3d50a6051d392a98c2533b6 to your computer and use it in GitHub Desktop.
Save scmanjarrez/f51ff1c7a3d50a6051d392a98c2533b6 to your computer and use it in GitHub Desktop.
Export threejs json to stl (used with thigiverse js models: example: https://cdn.thingiverse.com/threejs_json/16/3f/4e/a9/e6/large.js)
<html>
<head>
<title>STL viewer</title>
<script src="https://metalop.com/threejs/scripts/threejs/three.min.js"></script>
<script src="https://metalop.com/threejs/scripts/threejs/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.16"></script>
<script src="https://cdn.jsdelivr.net/npm/three-stlexporter@1.0.0"></script>
</head>
<body>
<script>
"use strict";
//Globals
var clock, renderer, effect, scene, model, material, camera, controls, gui, name;
var exporter = new THREE.STLExporter();
var browseModel = function() {
var browseButton;
return function() {
browseButton = document.createElement("input");
Object.assign(browseButton, {
type: "file",
multiple: false,
style: "display: none",
accept: ".js, .json",
onchange: function(e) {
let file = browseButton.files[0];
let parts = file.name.split(".");
name = parts[0];
let reader = new FileReader();
reader.onload = function(event) {
let result = event.target.result;
let loader = new THREE.JSONLoader();
if (model) scene.remove(model);
let data = JSON.parse(result);
let geometry = loader.parse(data);
addFromGeometry(geometry);
}
reader.readAsText(file);
}
});
browseButton.click();
};
}();
function addFromGeometry(geometry) {
if (material) material.dispose();
if (geometry.hasColors) {
console.log("color attribute found. Trying to enable vertex colors.");
material = new THREE.MeshPhongMaterial({
transparent: true,
opacity: geometry.alpha || 1,
vertexColors: THREE.VertexColors
});
} else {
console.log("No color attribute found. Using default color.");
material = new THREE.MeshLambertMaterial({
transparent: true,
opacity: geometry.alpha || 1,
color: 0x26f7f4
});
}
if (model) scene.remove(model);
model = new THREE.Mesh(geometry.geometry, material);
model.rotation.x = true * (-0.5 * Math.PI);
scene.add(model);
adjustCameraToModel(model);
}
function adjustCameraToModel(mesh) {
var middle = new THREE.Vector3;
var geometry = mesh.geometry;
geometry.computeBoundingBox();
middle.x = (geometry.boundingBox.max.x + geometry.boundingBox.min.x) / 2;
middle.y = (geometry.boundingBox.max.y + geometry.boundingBox.min.y) / 2;
middle.z = (geometry.boundingBox.max.z + geometry.boundingBox.min.z) / 2;
mesh.localToWorld(middle);
let bb = new THREE.Box3().setFromObject(model).expandByPoint(scene.position);
let diag = bb.max.clone().sub(bb.min).length();
let factor = Math.max(1, 1 / camera.aspect) / Math.tan(0.5 * (Math.PI * camera.fov / 180));
camera.position.normalize().multiplyScalar(diag * factor);
camera.near = Math.min(0.5 * factor, 1);
camera.far = 4 * diag * factor; //wrong?
(bb.max.x < bb.min.x) || (bb.max.y < bb.min.y) || (bb.max.z < bb.min.z) ? controls.target.set(0, 0, 0): controls.target.addVectors(bb.min, bb.max).multiplyScalar(0.5);
camera.lookAt(controls.target);
camera.updateProjectionMatrix();
requestAnimationFrame(render);
}
(function main() {
//Renderer setup
clock = new THREE.Clock( /*false*/ ); //false vil skru av autostart
document.body.style = "overflow: hidden;";
var container = document.createElement("div");
container.style = "position: absolute; top: 0; left: 0;"
document.body.appendChild(container);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xb3b3e5);
container.appendChild(renderer.domElement);
//Scene setup:
scene = new THREE.Scene();
var sun = new THREE.HemisphereLight(0xFFFFFF, 0x000000, 0.5);
scene.add(sun);
//Camera setup
camera = new THREE.PerspectiveCamera(26, window.innerWidth / window.innerHeight, 1, 100000);
window.addEventListener('resize', function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
requestAnimationFrame(render);
}, false);
camera.position.set(50, 50, -100);
scene.add(camera);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener("change", () => requestAnimationFrame(render));
//Menu
gui = new lil.GUI();
gui.add({
browse: function() {
browseModel();
}
}, "browse");
gui.add({
opacity: 1
}, "opacity", 0, 1).onChange(function(value) {
if (material !== undefined) {
material.opacity = value;
} else {
if (model) {
model.traverse((obj) => {
if (obj.isMesh) {
obj.material.opacity = value;
}
});
}
}
requestAnimationFrame(render);
});
gui.addColor({
color: "#26f7f4"
}, "color").onChange(function(value) {
if (material !== undefined) {
material.color = new THREE.Color(value);
} else {
if (model) {
model.traverse((obj) => {
if (obj.isMesh) {
obj.material.color = new THREE.Color(value);
}
});
}
}
requestAnimationFrame(render);
});
gui.add({
zUp: true
}, "zUp").onChange(function(value) {
if (model) {
model.rotation.x = value * (-0.5 * Math.PI);
adjustCameraToModel(model);
}
});
gui.addColor({
background: "#b3b3e5"
}, "background").onChange(value => {
renderer.setClearColor(value);
requestAnimationFrame(render);
});
gui.add({
exportSTL: function() {
exportSTL();
}
}, "exportSTL");
requestAnimationFrame(render);
const link = document.createElement('a');
link.style.display = 'none';
document.body.appendChild(link);
function exportSTL() {
console.log(camera.position);
if (model) {
const result = exporter.parse(model);
saveString(result, name + '.stl');
}
};
function save(blob, filename) {
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
}
function saveString(text, filename) {
save(new Blob([text], {
type: 'text/plain'
}), filename);
}
})();
function render() {
renderer.render(scene, camera);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment