Alan Colon 7 gadi atpakaļ
vecāks
revīzija
3b4812b5ba
6 mainītis faili ar 217 papildinājumiem un 159 dzēšanām
  1. 15 0
      src/array.js
  2. 129 153
      src/baker.js
  3. 13 2
      src/index.js
  4. 35 0
      src/stl.js
  5. 5 4
      src/three.js
  6. 20 0
      src/transformed-skin-vertex.js

+ 15 - 0
src/array.js

@@ -0,0 +1,15 @@
+const slices = (array, step) => {
+  const ret = []
+  for (var i = 0; i < array.length; i += step) {
+    ret.push(array.slice(i, i + step))
+  }
+  return ret
+}
+
+const pushAll = (target, array) =>
+  target.constructor.prototype.push.apply(target, array)
+
+module.exports = {
+  slices,
+  pushAll
+}

+ 129 - 153
src/baker.js

@@ -1,5 +1,11 @@
+const { slices, pushAll } = require('./array')
+const {toStl, rotate} = require('./stl')
+
 const THREE = require('./three')
 
+const transformedSkinVertex = require('./transformed-skin-vertex')
+
+
 THREE.Baker = function() {};
 
 THREE.Baker.prototype = {
@@ -20,7 +26,8 @@ THREE.Baker.prototype = {
       //
 
       var objects = [];
-      var triangles = 0;
+      var triangles = [];
+      const _triangles = triangles
 
       scene.traverse(function(object) {
 
@@ -28,107 +35,50 @@ THREE.Baker.prototype = {
 
           if (object.pose && object.skeleton && typeof(object.skeleton.pose) == 'function') {
             console.log('Posing object', object)
-            object.pose();
+            //object.pose();
+          }
+          if (object.geometry && object.geometry.attributes) {
+            object.geometry.attributes._geometry = object.geometry
+            object.geometry.attributes._object = object
+            console.log(object.geometry.attributes)
           }
-          console.log(object)
           var og = object.geometry;
           var geometry = object.geometry;
           /* FROM */
 
-          function checkBufferGeometryIntersection(object, positions, uvs, a, b, c) {
-            var inverseMatrix = new THREE.Matrix4();
-            var ray = new THREE.Ray();
-            var sphere = new THREE.Sphere();
-
-            var vA = new THREE.Vec3();
-            var vB = new THREE.Vec3();
-            var vC = new THREE.Vec3();
-
-            var tempA = new THREE.Vec3();
-            var tempB = new THREE.Vec3();
-            var tempC = new THREE.Vec3();
-
-            var uvA = new THREE.Vec2();
-            var uvB = new THREE.Vec2();
-            var uvC = new THREE.Vec2();
-
-            var barycoord = new THREE.Vec3();
-
-            var intersectionPoint = new THREE.Vec3();
-            var intersectionPointWorld = new THREE.Vec3();
-            vA.fromArray(positions, a * 3);
-            vB.fromArray(positions, b * 3);
-            vC.fromArray(positions, c * 3);
-
-            if (object.boneTransform) {
-
-              vA = object.boneTransform(vA, a);
-              vB = object.boneTransform(vB, b);
-              vC = object.boneTransform(vC, c);
-
-            }
-          }
-          var uvs, intersection;
-
+          let positions, triangles, skinIndices, skinWeights
           if (geometry instanceof THREE.BufferGeometry) {
-            debugger;
-            console.log('BUFFER')
             var a, b, c;
             var index = geometry.index;
             var attributes = geometry.attributes;
-            var positions = attributes.position.array;
-
-            if (attributes.uv !== undefined) {
-
-              uvs = attributes.uv.array;
-
-            }
-
-            if (index !== null) {
-
-              var indices = index.array;
-
-              for (var i = 0, l = indices.length; i < l; i += 3) {
-
-                a = indices[i];
-                b = indices[i + 1];
-                c = indices[i + 2];
-
-                intersection = checkBufferGeometryIntersection(this, positions, uvs, a, b, c);
-
-                if (intersection) {
-
-                  intersection.faceIndex = Math.floor(i / 3); // triangle number in indices buffer semantics
-                  intersects.push(intersection);
 
-                }
+            // Figure out where each triangle is supposed to be, globally.
+            positions = slices(attributes.position.array, 3).map(([x, y, z]) => new THREE.Vec3(x, y, z));
+            triangles = index
+            ? slices(Array.from(index.array).map(i => positions[i]), 3)
+            : slices(positions, 3)
 
-              }
-
-            } else {
-
-
-              for (var i = 0, l = positions.length; i < l; i += 9) {
-
-                a = i / 3;
-                b = a + 1;
-                c = a + 2;
-
-                intersection = checkBufferGeometryIntersection(this, positions, uvs, a, b, c);
-
-                if (intersection) {
-
-                  intersection.index = a; // triangle number in positions buffer semantics
-                  intersects.push(intersection);
-
-                }
-
-              }
-
-            }
+            if (attributes.skinIndex) {
+              skinIndices = slices(Array.from(attributes.skinIndex.array), 4)
+              skinWeights = slices(attributes.skinWeight.array, 4)
+            }  
 
           } else if (geometry instanceof THREE.Geometry) {
             console.log('GEOMETRY')
+
+            positions = geometry.vertices.map(v => v.clone())
+            triangles = geometry.faces.map(({a, b, c}) => [
+              positions[a],
+              positions[b],
+              positions[c]
+            ])
+            if (object.geometry.skinIndices) {
+              skinIndices = object.geometry.skinIndices.map(({x, y, z, w}) => [x, y, z, w])
+              skinWeights = object.geometry.skinWeights.map(({x, y, z, w}) => [x, y, z, w])
+            }  
+
+            {
+  /*
             var fvA, fvB, fvC;
             //var isFaceMaterial = material instanceof THREE.MultiMaterial;
             //var materials = isFaceMaterial === true ? material.materials : null;
@@ -149,7 +99,7 @@ THREE.Baker.prototype = {
               fvB = vertices[face.b];
               fvC = vertices[face.c];
 
-              /*
+              / *
               if ( faceMaterial.morphTargets === true ) {
 
                   var morphTargets = geometry.morphTargets;
@@ -182,90 +132,116 @@ THREE.Baker.prototype = {
                   fvC = vC;
 
               }
-              */
+              * /
 
-              if (this.boneTransform) {
-                console.log('YES')
-                fvA = this.boneTransform(fvA, face.a);
-                fvB = this.boneTransform(fvB, face.b);
-                fvC = this.boneTransform(fvC, face.c);
+              // if (this.boneTransform) {
+              //   console.log('YES')
+              //   fvA = this.boneTransform(fvA, face.a);
+              //   fvB = this.boneTransform(fvB, face.b);
+              //   fvC = this.boneTransform(fvC, face.c);
 
-              }
+              // }
 
 
 
             }
-
+*/
+            }
           } else {
             console.log(geometry && geometry.constructor.name || 'Non-Geo')
           }
 
+          let o = object
+          // positions.forEach((p, i) => {
+          //   p.applyMatrix4(object.matrixWorld)
+          // })
+          if (skinIndices) {
+            // const skinIndices = object.geometry.skinIndices.map(({x, y, z, w}) => [x, y, z, w])
+            // const skinWeights = object.geometry.skinWeights.map(({x, y, z, w}) => [x, y, z, w])
+            const bones = object.skeleton.bones
+
+            positions.forEach((p, index) => {
+
+              var skinIndex = skinIndices[index]
+              var skinWeight = skinWeights[index]
+              const skinVertex = p.clone().applyMatrix4(object.bindMatrix)
+              //var skinVertex = positions[index].applyMatrix4(object.bindMatrix)
+              //(new THREE.Vector3 ()).fromAttribute (skin.geometry.getAttribute ('position'), index).applyMatrix4 (skin.bindMatrix);
+              var result = new THREE.Vector3 ()
+              var temp = new THREE.Vector3 ()
+              var tempMatrix = new THREE.Matrix4 ()
+              var properties = ['x', 'y', 'z', 'w'];
+              for (var i = 0; i < 4; i++) {
+                  var boneIndex = skinIndex[i];
+                  if (boneIndex >= 0) {
+                    tempMatrix.multiplyMatrices (object.skeleton.bones[boneIndex].matrixWorld, object.skeleton.boneInverses[boneIndex]);
+                    //result.add (temp.copy (skinVertex).multiplyScalar (skinWeights[properties[i]]).applyMatrix4 (tempMatrix));
+                    //result.add (temp.copy (skinVertex).applyMatrix4 (tempMatrix).multiplyScalar (skinWeight[i]));
+                    result.add(skinVertex.clone().applyMatrix4(tempMatrix).multiplyScalar(skinWeight[i]))
+                  }
+            
+              }
+              result.applyMatrix4(object.bindMatrixInverse)
+
+              p.copy(result)
+              //return result.applyMatrix4 (skin.bindMatrixInverse);
+            
+              // const skinIndex = skinIndices[i]
+              // const skinWeight = skinWeights[i]
+              // skinIndex.forEach((s, j) => {
+              //   //https://stackoverflow.com/questions/31620194/how-to-calculate-transformed-skin-vertices
+              //   //result.add (temp.copy (skinVertex).applyMatrix4 (tempMatrix).multiplyScalar (skinWeights[properties[i]]));
+
+
+              //   const w = skinWeight[j]
+              //   const bone = bones[s]
+              //   if (bone) {
+              //     p.add(p.clone().applyMatrix4(bone.matrixWorld).multiplyScalar(w))
+              //   }
+              // })
+            })
 
-          /* END FROM*/
-
-          if (geometry.isBufferGeometry) {
-            geometry = new THREE.Geometry().fromBufferGeometry(geometry);
           }
+          
 
+          // attributes.position is a flattened Array<Array<Vector3>>.
+          // attributes.skinIndex is a flattened Array<Array(4)<Int>>. Each is an ordinal to a bone.
+          // attributes.skinWeight is a flattened Array<Array(4)<Float>>. Each is a 0.0 - 1.0 weight for a bone.
 
-          /*
-          if ( geometry.isGeometry ) {
-              if (object.skeleton) {
-                  const allBones = object.skeleton.bones;
-                  const position = Array.from(og.attributes.position.array);
-                  const skinWeight = Array.from(og.attributes.skinWeight.array);
-                  const skinIndex = Array.from(og.attributes.skinIndex.array);
-                  // "loop each vert"
-                  geometry.vertices.forEach((v, i) => {
-                      const p = i * 3;
-                      const f = i * 4;
-                      var pos = new THREE.Vec3(position[p], position[p + 1], position[p + 2]);
-                      var weights = skinWeight.slice(i * 4, i * 4 + 4);
-                      var totalWeight = weights.reduce((a, b) => a + b);
-                      var indices = skinIndex.slice(i * 4, i * 4 + 4);
-                      var bones = indices.map((a, b) => allBones[a].matrix);
-                      // "then over each bone that affects that vert"
-                      var applied = bones.map((bone, i) =>
-                          pos.clone().applyMatrix4(
-                              // "weighted if you have bone weights"
-                              bone.clone().multiplyScalar(weights[i] / totalWeight)
-                          )
-                      )
-                      // "accumulate that"
-                      var final = applied.reduce((a, b) => a.add(b), new THREE.Vec3(0, 0, 0))
-
-                      final.multiplyScalar(1/4)
-                      //bones.forEach((bone, i) => pos.applyMatrix4(bone.clone().multiplyScalar(weights[i])))
-                      v.set(final.x, final.y, final.z)
-                  })
-                  /*
-                  geometry.vertices.forEach(v => {
-                      object.skeleton.bones.forEach(b => {
-                          window.xx = [v, b]
-                          v.applyMatrix4(b.matrixWorld.clone().multiplyScalar(1/object.skeleton.bones.length))
-                      })
-                  })
-                  * /
-              };
-
-              object.geometry = geometry;
-
-              triangles += geometry.faces.length;
-              objects.push( {
-
-                  geometry: geometry,
-                  matrixWorld: object.matrixWorld,
-                  boneMatrices: object.skeleton && object.skeleton.boneMatrices
-
-              } );
 
-          }
-          */
+          // if (attributes.skinIndex) {
+          //   const skinIndex = attributes.skinIndex
+          //   const skinWeight = attributes.skinWeight
+
+          //   const bones = object.skeleton.bones
+          //   const bonesPerPosition = slices(Array.from(skinIndex.array).map(i => bones[i]), 4)
+          //   const weightsPerPosition = slices(skinWeight.array, 4)
+          //   positions.forEach((p, i) => {
+          //     const bones = bonesPerPosition[i]
+          //     const weights = weightsPerPosition[i]
+          //     bones.forEach((bone, b) => {
+          //       const weight = weights[b]
+          //       if (weight !== 0) {
+          //         const matrix = bone.matrix.clone().multiply(object.matrixWorld)
+          //         //matrix.multiplyScalar(weight)
+          //         p.applyMatrix4(matrix)
+          //       }
+          //     })
+          //   })
+          // }
 
+
+          pushAll(_triangles, triangles)
+
+          /* END FROM*/
         }
 
       });
 
+      console.log('Triangles', triangles)
+      const stl = toStl(rotate(triangles))
+      window.save = (filename) => console.save(stl, filename || 'export.stl')
+      console.log('save([filename]) to save')
     };
 
   }())

+ 13 - 2
src/index.js

@@ -3,14 +3,25 @@ const walk = require('./walk')
 
 const THREE = require('./three')
 
+window.character = window.CK && CK.characters[0].characterDisplay.threeObj
+window.character = window.character || scene.children[4]
+
+if (window.scene) {
+  var i = -6
+  scene.traverse(o => {
+    o.name = o.type + i++
+  })
+  scene.getObjectByName('Bone3').rotation.z = 32  
+}
+
 window.bake = () => {
   const baker = new THREE.Baker();
-  baker.parse(CK.characters[0].characterDisplay.threeObj);
+  baker.parse(character);
   console.log('Baked');
 }
 window.save = (filename) => {
   const exporter = new THREE.GLTFExporter();
-  exporter.parse(CK.characters[0].characterDisplay.threeObj, data => {
+  exporter.parse(character, data => {
     window.data = data;
     console.log('done')
     if (filename) console.save(JSON.stringify(window.data), `${filename}.gltf`)

+ 35 - 0
src/stl.js

@@ -0,0 +1,35 @@
+const surfaceNormal = triangle => {
+  const [p1, p2, p3] = triangle
+  const v = p2.clone().sub(p1)
+  const w = p3.clone().sub(p1)
+  const nx = (v.y * w.z) - (v.z * w.y)
+  const ny = (v.z * w.x) - (v.x * w.z)
+  const nz = (v.x * w.y) - (v.y * w.x)
+  const m = Math.abs(nx) + Math.abs(ny) + Math.abs(nz)
+  const ax = nx / m
+  const ay = ny / m
+  const az = nz / m
+  return [ax, ay, az]
+}
+
+const toStl = (triangles) => {
+  const output = []
+  output.push('solid exported')
+  triangles.forEach(t => {
+    output.push(` facet normal ${surfaceNormal(t).join(' ')}`)
+    output.push('  outer loop')
+    t.forEach(v => output.push(`  vertex ${v.x} ${v.y} ${v.z}`))
+    output.push('  endloop')
+    output.push(' endfacet')
+    output.push('')
+  })
+  output.push('endsolid exported')
+  output.push('')
+  return output.join('\n')
+}
+
+const rv = (v) => new v.constructor(v.x, -v.z, v.y)
+
+const rotate = (triangles) => triangles.map(([a, b, c]) => [rv(a), rv(b), rv(c)])
+
+module.exports = {toStl, rotate}

+ 5 - 4
src/three.js

@@ -1,9 +1,10 @@
-const THREE = RK;
-THREE.Vector3 = THREE.Vec3;
+const THREE = window.THREE || RK;
+THREE.Vector3 = THREE.Vec3 || THREE.Vector3;
+THREE.Vec3 = THREE.Vector3;
 
 // Add default .toString() functions to display the type, name, and ID.
-Object.keys(RK).forEach(key => {
-  const Type = RK[key]
+Object.keys(THREE).forEach(key => {
+  const Type = THREE[key]
   if (Type && Type.prototype && !Type.prototype.hasOwnProperty('toString')) {
     Type.prototype.toString = function() {
       const description = [key, this.name, this.id].filter(x => x === 0 || x).join(' ')

+ 20 - 0
src/transformed-skin-vertex.js

@@ -0,0 +1,20 @@
+var transformedSkinVertex = function (skin, index) {
+  var skinIndices = (new THREE.Vector4 ()).fromAttribute (skin.geometry.getAttribute ('skinIndex'), index);
+  var skinWeights = (new THREE.Vector4 ()).fromAttribute (skin.geometry.getAttribute ('skinWeight'), index);
+  var skinVertex = (new THREE.Vector3 ()).fromAttribute (skin.geometry.getAttribute ('position'), index).applyMatrix4 (skin.bindMatrix);
+  var result = new THREE.Vector3 ()
+  var temp = new THREE.Vector3 ()
+  var tempMatrix = new THREE.Matrix4 ()
+  var properties = ['x', 'y', 'z', 'w'];
+
+  for (var i = 0; i < 4; i++) {
+      var boneIndex = skinIndices[properties[i]];
+      tempMatrix.multiplyMatrices (skin.skeleton.bones[boneIndex].matrixWorld, skin.skeleton.boneInverses[boneIndex]);
+      //result.add (temp.copy (skinVertex).multiplyScalar (skinWeights[properties[i]]).applyMatrix4 (tempMatrix));
+      result.add (temp.copy (skinVertex).applyMatrix4 (tempMatrix).multiplyScalar (skinWeights[properties[i]]));
+
+  }
+  return result.applyMatrix4 (skin.bindMatrixInverse);
+};
+
+module.exports = transformedSkinVertex