CubismWebFramework를 직접 이용하는 방법

업데이트: 2020/01/30

Cubism SDK for Web과 함께 제공되는 샘플 프로젝트는 SDK 패키지의 「/Framework」 디렉토리 아래의 처리를 사용하여 Cubism 모델을 취급합니다.
Cubism 모델을 취급하는 프로젝트를 작성하는 경우는 샘플 프로젝트를 기초로 이용할 수 있지만, 기존의 애플리케이션이나 유저의 독자적인 엔진 등에 구현할 때는 CubismWebFramework의 API를 직접 취급하고 싶은 경우가 있습니다.
그러나 포함된 샘플 프로젝트는 고기능이기 때문에, 이를 참고로 하는 것만으로는 구조의 이해와 분리가 어렵습니다.

아래에서는 위와 같은 사용자를 대상으로 CubismFramework를 직접 호출하여 모델을 취급하는 최소 스니펫을 소개합니다.

CubismFramework 사이클

CubismFramework를 다루는 절차는 다음과 같습니다.

  1. CubismFramework 초기화
  2. 모델 파일의 패스 가져오기
  3. 모델 불러오기
  4. 업데이트 처리
  5. 모델 파기
  6. CubismFramework 종료 처리

CubismFramework 초기화

CubismFramework의 초기화 처리는 다음과 같습니다.

CubismFramework는 CubismFramework.startUp()을 사용하여 초기화를 수행합니다.
Cubism SDK for Native에서는 첫 번째 인수에 할당자(ICubismAllocator)를 사용했지만 Cubism SDK for Web에서는 사용하지 않습니다.

    // 로그 등의 옵션 설정.
    _cubismOption: Csm_Option;

    // 메시지 출력 함수.
    public static printMessage(message: string): void

printMessage()의 내용은 샘플 중의 동명 함수를 참고로 구현해 주세요.

import {Live2DCubismFramework as live2dcubismframework, Option as Csm_Option, LogLevel} from "../../../../Framework/live2dcubismframework";
import Csm_CubismFramework = live2dcubismframework.CubismFramework;    
・
・
・
    // 로그 출력 레벨을 설정. LogLevel_Verbose의 경우는 상세 로그를 출력시킨다.
    this._cubismOption.logFunction = printMessage;
    this._cubismOption.loggingLevel = LogLevel.LogLevel_Verbose;
    
    // CubismNativeFramework 초기화에 필요한 파라미터를 설정한다.
    Csm_CubismFramework.startUp(this._cubismOption);
    
    // CubismFramework를 초기화한다.
    Csm_CubismFramework.initialize();
Tips

CubismFramework.initialize()를 호출하는 것은 초기화 시 한 번뿐으로, 그 후에는 CubismFramework.dispose()에 의해 CubismFramework 인스턴스가 파기되지 않는 한 연속으로 호출해도 스킵합니다.
단, 한번 CubismFramework 인스턴스를 파기한 후라면 재차 초기화를 실시하는 경우에는 CubismFramework.initialize()를 호출합니다.

모델 파일 취득

Cubism의 임베디드용 데이터 세트는 .model3.json에 각각의 상대 패스가 기술되어 있으며 이를 참조하여 바이트 데이터를 읽습니다.
.model3.json을 파싱하여 모델 파일 등의 패스를 취득하고 로드하는 것이 좋습니다.

.model3.json의 투시는 CubismFramework의 CubismModelSettingJson 클래스를 사용합니다.

.moc3 파일이나 텍스쳐 등을 직접 지정하여 읽을 수도 있습니다.
직접 지정해 읽어들이는 경우 코드 개수가 필요합니다.

샘플에서는 LAppModel.loadAssets()으로 fetch()를 사용해 리소스 패스로부터 파일을 취득하고 바이트 데이터를 읽어들여 Json의 내용을 취득합니다.

fetch(path).then(
    (response) =>
    {
        return response.arrayBuffer();
    }
).then(
    (arrayBuffer) =>
    {
        let buffer: ArrayBuffer = arrayBuffer;
        let size = buffer.byteLength;
        // Json에 기재된 모델 데이터의 패스 등을 취득
        let setting: ICubismModelSetting = new CubismModelSettingJson(buffer, size);

        // 결과 저장
        this.setupModel(setting);
    }
);

모델 불러오기

모델 로드는 CubismModel 인터페이스에 의해 수행됩니다.

CubismModel의 인스턴스는 CubismNativeFramework에서는 CubismUserModel._model이 보유하고 있어 CubismUserModel.loadModel()을 사용해 모델 데이터를 취득·저장합니다.

CubismModel을 이용하는 경우 CubismUserModel을 상속한 클래스로 취급하는 것을 추천하고 있습니다.
샘플에서 LAppModel 클래스는 CubismUserModel을 상속하고 취급합니다.

또 텍스쳐나 모션, 표정 모션 등의 리소스 관리는 외부에서 실시하는 것도 가능합니다.

샘플에서는 LAppModel.setupModel() 내에서 fetch()를 사용해 ICubismModelSetting에 저장된 파일 패스로부터 모델 데이터를 읽어들이는 처리를 실시했습니다.

// ICubismModelSetting에 저장된 모델 파일 패스를 취득
let path: string = this._modelSetting.getModelFileName();
path = this._modelHomeDir + path;

fetch(path).then(
    (response) =>
    {
        return response.arrayBuffer();
    }
).then(
    (arrayBuffer) =>
    {
        buffer = arrayBuffer;
        // 모델 데이터 로드
        this.loadModel(buffer);
        deleteBuffer(buffer, path);
    }
);
this._state = LoadStep.WaitLoadModel;

로드할 .moc3 파일의 패스는 위와 같이 .model3.json에서 얻을 수 있는데, 마찬가지로 .model3.json에서 표정, 물리 연산, 포즈, 눈 깜빡임, 립싱크, 사용자 데이터, 모션 패스도 얻을 수 있습니다.
SDK의 샘플에서는 모델의 로드와 동시에 이러한 로드도 실시하고 있습니다.
각각의 로드 방법에 대해서는 이하를 참고해 주세요.

Tips

상기의 스니펫은 화면에 모델을 1개 표시하는 것을 전제로 한 것입니다.
화면에 여러 모델을 동시에 표시하려면 표시할 모델과 동일한 수의 CubismUserModel 파생 클래스의 인스턴스를 생성합니다.

업데이트 처리

Cubism 모델의 업데이트 처리는 대상의 모델에 CubismModel 의 인터페이스인 CubismModel.setParameterValueById() 등으로 갱신하는 파라미터와 값을 전달해 설정하고
CubismModel.update()를 호출해 갱신합니다.
CubismModel.update()를 호출하면 Cubism Core로 갱신 처리가 이루어져, 그때까지 설정된 파라미터나 파츠의 값으로부터 정점 정보 등을 갱신합니다.

이 갱신 후의 정점 정보 등을 렌더러에 전달하면 Cubism 모델을 화면에 그릴 수 있습니다.

다음 코드에서는 _model(CubismModel)을 가지는 클래스 내에서 모델의 파라미터 조작을 직접 실행하고 Cubism Core의 갱신 처리를 호출해 조작을 적용하고 있습니다.

public update(): void
{
    // 파라미터 조작.
    // ParamAngleX를 value로 이동
    this._model.setParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), value);

    // 파츠 불투명도 조작.
    // PartArmL 불투명도를 opacity로 설정
    this._model.setPartOpacityById(CubismFramework.getIdManager().getId("PartArmL"), opacity);

    // 모델 업데이트
    this._model.update();
}

업데이트 처리에서는 반드시 CubismModel.update() 이전에 시선 추종이나 물리 연산, 모션 재생 등을 실시합니다.

CubismModel.update()보다 나중에 파라미터의 값을 조작해도 반영되지 않습니다.
그 후에 다시 CubismModel.update()를 호출하면 반영되지만, 이 처리는 부하가 높기 때문에 하나로 정리하는 것을 추천합니다.

    // 정점에 반영됨
    _model.setParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), value1);
    
    // 모델 정점 정보 업데이트
    _model.update();
    
    // 정점에 반영되지 않음
    _model.setParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), value);

모션을 재생하는 CubismMotionManager.updateMotion()은 재생하는 모션에 사용되는 ID의 파라미터값을 모두 덮어쓰기합니다.
그 때문에, 이 처리 이전에 파라미터의 값을 조작해도 모두 CubismMotionManager.updateMotion()에 의해 덮어쓰기되어 버립니다.
시선 추종 등의 값 조작이나 물리 연산 등은 먼저 모션의 재생 처리를 실시한 후에 실시하는 것을 추천합니다.

    // 재생 중인 모션을 모델에 반영
    _motionManager.updateMotion(_model, deltaTimeSeconds);
    
    // 시선 추종 등의 값 조작이나 물리 연산 처리
    
    // 모델 정점 정보 업데이트
    _model.update();

또한 재생하는 모션에 모든 파라미터가 사용되고 있지 않은 경우나 모션의 재생이 정지하고 있는 등의 이유로 파라미터의 값을 조작하지 않는 경우 이전 프레임에서 실시한 값 조작의 결과가 남아 있는 상태가 됩니다.
그러므로 나중에 수행하는 상대적인 파라미터의 값 조작 결과가 의도하지 않은 것이 될 가능성이 있습니다.
이것은 모션을 모델에 반영시키는 처리의 전후에 CubismModel.loadParameter(), CubismModel.saveParameter()를 호출함으로써 그 후에 실시하는 상대적인 값 조작을 리셋할 수 있습니다.

    // 모든 파라미터의 값을 저장 시 상태로 복원
    _modelloadParameters();
    
    // 재생 중인 모션을 모델에 반영
    _motionManager.updateMotion(_model, deltaTimeSeconds);
    
    // 모든 파라미터의 값을 저장
    _model.saveParameters();
    
    
    // 상대적인 값 조작 처리
    
    
    // 모델 정점 정보 업데이트
    _model.update();

시선 추종이나 물리 연산, 모션의 재생 등의 처리 자체에 대해서는 각각의 문서를 참조해 주세요.

이 갱신 후의 정점 정보 등을 렌더러에 전달하면 Cubism 모델을 화면에 그릴 수 있습니다.

모델 파기

모델을 파기하려면 생성된 CubismUserModel 파생 클래스의 인스턴스를 파기합니다.
이렇게 하면 이 모델이 보유하고 있는 모션이나 표정, 물리 연산 등의 정보가 CubismUserModel의 소멸자로부터 파기됩니다.

    // 모델 데이터 파기
    this._model.release();
    this._model = null;

Cubism Framework 종료 처리

CubismFramework가 확보한 공통 부분의 리소스를 해제하려면 CubismFramework.dispose()를 호출합니다.
CubismFramework.dispose()는 CubismFramework.initialize()를 호출하기 전에 호출하지 마십시오.

    // CubismFramework 파기
    CubismFramework.dispose();
Tips

CubismFramework로 초기화된 데이터는 static한 영역에 배치되며 모델 데이터에 의존하지 않습니다.
따라서 여러 모델 사이에서 쓸 수 있으며 모델 전환만이라면 CubismFramework.dispose()를 호출할 필요가 없습니다.

이 기사가 도움이 되었나요?
아니요
이 기사에 관한 의견 및 요청사항을 보내 주시기 바랍니다.