VRM의 아바타 표정을 애니메이션으로 관리

하고 싶었던 일



연구 목적으로 여러 대량의 아바타에 적용되는 애니메이션을 만들어야했습니다. 목에서 아래는 HumanoidBorn에서 보통으로 조작할 수 있었습니다만, FBX(라고 하는지 기존의 인형 아바타)라고 표정의 설정이 지나치게 곤란.
그래서 모처럼이므로 최근 할 수 있던 VRM 포맷으로 표정 제어를 하려고 결의(Blender라든지 사용할 수 있으면 간단하겠지만 좌절)

전제



Animation,Animator는 최소한 사용할 수 있습니다

환경 구축 및 설정 변경



Dowango의 공식 페이지을 참조하여 Unity에 VRM을로드하는 환경 구축
사용하는 모델은 AliciaSolidUnity 짱
드래그 앤 드롭만으로 정상적으로 사용할 수 있었으므로 편리

목에서 아래는 이미 만들어져 있던 「앉아 팔을 짜고 있다」애니메이션을 적용.

Scene에 배치하고 우선 재생 버튼을 누르면 왠지 얼굴이 사라져 가볍게 공포


얼굴의 파트가 얼굴에 추종하지 않는 부모와 자식 구조가 되어 있었지만, 구조 파괴하면 어떻게 될지 몰랐기 때문에, 일단 MeshRenderer의 위치를 ​​낮추어 대응한다.


VRMBlendShapeProxy 터치



UniVRM의 VRMBlendShapeProxy로 표정 애니메이션 처리를 공통화
↑를 읽으면서,VRMBlendShapeProxy를 접하면 좋을까 이해.
그러나 Editor에서 Start가 시작되지 않으면 VRMBlendShapeProxy의 값을 변경할 수 없습니다. Animation에서 사용할 수 없습니다.


그래서 이 값을 Update 후에 어떻게 하는 스크립트를 쓰고, 그 변수를 변경하는 Animation을 설정하기로 했다.

VRMShapesControl.cs
public class VRMShapesControl : MonoBehaviour
{

    private VRMBlendShapeProxy _proxy;

    [Range(0, 1)]
    public float A;

    [Range(0, 1)]
    public float I;

    [Range(0, 1)]
    public float U;

    [Range(0, 1)]
    public float E;

    [Range(0, 1)]
    public float O;

    [Range(0, 1)]
    public float Blink;

    [Range(0, 1)]
    public float Joy;

    [Range(0, 1)]
    public float Angry;

    [Range(0, 1)]
    public float Sorrow;

    [Range(0, 1)]
    public float Fun;

    [Range(0, 1)]
    public float LookUp;

    [Range(0, 1)]
    public float LookDown;

    [Range(0, 1)]
    public float LookLeft;

    [Range(0, 1)]
    public float LookRight;

    [Range(0, 1)]
    public float Blink_L;

    [Range(0, 1)]
    public float Blink_R;


    // Update is called once per frame
    void Update()
    {
        if (_proxy == null)
        {
            _proxy = GetComponent<VRMBlendShapeProxy>();
        }
        else
        {
            foreach (BlendShapePreset t in Enum.GetValues(typeof(BlendShapePreset)))
            {
                _proxy.SetValue(t, GetPropertyValue(t));
            }
        }
    }

    private float GetPropertyValue(BlendShapePreset t)
    {
        switch (t)
        {
            default:
                return 0;
            case BlendShapePreset.A:
                return A;
            case BlendShapePreset.Angry:
                return Angry;
            case BlendShapePreset.Blink:
                return Blink;
            case BlendShapePreset.Blink_L:
                return Blink_L;
            case BlendShapePreset.Blink_R:
                return Blink_R;
            case BlendShapePreset.E:
                return E;
            case BlendShapePreset.Fun:
                return Fun;
            case BlendShapePreset.I:
                return I;
            case BlendShapePreset.Joy:
                return Joy;
            case BlendShapePreset.LookDown:
                return LookDown;
            case BlendShapePreset.LookLeft:
                return LookLeft;
            case BlendShapePreset.LookRight:
                return LookRight;
            case BlendShapePreset.LookUp:
                return LookUp;
            case BlendShapePreset.O:
                return O;
            case BlendShapePreset.Sorrow:
                return Sorrow;
            case BlendShapePreset.U:
                return U;
        }
    }
}

본래는 GetPropertyValue의 내용을 「변수명(string)으로부터 값을 취득」이라고 하고 싶었지만, Enum으로부터의 변환이라든지 잘 되지 않는 것 같기 때문에 우선 원시적으로 구현.
이 스크립트를 VRMBlendShapeProxy와 같은 GameObject에 추가.
BlendShapePreset은 확실히 스스로 변경할 수 있었을 것이므로, 그 때마다 여기를 변경하지 않으면 안되는 것은 난점.

우선 깜박임을 하고 싶었기 때문에, Blink(눈꺼풀을 닫는다)의 값을 접한다(0으로 열다, 1로 닫는다). 10초에 1회 0.5초 걸어 눈꺼풀을 닫는 설정.


그리고 재생

성공

같은 것이 Unity에서도 만들어졌기 때문에 목표 달성


어려움



항목이 늘어날 때마다 GetPropertyValue를 바꿔야 한다.
게임의 재생중이 아니면 어떻게 움직일지 모르기 때문에 값의 조정이 하기 어렵기 때문에, 모션을 만들고 있는 동안은 항상 재생중으로 해 둘 필요가 있다.

VRM



VR게임계의 이용이라고 하는 것으로, 아무래도 아바타의 종류가 애니메이션보다에 치우쳐 있는 것이 유감. RobotKyle같은 학회 발표중에 낯설지 않아도 되는 느낌도 갖고 싶다…뭐 스스로 만들면 좋겠지만…

좋은 웹페이지 즐겨찾기