diff --git a/scr/finalizeMesh.js b/scr/finalizeMesh.js new file mode 100644 index 0000000..5c127e2 --- /dev/null +++ b/scr/finalizeMesh.js @@ -0,0 +1,117 @@ +import { Matrix4, Vector3, Vector4 } from "three"; + +var finalizeMesh = function() {}; + +finalizeMesh.prototype = { + + constructor: finalizeMesh, + + parse: function (mesh) { + + if (!mesh.isMesh) { + console.warn('Mesh type unsupported', mesh); + return; + } + + var vertex = new Vector3(); + var i, l = []; + var nbVertex = 0; + var geometry = mesh.geometry; + + var mrot = new Matrix4().makeRotationX(90 * Math.PI / 180); + + var msca = new Matrix4().makeScale(10, 10, 10); + + if (geometry.isBufferGeometry) { + var newGeometry = geometry.clone(geometry); + var vertices = geometry.getAttribute('position'); + + // vertices + if (vertices !== undefined) { + for (i = 0, l = vertices.count; i < l; i++ , nbVertex++) { + vertex.x = vertices.getX(i); + vertex.y = vertices.getY(i); + vertex.z = vertices.getZ(i); + + if (geometry.skinIndexNames == undefined) { + vertex.applyMatrix4(mesh.matrixWorld).applyMatrix4(mrot).applyMatrix4(msca); + newGeometry.attributes.position.setXYZ(i, vertex.x, vertex.y, vertex.z); + } else { + var finalVector = new Vector4(); + if (geometry.morphTargetInfluences !== undefined) { + + var morphVector = new Vector4(vertex.x, vertex.y, vertex.z); + var tempMorph = new Vector4(); + + for (var mt = 0; mt < geometry.morphAttributes.position.length; mt++) { + if (geometry.morphTargetInfluences[mt] == 0) continue; + if (geometry.morphTargetDictionary.hide == mt) continue; + + var morph = new Vector4( + geometry.morphAttributes.position[mt].getX(i), + geometry.morphAttributes.position[mt].getY(i), + geometry.morphAttributes.position[mt].getZ(i)); + + tempMorph.addScaledVector(morph.sub(morphVector), geometry.morphTargetInfluences[mt]); + } + morphVector.add(tempMorph); + } + + for (var si = 0; si < geometry.skinIndexNames.length; si++) { + + var skinIndices = geometry.getAttribute([geometry.skinIndexNames[si]]) + var weights = geometry.getAttribute([geometry.skinWeightNames[si]]) + + var skinIndex = []; + skinIndex[0] = skinIndices.getX(i); + skinIndex[1] = skinIndices.getY(i); + skinIndex[2] = skinIndices.getZ(i); + skinIndex[3] = skinIndices.getW(i); + + var skinWeight = []; + skinWeight[0] = weights.getX(i); + skinWeight[1] = weights.getY(i); + skinWeight[2] = weights.getZ(i); + skinWeight[3] = weights.getW(i); + + var inverses = []; + inverses[0] = mesh.skeleton.boneInverses[skinIndex[0]]; + inverses[1] = mesh.skeleton.boneInverses[skinIndex[1]]; + inverses[2] = mesh.skeleton.boneInverses[skinIndex[2]]; + inverses[3] = mesh.skeleton.boneInverses[skinIndex[3]]; + + var skinMatrices = []; + skinMatrices[0] = mesh.skeleton.bones[skinIndex[0]].matrixWorld; + skinMatrices[1] = mesh.skeleton.bones[skinIndex[1]].matrixWorld; + skinMatrices[2] = mesh.skeleton.bones[skinIndex[2]].matrixWorld; + skinMatrices[3] = mesh.skeleton.bones[skinIndex[3]].matrixWorld; + + for (var k = 0; k < 4; k++) { + if (geometry.morphTargetInfluences !== undefined) { + var tempVector = new Vector4(morphVector.x, morphVector.y, morphVector.z); + } else { + var tempVector = new Vector4(vertex.x, vertex.y, vertex.z); + } + + tempVector.multiplyScalar(skinWeight[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]) + .applyMatrix4(mrot).applyMatrix4(msca); + finalVector.add(tempVector); + } + } + newGeometry.attributes.position.setXYZ(i, finalVector.x, finalVector.y, finalVector.z); + } + } + } + } else { + console.warn( 'Geometry type unsupported', geometry ); + } + + return newGeometry; + } +}; + +export { finalizeMesh }; diff --git a/scr/saver.js b/scr/saver.js index 8b13789..05f763d 100644 --- a/scr/saver.js +++ b/scr/saver.js @@ -1 +1,119 @@ +import { MeshBasicMaterial, Group, Mesh } from 'three'; +import { STLExporter } from 'three/examples/jsm/exporters/STLExporter.js'; +import { OBJExporter } from 'three/examples/jsm/exporters/OBJExporter.js'; +import { SubdivisionModifier } from 'three/examples/jsm/modifiers/SubdivisionModifier.js'; +import { saveAs } from 'file-saver'; +import jQuery from 'jquery'; +import { arrive } from 'arrive'; +import { finalizeMesh } from './finalizeMesh.js'; +function save_stl() { + var smooth = jQuery('#subdivideSLT').val() > 0 ? jQuery('#subdivideSLT').val() : undefined; + + var group = process(CK.character, smooth); + + var exporter = new STLExporter(); + var fileString = exporter.parse(group); + + var name = get_name(); + + var blob = new Blob([fileString], { type: "application/sla;charset=utf-8" }); + saveAs(blob, name + ((smooth) ? '-smooth' : '') + '.stl'); +}; + +function save_obj() { + var smooth = jQuery('#subdivideSLT').val(); + + var group = process(CK.character, smooth); + + var exporter = new OBJExporter(); + var fileString = exporter.parse(group); + + var name = get_name(); + + var blob = new Blob([fileString], { type: "text/plain;charset=utf-8" }); + saveAs(blob, name + ((smooth) ? '-smooth' : '') + '.obj'); +}; + +function save_json(){ + var name = get_name(); + + var blob = new Blob([JSON.stringify(CK.data.getJson())], {type: "text/plain;charset=utf-8"}); + + saveAs(blob, name + ".json"); +}; + +function load_json (e) { + var file = e.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + e.preventDefault(); + CK.change(JSON.parse(e.target.result)); + }; + })(file); + + if (file != undefined) reader.readAsText(file); +}; + +function get_name() { + var getName = CK.character.data.meta.character_name; + return getName === "" ? "Hero" : getName; +}; + +function subdivide(geometry, subdivisions) { + var modifier = new SubdivisionModifier( subdivisions ); + var smoothGeometry = modifier.modify( geometry ); + return smoothGeometry; +}; + +function process(object3d, smooth) { + var material = new MeshBasicMaterial(); + var group = new Group(); + + object3d.traverseVisible(function (object) { + if (object.isMesh) { + + var exporter = new finalizeMesh(); + var geometry = exporter.parse(object); + + if (smooth + && object.name != 'baseRim' + && object.name != 'base') { + geometry = subdivide(geometry, smooth); + } + + var mesh = new Mesh(geometry, material); + + group.add(mesh); + } + }); + return group; +}; + +document.body.arrive(".footer", { onceOnly: true, existing: true }, function () { + jQuery('.headerMenu:last').remove(); + jQuery('a:contains(Log In)').remove(); + jQuery(".headerMenu-nav-item:contains(Save)").remove(); + jQuery(".headerMenu-nav-item:contains(Share)").remove(); + jQuery(".headerMenu-nav-item:contains(Heroes)").remove(); + jQuery(".editorFooter").empty(); + jQuery("li.tab-Material").remove(); + jQuery(".footer").empty(); + + var style = { "margin-left": "20px", "font-size": "1.4em", "color": "rgba(255, 255, 255, 0.8)", "cursor": "pointer" }; + jQuery("
", { class: "content-side", css: { "align-items": "center" } }).append([ + jQuery("", { css: style, text: "STL" }).on("click", save_stl), + jQuery("", { css: style, text: "OBJ" }).on("click", save_obj), + jQuery('').on("change", load_json) + ]); +});