public void Awake(ModelType type, string name) { try { Type = type; Name = name; URL = Live2dPathHelper.GetModelConfigPath(type, name); TextAsset config = ResourcesHelper.GetAsset <TextAsset>(URL); ModelConfig = JsonMapper.ToObject <Live2dModelConfig>(config.text); ModelConfig.AssetPath = Live2dPathHelper.GetAssetPath(type, name); string modelPath = ModelConfig.GetModelPath(); var model3Json = CubismModel3Json.LoadAtPath(modelPath, BuiltinLoadAssetAtPath); Model = model3Json.ToModel(); EntityRef.GameObject = Model.gameObject; EntityRef.Transform = Model.gameObject.transform; EntityRef.GameObject.layer = LayerHelper.LayerNameToLayer("Unit"); GameObjectHelper.Traversal(EntityRef.Transform, (arg) => { arg.gameObject.layer = LayerHelper.LayerNameToLayer("Unit"); }, true); Animations = new Dictionary <string, AnimationClip>(); fadeController = EntityRef.GameObject.AddComponent <CubismFadeController>(); fadeController.CubismFadeMotionList = ScriptableObject.CreateInstance <CubismFadeMotionList>(); fadeController.CubismFadeMotionList.MotionInstanceIds = new int[ModelConfig.Motions.Length]; fadeController.CubismFadeMotionList.CubismFadeMotionObjects = new CubismFadeMotionData[ModelConfig.Motions.Length]; for (int i = 0; i < ModelConfig.Motions.Length; ++i) { string motion = ModelConfig.Motions[i]; string motionPath = ModelConfig.GetMotionPath(motion); var motion3Json = CubismMotion3Json.LoadFrom(ResourcesHelper.GetAsset <TextAsset>(motionPath)); var clip = ResourcesHelper.GetAsset <AnimationClip>(ModelConfig.GetAnimationClipPath(motion)); clip.name = motion; int instanceId = clip.GetInstanceID(); var events = clip.events; for (var j = 0; j < events.Length; ++j) { if (events[j].functionName != "InstanceId") { continue; } instanceId = events[j].intParameter; } fadeController.CubismFadeMotionList.MotionInstanceIds[i] = instanceId; fadeController.CubismFadeMotionList.CubismFadeMotionObjects[i] = CubismFadeMotionData.CreateInstance(motion3Json, clip.name, clip.length); Animations.Add(motion, clip); } motionController = EntityRef.GameObject.AddComponent <CubismMotionController>(); } catch (Exception e) { Log.Error(e); } }
/// <summary> /// Instantiates a <see cref="CubismMoc">model source</see> and a <see cref="CubismModel">model</see>. /// </summary> /// <param name="pickMaterial">The material mapper to use.</param> /// <param name="pickTexture">The texture mapper to use.</param> /// <param name="shouldImportAsOriginalWorkflow">Should import as original workflow.</param> /// <returns>The instantiated <see cref="CubismModel">model</see> on success; <see langword="null"/> otherwise.</returns> public CubismModel ToModel(MaterialPicker pickMaterial, TexturePicker pickTexture, bool shouldImportAsOriginalWorkflow = false) { // Initialize model source and instantiate it. var mocAsBytes = Moc3; if (mocAsBytes == null) { return(null); } var moc = CubismMoc.CreateFrom(mocAsBytes); var model = CubismModel.InstantiateFrom(moc); model.name = Path.GetFileNameWithoutExtension(FileReferences.Moc); #if UNITY_EDITOR // Add parameters and parts inspectors. model.gameObject.AddComponent <CubismParametersInspector>(); model.gameObject.AddComponent <CubismPartsInspector>(); #endif // Create renderers. var rendererController = model.gameObject.AddComponent <CubismRenderController>(); var renderers = rendererController.Renderers; var drawables = model.Drawables; // Initialize materials. for (var i = 0; i < renderers.Length; ++i) { renderers[i].Material = pickMaterial(this, drawables[i]); } // Initialize textures. for (var i = 0; i < renderers.Length; ++i) { renderers[i].MainTexture = pickTexture(this, drawables[i]); } // Initialize groups. var parameters = model.Parameters; for (var i = 0; i < parameters.Length; ++i) { if (IsParameterInGroup(parameters[i], "EyeBlink")) { if (model.gameObject.GetComponent <CubismEyeBlinkController>() == null) { model.gameObject.AddComponent <CubismEyeBlinkController>(); } parameters[i].gameObject.AddComponent <CubismEyeBlinkParameter>(); } // Set up mouth parameters. if (IsParameterInGroup(parameters[i], "LipSync")) { if (model.gameObject.GetComponent <CubismMouthController>() == null) { model.gameObject.AddComponent <CubismMouthController>(); } parameters[i].gameObject.AddComponent <CubismMouthParameter>(); } } // Add mask controller if required. for (var i = 0; i < drawables.Length; ++i) { if (!drawables[i].IsMasked) { continue; } // Add controller exactly once... model.gameObject.AddComponent <CubismMaskController>(); break; } // Add original workflow component if is original workflow. if (shouldImportAsOriginalWorkflow) { // Add cubism update manager. var updateaManager = model.gameObject.GetComponent <CubismUpdateController>(); if (updateaManager == null) { model.gameObject.AddComponent <CubismUpdateController>(); } // Add parameter store. var parameterStore = model.gameObject.GetComponent <CubismParameterStore>(); if (parameterStore == null) { parameterStore = model.gameObject.AddComponent <CubismParameterStore>(); } // Add pose controller. var poseController = model.gameObject.GetComponent <CubismPoseController>(); if (poseController == null) { poseController = model.gameObject.AddComponent <CubismPoseController>(); } poseController.PoseData.Initialize(Pose3Json); #if UNITY_EDITOR // Create pose animation clip var motions = new List <SerializableMotion>(); if (FileReferences.Motions.Idle != null) { motions.AddRange(FileReferences.Motions.Idle); } if (FileReferences.Motions.TapBody != null) { motions.AddRange(FileReferences.Motions.TapBody); } for (var i = 0; i < motions.Count; ++i) { var jsonString = string.IsNullOrEmpty(motions[i].File) ? null : LoadReferencedAsset <string>(motions[i].File); if (jsonString == null) { continue; } var assetsDirectoryPath = Application.dataPath.Replace("Assets", ""); var assetPath = AssetPath.Replace(assetsDirectoryPath, ""); var directoryPath = Path.GetDirectoryName(assetPath) + "/"; var motion3Json = CubismMotion3Json.LoadFrom(jsonString); var animationClipPath = directoryPath + motions[i].File.Replace(".motion3.json", ".anim"); var newAnimationClip = motion3Json.ToAnimationClip(shouldImportAsOriginalWorkflow, false, true, Pose3Json); var oldAnimationClip = AssetDatabase.LoadAssetAtPath <AnimationClip>(animationClipPath); // Create animation clip. if (oldAnimationClip == null) { AssetDatabase.CreateAsset(newAnimationClip, animationClipPath); oldAnimationClip = newAnimationClip; } // Update animation clip. else { EditorUtility.CopySerialized(newAnimationClip, oldAnimationClip); EditorUtility.SetDirty(oldAnimationClip); } var fadeMotionPath = directoryPath + motions[i].File.Replace(".motion3.json", ".fade.asset"); var fadeMotion = AssetDatabase.LoadAssetAtPath <CubismFadeMotionData>(fadeMotionPath); if (fadeMotion == null) { fadeMotion = CubismFadeMotionData.CreateInstance(motion3Json, fadeMotionPath.Replace(directoryPath, ""), newAnimationClip.length, shouldImportAsOriginalWorkflow, true); AssetDatabase.CreateAsset(fadeMotion, fadeMotionPath); EditorUtility.SetDirty(fadeMotion); // Fade用モーションの参照をリストに追加 var directoryName = Path.GetDirectoryName(fadeMotionPath).ToString(); var modelDir = Path.GetDirectoryName(directoryName).ToString(); var modelName = Path.GetFileName(modelDir).ToString(); var fadeMotionListPath = Path.GetDirectoryName(directoryName).ToString() + "/" + modelName + ".fadeMotionList.asset"; var fadeMotions = AssetDatabase.LoadAssetAtPath <CubismFadeMotionList>(fadeMotionListPath); // 参照リスト作成 if (fadeMotions == null) { fadeMotions = ScriptableObject.CreateInstance <CubismFadeMotionList>(); fadeMotions.MotionInstanceIds = new int[0]; fadeMotions.CubismFadeMotionObjects = new CubismFadeMotionData[0]; AssetDatabase.CreateAsset(fadeMotions, fadeMotionListPath); } var instanceId = oldAnimationClip.GetInstanceID(); var motionIndex = Array.IndexOf(fadeMotions.MotionInstanceIds, instanceId); if (motionIndex != -1) { fadeMotions.CubismFadeMotionObjects[motionIndex] = fadeMotion; } else { motionIndex = fadeMotions.MotionInstanceIds.Length; Array.Resize(ref fadeMotions.MotionInstanceIds, motionIndex + 1); fadeMotions.MotionInstanceIds[motionIndex] = instanceId; Array.Resize(ref fadeMotions.CubismFadeMotionObjects, motionIndex + 1); fadeMotions.CubismFadeMotionObjects[motionIndex] = fadeMotion; } EditorUtility.SetDirty(fadeMotions); } for (var curveIndex = 0; curveIndex < motion3Json.Curves.Length; ++curveIndex) { var curve = motion3Json.Curves[curveIndex]; if (curve.Target == "PartOpacity") { if (Pose3Json.FadeInTime == 0.0f) { fadeMotion.ParameterIds[curveIndex] = curve.Id; fadeMotion.ParameterFadeInTimes[curveIndex] = Pose3Json.FadeInTime; fadeMotion.ParameterFadeOutTimes[curveIndex] = (curve.FadeOutTime < 0.0f) ? -1.0f : curve.FadeOutTime; fadeMotion.ParameterCurves[curveIndex] = new AnimationCurve(CubismMotion3Json.ConvertCurveSegmentsToKeyframes(curve.Segments)); } else { var poseFadeInTIme = (Pose3Json.FadeInTime < 0.0f) ? 0.5f : Pose3Json.FadeInTime; fadeMotion.ParameterIds[curveIndex] = curve.Id; fadeMotion.ParameterFadeInTimes[curveIndex] = poseFadeInTIme; fadeMotion.ParameterFadeOutTimes[curveIndex] = (curve.FadeOutTime < 0.0f) ? -1.0f : curve.FadeOutTime; var segments = curve.Segments; var segmentsCount = 2; for (var index = 2; index < curve.Segments.Length; index += 3) { // if current segment type is stepped and // next segment type is stepped or next segment is last segment // then convert segment type to liner. var currentSegmentTypeIsStepped = (curve.Segments[index] == 2); var currentSegmentIsLast = (index == (curve.Segments.Length - 3)); var nextSegmentTypeIsStepped = (currentSegmentIsLast) ? false : (curve.Segments[index + 3] == 2); var nextSegmentIsLast = (currentSegmentIsLast) ? false : ((index + 3) == (curve.Segments.Length - 3)); if (currentSegmentTypeIsStepped && (nextSegmentTypeIsStepped || nextSegmentIsLast)) { Array.Resize(ref segments, segments.Length + 3); segments[segmentsCount + 0] = 0; segments[segmentsCount + 1] = curve.Segments[index + 1]; segments[segmentsCount + 2] = curve.Segments[index - 1]; segments[segmentsCount + 3] = 0; segments[segmentsCount + 4] = curve.Segments[index + 1] + poseFadeInTIme; segments[segmentsCount + 5] = curve.Segments[index + 2]; segmentsCount += 6; } else if (curve.Segments[index] == 1) { segments[segmentsCount + 0] = curve.Segments[index + 0]; segments[segmentsCount + 1] = curve.Segments[index + 1]; segments[segmentsCount + 2] = curve.Segments[index + 2]; segments[segmentsCount + 3] = curve.Segments[index + 3]; segments[segmentsCount + 4] = curve.Segments[index + 4]; segments[segmentsCount + 5] = curve.Segments[index + 5]; segments[segmentsCount + 6] = curve.Segments[index + 6]; index += 4; segmentsCount += 7; } else { segments[segmentsCount + 0] = curve.Segments[index + 0]; segments[segmentsCount + 1] = curve.Segments[index + 1]; segments[segmentsCount + 2] = curve.Segments[index + 2]; segmentsCount += 3; } } fadeMotion.ParameterCurves[curveIndex] = new AnimationCurve(CubismMotion3Json.ConvertCurveSegmentsToKeyframes(segments)); } } } EditorUtility.SetDirty(fadeMotion); } #endif // Add expression controller. var expressionController = model.gameObject.GetComponent <CubismExpressionController>(); if (expressionController == null) { expressionController = model.gameObject.AddComponent <CubismExpressionController>(); } // Add fade controller. var motionFadeController = model.gameObject.GetComponent <CubismFadeController>(); if (motionFadeController == null) { motionFadeController = model.gameObject.AddComponent <CubismFadeController>(); } } // Initialize physics if JSON exists. var physics3JsonAsString = Physics3Json; if (!string.IsNullOrEmpty(physics3JsonAsString)) { var physics3Json = CubismPhysics3Json.LoadFrom(physics3JsonAsString); var physicsController = model.gameObject.GetComponent <CubismPhysicsController>(); if (physicsController == null) { physicsController = model.gameObject.AddComponent <CubismPhysicsController>(); } physicsController.Initialize(physics3Json.ToRig()); } var userData3JsonAsString = UserData3Json; if (!string.IsNullOrEmpty(userData3JsonAsString)) { var userData3Json = CubismUserData3Json.LoadFrom(userData3JsonAsString); var drawableBodies = userData3Json.ToBodyArray(CubismUserDataTargetType.ArtMesh); for (var i = 0; i < drawables.Length; ++i) { var index = GetBodyIndexById(drawableBodies, drawables[i].Id); if (index >= 0) { var tag = drawables[i].gameObject.GetComponent <CubismUserDataTag>(); if (tag == null) { tag = drawables[i].gameObject.AddComponent <CubismUserDataTag>(); } tag.Initialize(drawableBodies[index]); } } } if (model.gameObject.GetComponent <Animator>() == null) { model.gameObject.AddComponent <Animator>(); } // Make sure model is 'fresh' model.ForceUpdateNow(); return(model); }
/// <summary> /// Create pose motions. /// </summary> /// <param name="sender">Event source.</param> /// <param name="model">Imported model.</param> private static void OnModelImport(CubismModel3JsonImporter sender, CubismModel model) { var shouldImportAsOriginalWorkflow = CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow; var pose3Json = sender.Model3Json.Pose3Json; // Fail silently... if (!shouldImportAsOriginalWorkflow || pose3Json == null) { return; } var assetsDirectoryPath = Application.dataPath.Replace("Assets", ""); var assetPath = sender.AssetPath.Replace(assetsDirectoryPath, ""); var fileReferences = sender.Model3Json.FileReferences; // Create pose animation clip var motions = new List <CubismModel3Json.SerializableMotion>(); if (fileReferences.Motions.GroupNames != null) { for (var i = 0; i < fileReferences.Motions.GroupNames.Length; i++) { motions.AddRange(fileReferences.Motions.Motions[i]); } } for (var i = 0; i < motions.Count; ++i) { var motionPath = Path.GetDirectoryName(assetPath) + "/" + motions[i].File; var jsonString = string.IsNullOrEmpty(motionPath) ? null : File.ReadAllText(motionPath); if (jsonString == null) { continue; } var directoryPath = Path.GetDirectoryName(assetPath) + "/"; var motion3Json = CubismMotion3Json.LoadFrom(jsonString); var animationClipPath = directoryPath + motions[i].File.Replace(".motion3.json", ".anim"); var newAnimationClip = motion3Json.ToAnimationClip(shouldImportAsOriginalWorkflow, false, true, pose3Json); var oldAnimationClip = AssetDatabase.LoadAssetAtPath <AnimationClip>(animationClipPath); // Create animation clip. if (oldAnimationClip == null) { AssetDatabase.CreateAsset(newAnimationClip, animationClipPath); oldAnimationClip = newAnimationClip; } // Update animation clip. else { EditorUtility.CopySerialized(newAnimationClip, oldAnimationClip); EditorUtility.SetDirty(oldAnimationClip); newAnimationClip = oldAnimationClip; } // Add animation event { var instanceId = newAnimationClip.GetInstanceID(); var sourceAnimationEvents = AnimationUtility.GetAnimationEvents(newAnimationClip); var index = -1; for (var j = 0; j < sourceAnimationEvents.Length; ++j) { if (sourceAnimationEvents[j].functionName != "InstanceId") { continue; } index = j; break; } if (index == -1) { index = sourceAnimationEvents.Length; Array.Resize(ref sourceAnimationEvents, sourceAnimationEvents.Length + 1); sourceAnimationEvents[sourceAnimationEvents.Length - 1] = new AnimationEvent(); } sourceAnimationEvents[index].time = 0; sourceAnimationEvents[index].functionName = "InstanceId"; sourceAnimationEvents[index].intParameter = instanceId; sourceAnimationEvents[index].messageOptions = SendMessageOptions.DontRequireReceiver; AnimationUtility.SetAnimationEvents(newAnimationClip, sourceAnimationEvents); } // update fade motion data. var fadeMotionPath = directoryPath + motions[i].File.Replace(".motion3.json", ".fade.asset"); var fadeMotion = AssetDatabase.LoadAssetAtPath <CubismFadeMotionData>(fadeMotionPath); if (fadeMotion == null) { fadeMotion = CubismFadeMotionData.CreateInstance(motion3Json, fadeMotionPath.Replace(directoryPath, ""), newAnimationClip.length, shouldImportAsOriginalWorkflow, true); AssetDatabase.CreateAsset(fadeMotion, fadeMotionPath); EditorUtility.SetDirty(fadeMotion); // Fade用モーションの参照をリストに追加 var directoryName = Path.GetDirectoryName(fadeMotionPath).ToString(); var modelDir = Path.GetDirectoryName(directoryName).ToString(); var modelName = Path.GetFileName(modelDir).ToString(); var fadeMotionListPath = Path.GetDirectoryName(directoryName).ToString() + "/" + modelName + ".fadeMotionList.asset"; var fadeMotions = AssetDatabase.LoadAssetAtPath <CubismFadeMotionList>(fadeMotionListPath); // 参照リスト作成 if (fadeMotions == null) { fadeMotions = ScriptableObject.CreateInstance <CubismFadeMotionList>(); fadeMotions.MotionInstanceIds = new int[0]; fadeMotions.CubismFadeMotionObjects = new CubismFadeMotionData[0]; AssetDatabase.CreateAsset(fadeMotions, fadeMotionListPath); } var instanceId = oldAnimationClip.GetInstanceID(); var motionIndex = Array.IndexOf(fadeMotions.MotionInstanceIds, instanceId); if (motionIndex != -1) { fadeMotions.CubismFadeMotionObjects[motionIndex] = fadeMotion; } else { motionIndex = fadeMotions.MotionInstanceIds.Length; Array.Resize(ref fadeMotions.MotionInstanceIds, motionIndex + 1); fadeMotions.MotionInstanceIds[motionIndex] = instanceId; Array.Resize(ref fadeMotions.CubismFadeMotionObjects, motionIndex + 1); fadeMotions.CubismFadeMotionObjects[motionIndex] = fadeMotion; } EditorUtility.SetDirty(fadeMotions); } for (var curveIndex = 0; curveIndex < motion3Json.Curves.Length; ++curveIndex) { var curve = motion3Json.Curves[curveIndex]; if (curve.Target == "PartOpacity") { if (pose3Json.FadeInTime == 0.0f) { fadeMotion.ParameterIds[curveIndex] = curve.Id; fadeMotion.ParameterFadeInTimes[curveIndex] = pose3Json.FadeInTime; fadeMotion.ParameterFadeOutTimes[curveIndex] = (curve.FadeOutTime < 0.0f) ? -1.0f : curve.FadeOutTime; fadeMotion.ParameterCurves[curveIndex] = new AnimationCurve(CubismMotion3Json.ConvertCurveSegmentsToKeyframes(curve.Segments)); } else { fadeMotion.ParameterIds[curveIndex] = curve.Id; fadeMotion.ParameterFadeInTimes[curveIndex] = pose3Json.FadeInTime; fadeMotion.ParameterFadeOutTimes[curveIndex] = (curve.FadeOutTime < 0.0f) ? -1.0f : curve.FadeOutTime; fadeMotion.ParameterCurves[curveIndex] = CubismMotion3Json.ConvertSteppedCurveToLinerCurver(curve, pose3Json.FadeInTime); } } } EditorUtility.SetDirty(fadeMotion); } InitializePosePart(model.Parts, pose3Json.Groups); }