Last active
January 4, 2016 07:09
-
-
Save GRGSIBERIA/8586645 to your computer and use it in GitHub Desktop.
擬似的なスキンメッシュアニメーションをやるスクリプト
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
using UnityEngine; | |
using System.Collections.Generic; | |
using System.Collections; | |
using System.IO; | |
using System.Text; | |
public class SkinnedMeshConverter | |
{ | |
// 頂点インデックスとウェイトのペア | |
class IndexWeight | |
{ | |
public int Index { get; private set; } | |
public float Weight { get; private set; } | |
public IndexWeight(int index, float weight) | |
{ | |
Index = index; | |
Weight = weight; | |
} | |
} | |
GameObject gameObject; | |
GameObject rootBone; | |
Transform[] boneList; | |
Vector3[] originalVertices; | |
Vector3[] copiedVertices; | |
BoneWeight[] boneWeights; | |
Transform[] breadthDepthTransforms; | |
Dictionary<Transform, List<IndexWeight>> boneToVertexAndWeight = new Dictionary<Transform, List<IndexWeight>>(); | |
// 変数の初期化とか | |
void InitVariables() | |
{ | |
var skinnedmesh = gameObject.GetComponent<SkinnedMeshRenderer>(); | |
boneList = skinnedmesh.bones; | |
originalVertices = skinnedmesh.sharedMesh.vertices; | |
copiedVertices = (Vector3[])originalVertices.Clone(); | |
boneWeights = skinnedmesh.sharedMesh.boneWeights; | |
CollectBoneWeight(); | |
breadthDepthTransforms = ConstructBreadthDepthTransforms(); | |
} | |
public SkinnedMeshConverter(GameObject gameObject, GameObject rootBone) | |
{ | |
this.gameObject = gameObject; | |
this.rootBone = rootBone; | |
InitVariables(); | |
foreach (var t in breadthDepthTransforms) | |
{ | |
TransformVerticesFromBone(t); | |
} | |
} | |
public void ExportCSV(string filename_without_extension) | |
{ | |
string path = "C:/" + filename_without_extension + ".csv"; | |
using (StreamWriter sw = new StreamWriter(path, false, Encoding.GetEncoding("shift_jis"))) | |
{ | |
for (int i = 0; i < copiedVertices.Length; i++) | |
{ | |
if (originalVertices[i] != copiedVertices[i]) | |
{ | |
var v = originalVertices[i] - copiedVertices[i]; | |
sw.WriteLine(string.Format("{0},{1},{2},{3}", i, v.x, v.y, v.z)); | |
} | |
} | |
} | |
} | |
Transform[] ConstructBreadthDepthTransforms() | |
{ | |
// 最初のボーンを処理する | |
var transformList = new List<List<Transform>>(); | |
var root = rootBone.transform; | |
transformList.Add(new List<Transform>()); | |
transformList[0].Add(root); | |
// 再帰的に幅優先でボーンを取得する | |
ConstructBreadthDepthTransforms(1, root, transformList); | |
// 幅優先で取得したボーンをそのまま配列に展開する | |
List<Transform> buffer = new List<Transform>(); | |
foreach (var list in transformList) | |
buffer.AddRange(list); | |
return buffer.ToArray(); | |
} | |
void ConstructBreadthDepthTransforms(int depth, Transform target, List<List<Transform>> transformList) | |
{ | |
// もっと深くなったらリストをnewする | |
if (transformList.Count <= depth) | |
transformList.Add(new List<Transform>()); | |
// 幅優先でTransformを並べる | |
for (int i = 0; i < target.childCount; i++) | |
{ | |
var child = target.GetChild(i); | |
transformList[depth].Add(child); | |
ConstructBreadthDepthTransforms(depth + 1, child, transformList); | |
} | |
} | |
void TransformVerticesFromBone(Transform target) | |
{ | |
// ボーンごとにアサインされている頂点をブレンディングする | |
if (boneToVertexAndWeight.ContainsKey(target)) | |
{ | |
foreach (var bw in boneToVertexAndWeight[target]) | |
{ | |
var vertex = originalVertices[bw.Index]; | |
var vector = vertex - target.position; | |
var rotate = Quaternion.Slerp(Quaternion.identity, target.localRotation, bw.Weight); | |
var new_vector = rotate * vector; | |
originalVertices[bw.Index] = new_vector + target.position; | |
} | |
} | |
} | |
void CollectBoneWeight() | |
{ | |
for (int vi = 0; vi < boneWeights.Length; vi++) | |
{ | |
// BoneWeightの中身を展開して一つ一つ頂点とTransformを対応付ける | |
int[] indices = { boneWeights[vi].boneIndex0, boneWeights[vi].boneIndex1, boneWeights[vi].boneIndex2, boneWeights[vi].boneIndex3 }; | |
float[] weights = { boneWeights[vi].weight0, boneWeights[vi].weight1, boneWeights[vi].weight2, boneWeights[vi].weight3 }; | |
CollectIndicesAndWeight(vi, indices, weights); | |
} | |
} | |
void CollectIndicesAndWeight(int vi, int[] indices, float[] weights) | |
{ | |
for (int j = 0; j < 4; j++) | |
{ | |
// ボーンごとにアサインされている頂点とウェイトを収集する | |
var t = boneList[indices[j]]; | |
if (!boneToVertexAndWeight.ContainsKey(t)) | |
boneToVertexAndWeight[t] = new List<IndexWeight>(); | |
if (weights[j] > 0f) | |
boneToVertexAndWeight[t].Add(new IndexWeight(vi, weights[j])); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment