public void OnBeginAnimation() { try { MeshAnimation animation = animations[AnimationIndex]; if (animation.selectedFrames.Count > 0) { frames = new Frame[animation.selectedFrames.Count]; animation.selectedFrames.CopyTo(frames); } else { frames = new Frame[studio.frame.size]; for (int i = 0; i < studio.frame.size; ++i) { float frameRatio = 0.0f; if (i > 0 && i < studio.frame.size) { frameRatio = (float)i / (float)(studio.frame.size - 1); } float time = meshModel.GetTimeForRatio(animation.clip, frameRatio); frames[i] = new Frame(i, time); } } string animationName; if (meshModel.referenceController != null) { animationName = animation.stateName; } else { animationName = animation.clip.name; } fileBaseName = fileNameForModel + "_" + animationName; if (studio.packing.on && studio.output.animatorControllerMake) { BuildAnimatorController(); if (outRootPrefab != null && studio.output.normalMapMake) { animTexData = new AnimationTextureData(animationName); animationTextureDataList.Add(animTexData); } } viewIndex = 0; stateMachine.ChangeState(BakingState.BeginView); } catch (Exception e) { Debug.LogException(e); Finish(); } }
public void Animate(MeshAnimation animation, Frame frame) { if (animation == null || animation.clip == null) { return; } Animator animator = GetComponentInChildren <Animator>(); bool isHumanoid2018 = (animator != null); // for 2018 or newer Vector3 originalPosition = transform.position; Vector3 movedVector = Vector3.zero - originalPosition; if (isHumanoid2018) { transform.position = Vector3.zero; Camera.main.transform.Translate(movedVector); } animation.clip.SampleAnimation(gameObject, frame.time); if (animation.customizer != null) { animation.customizer.UpdateFrame(frame); } if (isHumanoid2018 && currentAngle > float.Epsilon) { Rotate(currentAngle); } if (IsFixingToOrigin()) { float bottomY = 0.0f; if (isFixingToGround) { bottomY = float.MaxValue; Transform[] transforms = rootBoneObj.GetComponentsInChildren <Transform>(); foreach (Transform trsf in transforms) { bottomY = Mathf.Min(trsf.position.y, bottomY); } } Vector3 translation = new Vector3(ComputedBottom.x - rootBoneObj.position.x, ComputedBottom.y - bottomY, ComputedBottom.z - rootBoneObj.position.z); rootBoneObj.Translate(translation, Space.World); } if (isHumanoid2018) { transform.position = originalPosition; Camera.main.transform.Translate(-movedVector); } }
public MeshSampler(Model model, MeshAnimation animation, Studio studio) : base(model, studio) { this.animation = animation; meshModel = model as MeshModel; if (studio.shadow.type == ShadowType.Simple && studio.shadow.simple.isDynamicScale) { modelBaseSize = model.GetSize(); simpleShadowBaseScale = studio.shadow.obj.transform.localScale; } }
public void AddAnimation(MeshAnimation anim) { bool assigned = false; for (int i = 0; i < animations.Count; ++i) { if (animations[i] == null || animations[i].clip == null) { animations[i] = anim; assigned = true; break; } } if (!assigned) { animations.Add(anim); } }
private void OnInspectorGUI_Single() { Undo.RecordObject(model, "Mesh Model"); bool isAnyChanged = false; EditorGUILayout.Space(); EditorGUI.BeginChangeCheck(); model.mainRenderer = EditorGUILayout.ObjectField(new GUIContent("Main Renderer", "the most important and biggest renderer in hierarchy"), model.mainRenderer, typeof(Renderer), true) as Renderer; bool mainRendererChanged = EditorGUI.EndChangeCheck(); if (model.mainRenderer == null) { model.mainRenderer = MeshModel.FindBiggestRenderer(model.gameObject); } if (model.IsSkinnedModel()) { EditorGUILayout.Space(); if (mainRendererChanged) { model.pivotType = PivotType.Bottom; } bool isPivotTypeChanged; model.pivotType = DrawPivotTypeField(model, out isPivotTypeChanged); if (isPivotTypeChanged) { UpdateSceneWindow(); } } else { model.pivotType = PivotType.Center; } if (model.isFixingToOrigin && model.isFixingToGround) { GUI.enabled = false; } { bool isGroundPivotChanged; model.isGroundPivot = DrawGroundPivotField(model, out isGroundPivotChanged); if (isGroundPivotChanged) { UpdateSceneWindow(); } } if (model.isFixingToOrigin && model.isFixingToGround) { GUI.enabled = true; } if (model.IsSkinnedModel()) { EditorGUILayout.Space(); EditorGUI.BeginChangeCheck(); model.rootBoneObj = EditorGUILayout.ObjectField(new GUIContent("Root Bone", "root bone object to fix body"), model.rootBoneObj, typeof(Transform), true) as Transform; if (model.rootBoneObj == null) { GUI.enabled = false; } EditorGUI.indentLevel++; { model.isFixingToOrigin = DrawFixToOriginField(model, out isAnyChanged); if (model.isFixingToOrigin) { EditorGUI.indentLevel++; if (model.isGroundPivot) { GUI.enabled = false; } model.isFixingToGround = DrawFixToGroundField(model, out isAnyChanged); if (model.isGroundPivot) { GUI.enabled = true; } EditorGUI.indentLevel--; } } EditorGUI.indentLevel--; if (model.rootBoneObj == null) { GUI.enabled = true; } if (EditorGUI.EndChangeCheck()) { model.Animate(SelectedAnimation, Frame.BEGIN); } } EditorGUILayout.Space(); if (reservedAnimIndex >= 0) { SetAnimationByIndex(reservedAnimIndex); reservedAnimIndex = -1; } Rect animBoxRect = EditorGUILayout.BeginVertical(); serializedObject.Update(); animReorderableList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); EditorGUILayout.EndVertical(); switch (Event.current.type) { case EventType.DragUpdated: case EventType.DragPerform: { if (!animBoxRect.Contains(Event.current.mousePosition)) { break; } DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (Event.current.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); foreach (object draggedObj in DragAndDrop.objectReferences) { AnimationClip clip = draggedObj as AnimationClip; if (clip != null) { MeshAnimation anim = new MeshAnimation(); anim.clip = clip; anim.selectedFrames = new List <Frame>(); model.AddAnimation(anim); } } } } Event.current.Use(); break; } if (model.animations.Count > 0 && DrawingHelper.DrawMiddleButton("Clear all")) { model.animations.Clear(); } EditorGUILayout.Space(); DrawReferenceControllerField(); if (model.referenceController != null) { EditorGUI.indentLevel++; model.outputController = EditorGUILayout.ObjectField(new GUIContent("Output Controller", "controller to which a baker saves animation states related to the animation list's animations"), model.outputController, typeof(AnimatorController), false) as AnimatorController; EditorGUI.indentLevel--; } EditorGUILayout.Space(); model.spritePrefab = DrawSpritePrefabField(model, out isAnyChanged); if (model.spritePrefab != null) { EditorGUI.indentLevel++; model.prefabBuilder = DrawPrefabBuilderField(model, out isAnyChanged); EditorGUI.indentLevel--; } EditorGUILayout.Space(); if (SelectedAnimation != null) { SelectedAnimation.customizer = EditorGUILayout.ObjectField(new GUIContent("Customizer", "component that customizes this model at every frames in the selected animation"), SelectedAnimation.customizer, typeof(AnimationCustomizer), true) as AnimationCustomizer; } EditorGUILayout.Space(); bool isNameSuffixChanged; model.nameSuffix = DrawModelNameSuffix(model, out isNameSuffixChanged); if (isNameSuffixChanged) { PathHelper.CorrectPathString(ref model.nameSuffix); } EditorGUILayout.Space(); if (DrawingHelper.DrawWideButton("Add to the model list")) { AddToModelList(model); } }
private static void DrawBakingProgress(int editorWidth, int editorHeight, GUIStyle titleStyle, List <Model> bakingModels, Batcher batcher) { const float HELP_BOX_HEIGHT = 54; // help box + two spaces const float TITLE_HEIGHT = 30; // title label + two spaces const float BOTTOM_AREA_HEIGHT = 34; // cancel button + two spaces float maxBodyAreaHeight = editorHeight - HELP_BOX_HEIGHT - TITLE_HEIGHT - BOTTOM_AREA_HEIGHT; float FIELD_HEIGHT = 16; float computedBodyHeight = 0; for (int i = 0; i < bakingModels.Count; ++i) { computedBodyHeight += FIELD_HEIGHT; Model model = bakingModels[i]; if (Model.IsMeshModel(model)) { computedBodyHeight += Model.AsMeshModel(model).GetValidAnimations().Count *FIELD_HEIGHT; } } float bodyAreaHeight = Mathf.Min(computedBodyHeight, maxBodyAreaHeight); Rect titleRect = EditorGUILayout.BeginVertical(); EditorGUILayout.LabelField(string.Format("Baking.. ({0}/{1})", batcher.ModelIndex, bakingModels.Count), titleStyle, GUILayout.Height(TITLE_HEIGHT + bodyAreaHeight)); EditorGUILayout.EndVertical(); float bodyY = titleRect.y + TITLE_HEIGHT; int firstModelIndex = 0; if (computedBodyHeight > maxBodyAreaHeight) { float simulatedBodyHeight = 0; for (int i = 0; i < bakingModels.Count; ++i) { float totalModelHeight = FIELD_HEIGHT; Model model = bakingModels[i]; if (Model.IsMeshModel(model)) { totalModelHeight += Model.AsMeshModel(model).GetValidAnimations().Count *FIELD_HEIGHT; } float thresholdHeight = totalModelHeight + FIELD_HEIGHT * 2; // extra two for baking one & post ellipsis; if (simulatedBodyHeight + thresholdHeight < maxBodyAreaHeight) { simulatedBodyHeight += totalModelHeight; } else { if (i > batcher.ModelIndex) { break; } firstModelIndex++; if (firstModelIndex == 1) { simulatedBodyHeight += FIELD_HEIGHT; // for pre ellipsis } } } } Debug.Assert(firstModelIndex < bakingModels.Count); GUIStyle labelStyle = new GUIStyle(); labelStyle.normal.textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black; { // progress bar int totalTargetCount = 0; int ongoingTargetCount = 0; for (int i = 0; i < bakingModels.Count; ++i) { Model model = bakingModels[i]; if (Model.IsMeshModel(model)) { int validAnimationCount = Model.AsMeshModel(model).GetValidAnimations().Count; if (validAnimationCount > 0) { totalTargetCount += validAnimationCount; if (i < batcher.ModelIndex) { ongoingTargetCount += validAnimationCount; } else if (i == batcher.ModelIndex) { MeshBaker animationBaker = batcher.CurrentBaker as MeshBaker; if (animationBaker != null) { ongoingTargetCount += animationBaker.AnimationIndex; } } } else { totalTargetCount++; if (i <= batcher.ModelIndex) { ongoingTargetCount++; } } } else { totalTargetCount++; if (i <= batcher.ModelIndex) { ongoingTargetCount++; } } } float progress = (float)ongoingTargetCount / (float)totalTargetCount; const float PROGRESS_BAR_WIDTH = 10; Rect progressBarBgRect = new Rect(editorWidth, bodyY, PROGRESS_BAR_WIDTH, bodyAreaHeight); DrawingHelper.FillRect(progressBarBgRect, EditorGUIUtility.isProSkin ? lightGrayColor : darkGrayColor); Rect progressBarFgRect = new Rect(editorWidth, bodyY, PROGRESS_BAR_WIDTH, bodyAreaHeight * progress); DrawingHelper.FillRect(progressBarFgRect, EditorGUIUtility.isProSkin ? Color.white : Color.black); labelStyle.alignment = TextAnchor.MiddleRight; float progressLabelY = bodyY + bodyAreaHeight * progress - (FIELD_HEIGHT / 2); Rect progressLabelRect = new Rect(14, progressLabelY, editorWidth - 17, FIELD_HEIGHT); EditorGUI.LabelField(progressLabelRect, string.Format("{0:0}%", progress * 100), labelStyle); } labelStyle.alignment = TextAnchor.MiddleLeft; float FIELD_X = 14; float bodyHeight = 0; if (firstModelIndex > 0) { Rect ellipsisRect = new Rect(FIELD_X, bodyY + bodyHeight, editorWidth, FIELD_HEIGHT); EditorGUI.indentLevel++; EditorGUI.indentLevel++; EditorGUI.LabelField(ellipsisRect, "...", labelStyle); EditorGUI.indentLevel--; EditorGUI.indentLevel--; bodyHeight += FIELD_HEIGHT; } for (int mi = firstModelIndex; mi < bakingModels.Count; ++mi) { if (bodyHeight + FIELD_HEIGHT > maxBodyAreaHeight) { return; } Model model = bakingModels[mi]; Rect modelRect = new Rect(FIELD_X, bodyY + bodyHeight, editorWidth, FIELD_HEIGHT); bodyHeight += FIELD_HEIGHT; FieldState state = FieldState.None; if (mi < batcher.ModelIndex) { state = FieldState.Completed; } else if (mi == batcher.ModelIndex) { state = FieldState.Baking; } bool elliptical = false; if (bodyHeight + FIELD_HEIGHT > maxBodyAreaHeight) { if (mi < bakingModels.Count - 1) { elliptical = true; } } string labelText; if (elliptical) { labelText = "..."; } else { labelText = mi.ToString() + ". " + model.name; if (model.nameSuffix.Length > 0) { labelText += model.nameSuffix; } } labelStyle.fontStyle = GetLabelFontStyle(state); EditorGUI.indentLevel++; EditorGUI.LabelField(modelRect, labelText, labelStyle); EditorGUI.indentLevel--; if (state == FieldState.Completed && !elliptical) { DrawCheckMark(modelRect); } if (Model.IsMeshModel(model)) { MeshModel meshModel = Model.AsMeshModel(model); List <MeshAnimation> validAnimations = meshModel.GetValidAnimations(); for (int ai = 0; ai < validAnimations.Count; ++ai) { if (bodyHeight + FIELD_HEIGHT > maxBodyAreaHeight) { return; } MeshAnimation anim = validAnimations[ai]; MeshBaker animationBaker = batcher.CurrentBaker as MeshBaker; Rect animationRect = new Rect(FIELD_X, bodyY + bodyHeight, editorWidth, FIELD_HEIGHT); bodyHeight += FIELD_HEIGHT; state = FieldState.None; if (mi < batcher.ModelIndex || (mi == batcher.ModelIndex && (animationBaker != null && ai < animationBaker.AnimationIndex))) { state = FieldState.Completed; } else if (mi == batcher.ModelIndex && (animationBaker != null && ai == animationBaker.AnimationIndex)) { state = FieldState.Baking; } elliptical = false; if (bodyHeight + FIELD_HEIGHT > maxBodyAreaHeight) { if (mi < bakingModels.Count - 1 || ai < validAnimations.Count - 1) { elliptical = true; } } if (elliptical) { labelText = "..."; } else { labelText = (meshModel.referenceController != null) ? anim.stateName : anim.clip.name; } labelStyle.fontStyle = GetLabelFontStyle(state); EditorGUI.indentLevel++; EditorGUI.indentLevel++; EditorGUI.LabelField(animationRect, labelText, labelStyle); EditorGUI.indentLevel--; EditorGUI.indentLevel--; if (state == FieldState.Completed && !elliptical) { DrawCheckMark(animationRect, 10); } } } } }
private void BuildAnimatorController() { if (meshModel.referenceController == null) { return; } animatorStates = null; MeshAnimation animation = animations[AnimationIndex]; if (meshModel.outputController == null) { string filePath = Path.Combine(folderPath, fileNameForModel + ".controller"); meshModel.outputController = AnimatorController.CreateAnimatorControllerAtPath(filePath); } AnimatorStateMachine outStateMachine = meshModel.outputController.layers[0].stateMachine; AddParameterIfNotExist(meshModel.outputController, ANGLE_PARAM_NAME, AnimatorControllerParameterType.Int); foreach (AnimatorControllerParameter refParam in meshModel.referenceController.parameters) { AddParameterIfNotExist(meshModel.outputController, refParam.name, refParam.type); } AnimatorStateMachine refStateMachine = meshModel.referenceController.layers[0].stateMachine; AnimatorState refMainAnimState = FindState(refStateMachine, animation.stateName); Debug.Assert(refMainAnimState != null); animatorStates = new List <AnimatorState>(); foreach (SubView subView in studio.view.checkedSubViews) { AnimatorStateMachine outSubStateMachine = GetOrCreateStateMachine(outStateMachine, subView.name, subView.angle); AnimatorState outStateForView = GetOrCreateState(outSubStateMachine, animation.stateName); CopyState(refMainAnimState, outStateForView); animatorStates.Add(outStateForView); } Debug.Assert(studio.view.checkedSubViews.Count == animatorStates.Count); bool hasAnyStateTransition = false; foreach (SubView subView in studio.view.checkedSubViews) { AnimatorStateMachine outViewStateMachine = FindStateMachine(outStateMachine, subView.name); Debug.Assert(outViewStateMachine != null); AnimatorState outMainAnimViewState = FindState(outViewStateMachine, animation.stateName); Debug.Assert(outMainAnimViewState != null); foreach (AnimatorTransition refEntryTransition in refStateMachine.entryTransitions) { AnimatorState outDestState = FindState(outViewStateMachine, refEntryTransition.destinationState.name); if (outDestState != null) { CopyOrCreateEntryTransition(outViewStateMachine, refEntryTransition, outDestState); } } foreach (AnimatorStateTransition refAnyStateTransition in refStateMachine.anyStateTransitions) { AnimatorState outDestState = FindState(outViewStateMachine, refAnyStateTransition.destinationState.name); if (outDestState != null) { CopyOrCreateAnyStateTransition(outStateMachine, refAnyStateTransition, outDestState, subView.angle); if (refAnyStateTransition.destinationState.name == animation.stateName) { hasAnyStateTransition = true; } } } foreach (ChildAnimatorState refChildState in refStateMachine.states) { foreach (AnimatorStateTransition refTransition in refChildState.state.transitions) { AnimatorState outStartState = FindState(outViewStateMachine, refChildState.state.name); if (outStartState == null) { continue; } if (refTransition.isExit) { CopyOrCreateExitTransition(refTransition, outStartState); } else { AnimatorState outDestState = FindState(outViewStateMachine, refTransition.destinationState.name); if (outDestState != null) { CopyOrCreateTransition(refTransition, outStartState, outDestState); foreach (AnimatorStateTransition refReverseTransition in refTransition.destinationState.transitions) { if (refReverseTransition.destinationState == refMainAnimState) { CopyOrCreateTransition(refReverseTransition, outDestState, outStartState); } } } } } } } if (!hasAnyStateTransition) { for (int ai = 0; ai < animatorStates.Count; ++ai) { for (int bi = 0; bi < animatorStates.Count; ++bi) { if (ai == bi) { continue; } AddDirectionTransitionA2BIfNotExist(animatorStates[ai], animatorStates[bi], studio.view.checkedSubViews[bi].angle); } } } }
public void OnEndView() { try { if (!studio.packing.on && studio.trimming.isUnifiedForAllViews) { TrimToUnifiedSize(framePivots, frameModelTextures, frameNormalMapTextures); BakeIndividually(framePivots, viewName, frameModelTextures, frameNormalMapTextures); } else if (studio.packing.on) { if (studio.trimming.isUnifiedForAllViews) { TrimToUnifiedSize(framePivots, frameModelTextures, frameNormalMapTextures); if (frameCompactBounds != null) { for (int i = 0; i < frameModelTextures.Length; ++i) { CalcCompactVector(frameModelTextures[i], unifiedTexBound); } } if (locationMappings != null) { foreach (LocationMapping mapping in locationMappings) { for (int i = 0; i < frameModelTextures.Length; ++i) { mapping.frameLocationPositions[i].SubtractWithMargin(unifiedTexBound.min, studio.trimming.margin); } } } } Sprite[] sprites = BakeWithPacking(framePivots, viewName, frameModelTextures, frameNormalMapTextures); if (locationMappings != null) { foreach (LocationMapping mapping in locationMappings) { Debug.Assert(frameModelTextures.Length == mapping.frameLocationPositions.Length); for (int i = 0; i < frameModelTextures.Length; ++i) { Texture2D tex = frameModelTextures[i]; float locRatioX = (float)mapping.frameLocationPositions[i].x / (float)tex.width; float locRatioY = (float)mapping.frameLocationPositions[i].y / (float)tex.height; float pivotRatioX = (float)framePivots[i].x / (float)tex.width; float pivotRatioY = (float)framePivots[i].y / (float)tex.height; mapping.frameRatioPositions[i] = new Vector2(locRatioX - pivotRatioX, locRatioY - pivotRatioY); } } } if (studio.output.animationClipMake) { MeshAnimation animation = animations[AnimationIndex]; AnimationClip animClip = MakeAnimationClipsForView(animation.isLooping, sprites, viewName); if (animClip != null && outRootPrefab != null) { BoxCollider2D collider = model.prefabBuilder.GetBoxCollider2D(outRootPrefab); if (collider != null) { AddBoxColliderCurve(animClip, collider, sprites); } if (locationMappings != null) { AddLocationPositionCurve(animClip, sprites); } if (studio.output.animatorControllerMake && studio.output.normalMapMake) { dirTexData = new DirectionTextureData(studio.view.checkedSubViews[viewIndex].angle, modelAtlasTexture, normalMapAtlasTexture); animTexData.directionTextureDataList.Add(dirTexData); } } } } viewIndex++; if (viewIndex < studio.view.checkedSubViews.Count) { stateMachine.ChangeState(BakingState.BeginView); } else { stateMachine.ChangeState(BakingState.EndAnimation); } } catch (Exception e) { Debug.LogException(e); Finish(); } }