표정 모션에 대해서

업데이트: 2022/10/06

표정 모션이란?

표정 모션은 일반 모션과는 별도로 표정용 값을 현재 상태에 상대적으로 설정하는 SDK의 기능입니다.
모션 매니저의 페이드 기능을 이용하여 현재의 표정으로부터 재생된 새로운 표정의 설정으로 시간을 들여 변화시킬 수 있습니다.
또한 모션에는 없는 기능으로 계산 방법을 지정할 수 있다는 점이 있습니다.

ACubismMotion 클래스를 상속하므로 일반 모션과 마찬가지로 CubismMotionManager 클래스에서 관리할 수 있습니다.
표정 데이터(.exp3.json 파일)의 작성은 .motion3.json 파일을 Cubism Viewer (for OW)에 표정용 모션으로서 읽어들여, 변환해 출력할 필요가 있습니다.
.motion3.json 파일을 읽었을 때는 모션의 초기 값이 표정의 목표 값으로 설정됩니다.
「애니메이션 뷰로 표정 생성」
「표정 설정과 내보내기」

표정은 모션과 비교하면 다음과 같은 차이가 있습니다.

  • 시간 경과에 따른 값 변화가 없습니다.
  • 파츠에 영향을 줄 수 없습니다.
  • 계산 방법(가산, 곱하기, 덮어쓰기)을 지정할 수 있습니다.

인스턴스 생성(.exp3.json 불러오기)

표정은 ACubismMotion 클래스에서 파생된 CubismExpressionMotion 클래스를 사용하여 재생합니다.
CubismExpressionMotion 인스턴스를 생성하려면, Native(C++)의 CubismExpressionMotion::Create 함수, Web(TypeScript), Java의 CubismExpressionMotion.create 함수를 사용합니다.

// C++
	csmInt32 len = _modelSetting->GetExpressionCount();
    for (csmInt32 i = 0; i < len; ++i)
    {
        csmString name = _modelSetting->GetExpressionName(i);
        csmString path = _modelSetting->GetExpressionFileName(i);
        path = _modelHomeDir + path;

        buffer = CreateBuffer(path.GetRawString(), &size);
        ACubismMotion* motion = CubismExpressionMotion::Create(buffer, size);

        if (_expressions[name] ! = NULL)
        {
            ACubismMotion::Delete(_expressions[name]);
            _expressions[name] = NULL;
        }
        _expressions[name] = motion;

        DeleteBuffer(buffer, path.GetRawString());
    }
// TypeScript
	let len: number = _modelSetting.getExpressionCount();

    for(let i: number = 0; i < len; ++i)
    {
        let name: string = this._modelSetting.getExpressionName(i);
        let path: string = this._modelSetting.getExpressionFileName(i);
        path = this._modelHomeDir + path;

        fetch(path).then(
            (response) => 
            {
                return response.arrayBuffer();
            }
        ).then(
            (arrayBuffer) =>
            {
                let buffer: ArrayBuffer = arrayBuffer;
                let size: number = buffer.byteLength;

                let motion: ACubismMotion = CubismExpressionMotion.create(buffer, size);

                if(this._expressions.getValue(name) ! = null)
                {
                    ACubismMotion.delete(this._expressions.getValue(name));
                    this._expressions.setValue(name, null);
                }

                this._expressions.setValue(name, motion);

                deleteBuffer(buffer, path);
            }
        );
    }
// Java
    final int count = _modelSetting.getExpressionCount();

    for (int i = 0; i < count; i++) {
        String name = _modelSetting.getExpressionName(i);
        String path = _modelSetting.getExpressionFileName(i);
        path = _modelHomeDirectory + path;
      
        byte[] buffer = createBuffer(path);
        CubismExpressionMotion motion = loadExpression(buffer);
      
        if (_expression.get(name) ! = null) {
            _expressions.remove(name);
        }
        _expressions.put(name, motion);
    }

표정 관리용 인스턴스 만들기

표정 적용은 CubismMotionManager 클래스를 사용합니다.
그러나 일반적인 모션과 효과를 함께 사용하려면 별도의 인스턴스로 만들어야 합니다.

// C++
    CubismMotionManager* motionManager = CSM_NEW CubismMotionManager();

    CubismMotionManager* expressionManager = CSM_NEW CubismMotionManager();
// TypeScript
    let motionManager: CubismMotionmanager = new CubismMotionManager();

    let expressionManager: CubismMotionManager = new CubismMotionManager();
// Java
    CubismMotionManager motionManager = new CubismMotionManager();

    CubismMotionManager expressionManager = new CubismMotionManager();

표정의 재생과 그 구조

모션 재생과 마찬가지로, 표정 재생 시에는 관리 클래스에 대해 재생 명령을 내립니다.

// C++
    ACubismMotion* motion = _expressions[expressionID];//loaded CubismExpression
    if (motion ! = NULL)
    {
        expressionManager->StartMotionPriority(motion, false, PriorityForce);
    }
// TypeScript
    let motion: ACubismMotion = _expressions[expressionID];//loaded CubismExpressionMotion
    if(motion ! = null)
    {
        expressionManager.startMotionPriority(motion, false, PriorityForce);
    }
// Java
    ACubismMotion motion = _expressions.get(expressionID); // loaded CubismExpression
    if (motion ! = null){
        expressionManager.startMotionPriority(motion, LAppDefine.Priority.FORCE.getPriority());
    }

표정의 각 파라미터의 지정에는 계산 방법의 지정이 가능합니다.
가산, 곱하기, 덮어쓰기의 세 가지 계산 방법이 있습니다.

가산

계산 방법 지정이 “Add”로 표시되거나 계산 방법 지정이 없는 경우 이 방법이 선택됩니다.
적용 시 파라미터 값에 그대로 .exp3.json 파일에 표시된 값이 가산됩니다.
모션에서는 별로 조작되지 않는 파라미터에 대해서나
그대로 슬라이드시켜 영향을 주고 싶을 때 사용합니다.
Cubism Viewer (for OW)로 값을 내보낼 때 파라미터의 초기 값에서 설정 값까지의 차이가 설정됩니다.

곱하기

계산 방법이 “Multiply”로 표시되면 선택됩니다.
적용 시 파라미터 값에 그대로 .exp3.json 파일에 표시된 값을 곱합니다.
적용 후의 가산, 덮어쓰기에는 이 곱셈이 영향을 주지 않는 점에 주의해 주세요.
모션의 움직임을 그대로 증폭시키거나 축소시킬 때 유용합니다.
Cubism Viewer (for OW)로 값을 내보낼 때 설정값이 그대로 설정됩니다.
-30~30의 모션에 30을 곱하면 -900~900의 모션이 되어 버리므로,
모션과 표정의 값의 조합에 주의하여 설정해 주세요.

덮어쓰기

Cubism Viewer (for OW)에서는 설정할 수 없지만 계산 방법을 “Overwrite”로 지정하면 사용할 수 있게 됩니다.
적용 시의 파라미터의 값을 무시하고 그대로 값을 덮어씁니다.
모션 등의 움직임을 무시하고 싶은 경우에 유효합니다.

연산 방식의 차이에 의한 표현의 차이

두 눈의 개폐를 설정값은 0.4로 하고 각각 Add, Multiply, Overwrite의 표정을 적용한 예입니다.
Add에서는 매 드로잉마다 -0.6 되기 때문에, 바로 개폐 하한에 도달하고 하한값으로 덮어쓰기 되어 잠시 눈이 닫힌 상태가 됩니다.
Multiply에서는 파형 전체에 값이 곱해지기 때문에 눈 깜빡임이 깔끔하게 동작합니다.
Overwrite에서는 눈 깜빡임이 무시되어 깜빡이지 않습니다.

모션 등과 조합했을 때, 표정의 계산 하나로 뉘앙스를 바꿀 수 있습니다.

표정 적용

모델에 대한 적용은 관리 클래스의 Native(C++)의 CubismMotionManager::UpdateMotion 함수 Web(TypeScript), Java의 CubismMotionManager.updateMotion 함수 또는 Native(C++)의 MotionQueueManager::DoUpdateMotion 함수, Web(TypeScript), Java의 CubismMotionQueueManager.doUpdateMotion 함수를 사용합니다.

// C++
	expressionManager->UpdateMotion(_model, deltaTimeSeconds);
// TypeScript
	expressionManager.updateMotion(_model, deltaTimeSeconds);
// Java
    expressionManager.updateMotion(_model, deltaTimeSeconds);

모션이나 표정, 다른 파라미터 조작 요소의 계산 순서는 표현에 큰 영향을 미칩니다.

「파라미터 정보: 파라미터 계산 순서의 중요성」

적용 순서에 충분히 주의하십시오.

이 기사에 관한 의견 및 요청사항을 보내 주시기 바랍니다.