关于表情动态

最終更新: 2022年10月6日

什么是表情动态?

表情动态与通常的动态不同,是一项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);

动态、表情和其他参数操作元素的计算顺序极大地影响表达。

“关于参数 – 参数计算顺序的重要性”

请充分注意应用顺序。

关于本报道,敬请提出您的意见及要求。