2012년 2월 6일 월요일

유니티에서 topology가 같은 캐릭터간에 애니메이션 공유하기...

이미지 출처: http://answers.unity3d.com/questions/191282/sharing-animations-between-models.html

본(bone)의 길이가 다른 캐릭터들 사이에서 애니메이션을 공유하려고 한다고 생각해 보죠. 물론 각 캐릭터마다 애니메이션을 따로 만들어주면 좋겠지만 인력이 부족한다던가... 그런데 이렇게 본의 길이가 다른 캐릭터터들 사이에서 애니메이션을 공유할 수 있을까요? 뭐 되니까 이글을 쓰는거죠... -_-; 평행이동과 확대/축소를 사용하지 않으면 가능합니다. 달리 말하면 회전만 이용하면 된다는거죠. 이렇게 생각해보면 이해가 쉬워요. 본인의 오른쪽 팔꿈치를 안쪽으로 90도만큼 회전시켜 보세요. 이제 본인보다 키가 작은 친구에게 똑같이 오른쪽 팔꿈치를 90도만큼 회전시키라고 하는거죠. 그러면 둘의 포즈가 똑같죠?  바로 이 원리 입니다. 이해 되죠?

결국 3DS Max가 뱉어내는 데이터가 어쨌던간에 애니메이션에서 회전만 적용시킬 수 있는 방법만 있으면 되는건데... 유니티에서 이런 걸 공식적으로 지원해주는 찾으려고 포럼을 뒤졌지만 그런것 같진 않더군요. 그러면 파이프라인 어딘가에서 회전 이외의 키프레임 정보를 지워버리는 방법이 없을까 찾아봤지요. 불행히도 딱히 대답을 찾을 순 없었습니다. 심지어는 물어보는 사람조차 없더군요. (이 글 쓰고 나서 이 질문을 한 사람을 찾았으나 마땅한 답변이 없더군요. 지금 달린 답변은 제가 이 글 쓰고 난 뒤 단 것 -_-.)

뭐든간에 좋은소식은...... 제가 그 꼼수를 찾아냈다는 거지요. 무핫핫..... :D

이렇게 했답니다. (코드는 조 밑에~)
  1. Asset/Editor 폴더 안에 ConvertToRotationOnlyAnim.cs 라는 스크립트 파일을 만듭니다.
  2. 이 스크립트를 호출하는 메뉴 항목을 만듭니다.
  3. Unity에 애니메이션을 import 해옵니다. (Unity가 애니메이션 파일이라고 생각하는 한 어디서 이 애니메이션을 만들었는지는 상관없습니다.)
  4. import해온 애니메이션 애셋에 마우스 오른쪽 버튼을 누르고, 단계 #2에서 추가했던 메뉴 아이템을 선택합니다.
  5. 이제 스트립트 안에서 propertyName 필드 중에 "m_LocalRotation"이란 이름을 포함한 놈만 복사합니다.
  6. 이제 _rot 애니메이션 클립을 게임오브젝트의 애니메이션 컴포넌트에 대입합니다.
  7. 시작 버튼을 누르고..... 즐거워 해봅시다.. 얼씨구나.. 지화자~ -_-
그리고 이게 위에서 말씀드린 스크립트의 전체 소스코드. 주석을 잘 달아놨으니 영어공부할겸..... 대충 보고 이해하세요. ㄱ ㄱ ㅑ ~ -_-


using UnityEditor;
using UnityEngine;

using System.IO;

public class ConvertToRotationOnlyAnim
{
    [MenuItem("Assets/Convert To Rotation Animation")]
    static void ConvertToRotationAnimation()
    {
        // Get Selected Animation Clip
        AnimationClip sourceClip = Selection.activeObject as AnimationClip;
        if (sourceClip == null)
        {
            Debug.Log("Please select an animation clip");
            return;
        }

        // Rotation only anim clip will have "_rot" post fix at the end
        const string destPostfix = "_rot";

        string sourcePath = AssetDatabase.GetAssetPath(sourceClip);
        string destPath = Path.Combine(Path.GetDirectoryName(sourcePath), sourceClip.name) + destPostfix + ".anim";

        // first try to open existing clip to avoid losing reference to this animation from other meshes that are already using it.
        AnimationClip destClip = AssetDatabase.LoadAssetAtPath(destPath, typeof(AnimationClip)) as AnimationClip;
        if (destClip == null)
        {
            // existing clip not found.  Let's create a new one
            Debug.Log("creating a new rotation only animation at " + destPath);
            
            destClip = new AnimationClip();
            destClip.name = sourceClip.name + destPostfix;

            AssetDatabase.CreateAsset(destClip, destPath);
            AssetDatabase.Refresh();

            // and let's load it back, just to make sure it's created?
            destClip = AssetDatabase.LoadAssetAtPath(destPath, typeof(AnimationClip)) as AnimationClip;
        }

        if (destClip == null)
        {
            Debug.Log("cannot create/open the rotation only anim at " + destPath);
            return;
        }

        // clear all the existing curves from destination.
        destClip.ClearCurves();

        // Now copy only rotation curves
        AnimationClipCurveData[] curveDatas = AnimationUtility.GetAllCurves(sourceClip, true);
        foreach (AnimationClipCurveData curveData in curveDatas)
        {
            if (curveData.propertyName.Contains("m_LocalRotation"))
            {
                AnimationUtility.SetEditorCurve(
                    destClip,
                    curveData.path,
                    curveData.type,
                    curveData.propertyName,
                    curveData.curve
                );
            }
        }

        Debug.Log("Hooray! Coverting to rotation-only anim to " + destClip.name + " is done");
    }
}

댓글 13개:

  1. 유니티가 물건인가 봅니다.

    많이 예기를 하는것 보면요 ^^

    답글삭제
    답글
    1. 저도 요즘들어 장난삼아 좀 주물러보는데(한 1주 되었나?) 잘 만든 물건이에요. 특히 아티스트나 디자이너(기획자) 용으로.. 게임 프로그래머한테도 괜찮은 편이고요.

      뭐 저야 이걸로 게임을 내거나 그럴 일은 없으니(저희는 자체 엔진 개발...) 그냥 공짜버전 가지고 열심히 놀고 있죠.. ㅎㅎ... 그냥 놀다가 뭔가 다른 사람에게 쓸만한게 보이면, 곧바로 이런식으로 글로 남기게요... 아 생각해보니 이거 게임개발포에버에 올려야할까 -_-

      삭제
  2. 유니티 엔진도 오픈소스 엔진 이었나요? 엔진 공부하는데 좋겠네요.

    답글삭제
    답글
    1. 오픈소스는 아니에요... 한해 매출이 $100,000달라가 안되면 그냥 공짜로 쓸 수 있는거죠.. PC용/웹브라우저 용으로 파는건 공짜버전으로도 되요... 안드로이드나 iOS는 각각 $400씩 내야함.

      소스 없이도 왠만한 게임은 만들수 있을정도의 에디터랄까...? 대마왕님 회사도 소스코드는 없다고 합니다. 단 회사 매출이 되니 $1500내고 라이센스를 샀겠지요. 개발자 한명당 $1500.

      그리고 실제 코딩이 필요하면 스크립트로 작성해서 게임오브젝트에 컴포넌트로 붙여버리더군요. 가지고 놀긴 좋아요. 엔진/에디터를 매우 유동적으로 만들어놔서 왠만한건 스크립트를 통해 다 할 수 있고요.

      삭제
  3. 포프님 글 잘보고 있습니다. 쉽게 잘설명하시는거같아 많이 배웁니다.

    답글삭제
    답글
    1. 좋게 봐주시니 고맙습니다... 설명 열심히 하려고 노력중입니다..(덕분에 한국말이 다시 많이 늘었습니다.. ^_^)

      삭제
    2. 시애틀에 거주하고 있습니다. 언젠가 꼭 한번 직접 뵙고 싶네요.

      삭제
    3. 멀지 않은 곳에 계시군요.. (차로 2시간? border에서 지체하는 시간만 없으면?)

      기회가 되면 함 볼 수 있겠군요... 이왕이면 날씨 좋은 날이면 드라이브 하는 기분도 나쁘지 않을테네....

      (이쁜 언니 소개시켜주시면 곧바로 제가 뛰쳐갑니다... 아니면 뛰쳐오세요..... 응? -_-)

      삭제
  4. 그냥 애니메이션을 Duplicate 해서 Position, Scale 키를 다 지워도 되긴 합니다. 다만 이게 노가다라서 위의 방법으로 하면 자동으로 되어서 편하긴 하겠네요~^^

    답글삭제
    답글
    1. 저도 고칠때마다 노가다가 싫어서 만든 스크립트지요 ^_^

      삭제
  5. 질문이 있습니다 ...아시는 부분이시라면 자비를....

    FBX 파일이 asset에 여러개 들어있는데 하나마다 하나씩의 animation이

    포함되어있습니다. 이것을 하나만 생성하고 생성한 하나의 FBX 모델이

    가지고 있는 Animation 컴포넌트에 Addclip을 해서 다른 FBX 모델들이 가

    지고 있는 animation만 따로 스크립트에서 동적으로 할당할 수 있는 방법이 있을까요?

    ㅠ.ㅠ

    답글삭제
    답글
    1. 제가 오랫동안 유니티를 안만져봐서(특히 애니메이션쪽은) 잘 모르겠습니다.. 죄송합니다.. '_'

      삭제
    2. ^^ 아니에요 ~ 답글 달아주신것만해도 감사합니다 !!

      삭제