/// <summary> /// Internal method, applies delta offset translation for each morph. /// </summary> /// <remarks> /// we may want to tally the totals once and apply it once. /// </remarks>> private void ApplyBindPoseChanges(JCTMorph morph) { float v = morph.m_value; //range is 0->1 (used as a percent for the deltas below) if (morph.m_nodes != null && current_bind_poses.Length == morph.m_nodes.Length) { for (int i = 0; i < current_bind_poses.Length; i++) { current_bone_positions[i] += morph.m_offsets[i] * v; current_bind_poses[i][12] -= morph.m_nodes[i].x * v; //updating the x translation value of the matrix current_bind_poses[i][13] -= morph.m_nodes[i].y * v; //updating the y translation value of the matrix current_bind_poses[i][14] -= morph.m_nodes[i].z * v; //updating the z translation value of the matrix } } }
/// <summary> /// Creates the JCT transition on import. Passing in the Exact geometry GameObject, one at a time. /// </summary> /// <param name="destination">Destination GameObject.</param> /// <param name="go">GameObject with geometry.</param> /// <param name="geometryId">Geometry identifier.</param> /// <param name="asset_path">Asset path.</param> public static void CreateJCTTransitionOnImport(GameObject destination, GameObject go, string geometryId, string asset_path) { // Morpher morpher = obj.transform.parent.gameObject.GetComponentInChildren (typeof (Morpher)) as Morpher; SkinnedMeshRenderer skinned_mesh_renderer = go.GetComponent <SkinnedMeshRenderer> (); // we'll skip calling handleskinnedmeshrenderer and just do what it does here but streamline it for our usage Transform[] bones = skinned_mesh_renderer.bones; // the importer passes in the path string assetPath = asset_path; string baseName = geometryId; //first let's look for the "new" way, which is a JCTs.json file that sits next to the .fbx file, if we can't find anything we'll fall back string jsonPath = assetPath.Substring(0, assetPath.LastIndexOf("/")) + "/JCTs.json"; if (File.Exists(jsonPath)) { //UnityEngine.Debug.Log ("I found a JCTs.json file: " + jsonPath + " , unpacking and using"); JCTsPacked packed = JsonUtility.FromJson <JCTsPacked> (File.ReadAllText(jsonPath)); Regex basePattern = new Regex(baseName + @"\.base$"); Regex baseNamePattern = new Regex(baseName); //we need to get the base first... string[] baseNames = null; Vector3[] baseNodes = null; Vector3[] baseOffsets = null; bool foundBase = false; //convert XYZFemale_LOD0.Aged_Posture to Aged_Posture, this is for dual compatibility for (int i = 0; i < packed.names.Length; i++) { int pos = packed.names[i].IndexOf('.'); if (pos >= 0) { packed.names[i] = packed.names[i].Substring(pos + 1); } } //UnityEngine.Debug.Log("Packed file contains: " + packed.count + " | " + packed.names.Length + " | " + packed.jcts.Length); for (int i = 0; i < packed.count; i++) { if (packed.names[i].Equals("base")) { //found the base Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(packed.jcts[i])); using (StreamReader reader = new StreamReader(stream)){ getJCTDataFromStream(reader, out baseNames, out baseNodes, out baseOffsets); } foundBase = true; break; } } if (!foundBase) { UnityEngine.Debug.LogWarning("Unable to locate base morph in JCT file, this means JCTs WILL NOT WORK"); } if (foundBase) { int[] nodeMap = calcNodeMap(bones, baseNames); List <JCTMorph> jct_list = new List <JCTMorph> (); //loop again and put the regular ones in for (int j = 0; j < packed.count; j++) { //if (baseNamePattern.Match (packed.names [j]).Success) { //pre 1.5 Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(packed.jcts [j])); string[] morph_names; Vector3[] nodes; Vector3[] offsets; string morph_name = Unescape(packed.names [j]); using (StreamReader reader = new StreamReader(stream)) { getJCTDataFromStream(reader, out morph_names, out nodes, out offsets); JCTMorph morph = new JCTMorph(); morph.m_name = morph_name; morph.m_value = 0; bool hasNodeDelta = false; Vector3[] nodeDeltas = new Vector3[bones.Length]; Vector3[] nodeOffsets = new Vector3[bones.Length]; for (int i = 0; i < bones.Length; i++) { int ii = nodeMap [i]; nodeDeltas [i] = nodes [ii] - baseNodes [ii]; nodeOffsets [i] = offsets [ii] - baseOffsets [ii]; if (nodeDeltas [i].sqrMagnitude > Mathf.Epsilon) { hasNodeDelta = true; } } if (hasNodeDelta) { morph.m_nodes = nodeDeltas; morph.m_offsets = nodeOffsets; jct_list.Add(morph); } } //} } if (jct_list.Count <= 0) { UnityEngine.Debug.LogWarning("JCT morph list is empty, morphs that affect bones will not work properly"); } JCTMorph[] morphs = jct_list.ToArray(); // add the data to the jct_adapter JCTTransition jct_adapter = destination.GetComponent <JCTTransition> (); // if (jct_adapter == null) { jct_adapter = destination.AddComponent <JCTTransition> (); // added by jesse for a compelte reference to all bones - theoretically since it comes from the figure mesh // jct_adapter.mesh_skeleton = skinned_mesh_renderer.bones; // } jct_adapter.m_morphs = morphs; jct_adapter.hideFlags = HideFlags.HideInInspector; // morpher.m_duplicates = duplicates; jct_adapter.CreationSetup(skinned_mesh_renderer); return; } } //LEGACY (1.0 way) // need root folder string morphFolder = assetPath.Substring(0, assetPath.LastIndexOf("/")) + "/Morphs"; string baseFile = morphFolder + "/" + baseName + ".base.morph"; if (File.Exists(baseFile) == true) { string[] baseNames; Vector3[] baseNodes; Vector3[] baseOffsets; // root bone position data. all bones are stored in absolute format. we need both to put them in relative positioning getJCTDataFromFile(baseFile, out baseNames, out baseNodes, out baseOffsets); int[] nodeMap = calcNodeMap(bones, baseNames); string[] files = Directory.GetFiles(morphFolder, baseName + ".*.morph"); List <JCTMorph> jct_list = new List <JCTMorph> (); foreach (var file in files) { if (File.Exists(file) == true) { string[] morph_names; Vector3[] nodes; Vector3[] offsets; getJCTDataFromFile(file, out morph_names, out nodes, out offsets); // we parse the file name to get the morph name char[] splitter = { '\\', '/' }; string[] parts = file.Split(splitter); string morph_name = parts [parts.Length - 1]; char[] splitter1 = { '.' }; parts = morph_name.Split(splitter1); morph_name = Unescape(parts [1]); JCTMorph morph = new JCTMorph(); morph.m_name = morph_name; morph.m_value = 0; bool hasNodeDelta = false; Vector3[] nodeDeltas = new Vector3[bones.Length]; Vector3[] nodeOffsets = new Vector3[bones.Length]; for (int i = 0; i < bones.Length; i++) { int ii = nodeMap [i]; nodeDeltas [i] = nodes [ii] - baseNodes [ii]; nodeOffsets [i] = offsets [ii] - baseOffsets [ii]; if (nodeDeltas [i].sqrMagnitude > Mathf.Epsilon) { hasNodeDelta = true; } } if (hasNodeDelta) { morph.m_nodes = nodeDeltas; morph.m_offsets = nodeOffsets; jct_list.Add(morph); } } else { Debug.LogWarning("Missing morph file:" + file); } } JCTMorph[] morphs = jct_list.ToArray(); // add the data to the jct_adapter JCTTransition jct_adapter = destination.GetComponent <JCTTransition> (); // if (jct_adapter == null) { jct_adapter = destination.AddComponent <JCTTransition> (); // added by jesse for a compelte reference to all bones - theoretically since it comes from the figure mesh // jct_adapter.mesh_skeleton = skinned_mesh_renderer.bones; // } jct_adapter.m_morphs = morphs; jct_adapter.hideFlags = HideFlags.HideInInspector; // morpher.m_duplicates = duplicates; jct_adapter.CreationSetup(skinned_mesh_renderer); } }