/// <summary> /// <para> /// Loads <see cref="Morph"/>s from a given key. This is done when the rootObject is initially set or when /// this CoreMorphs object is reset. /// </para> /// <para> /// Loading Morphs for CoreMorphs is handled by the <see cref="MCSCharacterManager"/> when it sets the /// <see cref="rootObject"/> for it's CoreMorphs object. Under normal circumstances a 3rd party developer /// would not need to use this method. /// </para> /// </summary> /// <param name="key">Should be the mesh.name, eg: Genesis2Female.Shape_LOD0</param> public void RefreshMorphsFromMeshKey(string key) { MorphManifest manifest = streamingMorphs.GetManifest(key, Application.isPlaying); //purge the old ones morphs.Clear(); morphLookup.Clear(); //dump the old groups morphStateGroups.Clear(); BuildDefaultStateMorphGroups(); foreach (string name in manifest.names) { Morph m = new Morph(name, 0f, false, false); #if !NIKEI_ENABLED if (m.name.ToLower().Contains("nikei")) { //Skip nikei continue; } #endif morphs.Add(m); morphLookup.Add(m.localName, m); //add this morph to the All group morphStateGroups["All"].Add(m); } //by default always sort the root morphs group alphabetically //SortMorphs(morphs); }
/// <summary> /// <para> /// Detatches the given <see cref="Morph"/>s from the current <see cref="rootObject"/> /// and all it's children and sets their values to zero. /// </para> /// <para> /// Note this has to re-create the list on the mesh in unity, this is expensive and should not be done frequently. /// </para> /// </summary> public void DettachMorphs(Morph[] morphs) { if (morphs.Length <= 0) { return; } string[] morphNames = new string[morphs.Length]; for (int i = 0; i < morphs.Length; i++) { Morph m = morphs[i]; morphNames[i] = m.localName; } DettachMorphs(morphNames); }
/// <summary> /// <para> /// Attach multipe <see cref="Morph"/>s into the current <see cref="rootObject"/> and all it's children. This means /// if Hair, Clothing, Etc. are attached they will have the morphs attached as well. /// </para> /// <para> /// Method can be done Async wiht optional CallBack. /// </para> /// </summary> /// <param name="morphs"><see cref="Morph"/>s to be attached. </param> public void AttachMorphs(Morph[] morphs, bool refresh = false, bool async = false, StreamingMorphs.OnPostInjectionMorphs callback = null) { if (morphs.Length <= 0) { return; } string[] morphNames = new string[morphs.Length]; for (int i = 0; i < morphs.Length; i++) { Morph m = morphs[i]; morphNames[i] = m.localName; } AttachMorphs(morphNames, refresh, async, callback); }
/// <summary> /// Dettaches all morphs from the current <see cref="rootObject"/> and sets all values to zero. /// </summary> public void DetachAllMorphs() { streamingMorphs.RemoveAllBlendshapesFromFigure(rootObject); Morph[] morphsAttached = new Morph[morphStateGroups["Attached"].Count]; Array.Copy(morphStateGroups["Attached"].ToArray(), morphsAttached, morphStateGroups["Attached"].Count); morphStateGroups["Attached"].Clear(); for (int i = 0; i < morphsAttached.Length; i++) { morphsAttached[i].attached = false; morphsAttached[i].value = 0; //Debug.Log("Detaching: " + morphsAttached[i].localName); morphStateGroups["Available"].Add(morphsAttached[i]); morphStateGroups["Attached"].Remove(morphsAttached[i]); } }
//regenerate all the fields we couldn't deserialize automatically public void OnAfterDeserialize() { BuildDefaultStateMorphGroups(); //unity doesn't serialize dicts, so this rebuilds our groups for (int i = 0; i < morphs.Count; i++) { Morph m = morphs[i]; morphLookup[m.localName] = m; morphStateGroups["All"].Add(m); if (m.attached) { morphStateGroups["Attached"].Add(m); } else { morphStateGroups["Available"].Add(m); } } }
///// <summary> ///// Renders the Morph Panel ///// </summary> //protected void HandleMorphsPane() //{ // List<MCS.FOUNDATIONS.Morph> dirtyMorphValues = new List<MCS.FOUNDATIONS.Morph>(); // List<MCS.FOUNDATIONS.Morph> dirtyMorphAttachments = new List<MCS.FOUNDATIONS.Morph>(); // List<MCS.FOUNDATIONS.Morph> dirtyMorphDettachments = new List<MCS.FOUNDATIONS.Morph>(); // for (int i = 0; i < charMan.coreMorphs.morphs.Count; i++) // { // if (selectedBlendShape != "" && // charMan.coreMorphs.morphs[i].displayName.IndexOf(selectedBlendShape, StringComparison.OrdinalIgnoreCase) < 0) // { // continue; // } // MCS.FOUNDATIONS.Morph morph = charMan.coreMorphs.morphs[i]; // EditorMorphState ems = HandleEditorMorphState(morph); // if (ems.dirty) // { // //we need to update this morph // if (ems.dirtyAttached) // { // if (ems.attached) // { // morph.attached = true; // dirtyMorphAttachments.Add(morph); // } // else // { // morph.attached = false; // dirtyMorphDettachments.Add(morph); // } // } // if (ems.dirtyValue) // { // morph.value = ems.value; // if(!morph.attached && ems.value > 0f) // { // //if it wasn't attached and the slider is not 0 attach it // morph.attached = true; // dirtyMorphAttachments.Add(morph); // } // dirtyMorphValues.Add(morph); // } // //replace the object with our modified one, why doesn't c# support references for local vars.... this is stupid // charMan.coreMorphs.morphs[i] = morph; // //Debug.Log("Morph: " + morph.name + " | " + morph.value + " | " + data.coreMorphs.morphs[i].value + " | " + (ems.dirtyValue ? " DIRTY VALUE " : "") + (ems.dirtyAttached ? " DIRTY ATTACH " : "") ); // } // } // if (dirtyMorphDettachments.Count > 0 || dirtyMorphAttachments.Count > 0 || dirtyMorphValues.Count > 0) // { // charMan.coreMorphs.DettachMorphs(dirtyMorphDettachments.ToArray()); // charMan.coreMorphs.AttachMorphs(dirtyMorphAttachments.ToArray()); // charMan.coreMorphs.SyncMorphValues(dirtyMorphValues.ToArray()); // charMan.SyncAllBlendShapes(); // } //} protected EditorMorphState HandleEditorMorphState(MCS.FOUNDATIONS.Morph morph) { EditorMorphState ems = new EditorMorphState(); ems.dirty = false; GUILayoutOption[] optionsLabel = new GUILayoutOption[] { GUILayout.MaxWidth(200.0f), GUILayout.MinWidth(25.0f), GUILayout.ExpandWidth(false) }; GUILayoutOption[] optionsSlider = new GUILayoutOption[] { GUILayout.ExpandWidth(true) }; GUILayoutOption[] optionsKey = new GUILayoutOption[] { GUILayout.MaxWidth(200.0f), GUILayout.MinWidth(0.0f), GUILayout.Height(EditorGUIUtility.singleLineHeight) }; GUILayoutOption[] optionsToggle = new GUILayoutOption[] { GUILayout.Width(40f), GUILayout.ExpandWidth(false) }; EditorGUILayout.BeginHorizontal(); //Show the slider between 0% and 100% for the morph EditorGUILayout.LabelField(morph.displayName, optionsLabel); ems.value = EditorGUILayout.Slider(morph.value, 0f, 100f, optionsSlider); //Show the checkbox for if this morph should be installed to the figure/mesh ems.attached = EditorGUILayout.Toggle(morph.attached, optionsToggle); //most efficient way, but not necessarily the most accurate way //ems.attached = EditorGUILayout.Toggle(charMan.coreMorphs.morphGroups["Attached"].Contains(morph)); //most accurate way but not O(1); //has a property changed? if (ems.attached != morph.attached) { ems.dirtyAttached = true; ems.dirty = true; } if (Mathf.Abs(ems.value - morph.value) > 0.001f) { ems.dirtyValue = true; ems.dirty = true; } EditorGUILayout.SelectableLabel(morph.localName, EditorStyles.textField, optionsKey); EditorGUILayout.EndHorizontal(); return(ems); }
protected void EditorMorphs(List <MCS.FOUNDATIONS.Morph> morphs, List <MCS.FOUNDATIONS.Morph> dirtyMorphValues, List <MCS.FOUNDATIONS.Morph> dirtyMorphAttachments, List <MCS.FOUNDATIONS.Morph> dirtyMorphDettachments) { string searchKey = null; if (!String.IsNullOrEmpty(selectedBlendShape)) { searchKey = selectedBlendShape.ToLower(); } for (int i = 0; i < morphs.Count; i++) { MCS.FOUNDATIONS.Morph morph = morphs[i]; if (!String.IsNullOrEmpty(selectedBlendShape)) { if (!morph.name.ToLower().Contains(searchKey) && !morph.displayName.ToLower().Contains(searchKey) && !morph.localName.ToLower().Contains(searchKey)) { continue; } } EditorMorphState ems = HandleEditorMorphState(morph); if (ems.dirty) { //we need to update this morph if (ems.dirtyAttached) { if (ems.attached) { morph.attached = true; dirtyMorphAttachments.Add(morph); } else { morph.attached = false; dirtyMorphDettachments.Add(morph); } } if (ems.dirtyValue) { morph.value = ems.value; if (!morph.attached && ems.value > 0f) { //if it wasn't attached and the slider is not 0 attach it morph.attached = true; dirtyMorphAttachments.Add(morph); } dirtyMorphValues.Add(morph); } //replace the object with our modified one, why doesn't c# support references for local vars.... this is stupid morphs[i] = morph; //Debug.Log("Morph: " + morph.name + " | " + morph.value + " | " + data.coreMorphs.morphs[i].value + " | " + (ems.dirtyValue ? " DIRTY VALUE " : "") + (ems.dirtyAttached ? " DIRTY ATTACH " : "") ); } } }