参数操作

最終更新: 2022年12月8日

CubismIdHandle

为了通过Cubism最终识别参数,需要得到一个参数列表的Index。
用通过ID识别时,将对参数字符串的ID进行核对。
在Native和Web的Framework中,我们准备了一个名为CubismIdHandle的类型来降低匹配的计算成本。

由于无法在Java中定义新类型,我们采用了另一种方法。

Native

CubismIdHandle类型的实际状态是CubismId类的指针类型,可以通过管理类的函数CubismIdManager::GetId函数获取。
若CubismIdManager::GetId函数是相同的字符串,则返回相同的指针,
因此,如果CubismIdHandle相互比较,并且指针地址相同,则可以保证它们是相同的字符串。

您可以使用static的CubismFramework::GetIdManager函数访问CubismIdManager副本。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
CubismIdHandle idA = CubismFramework::GetIdManager()->GetId("ParamAngleX")
CubismIdHandle idB = CubismFramework::GetIdManager()->GetId("ParamAngleX")
CubismIdHandle idC = CubismFramework::GetIdManager()->GetId("ParamAngleY")
csmBool ab = (idA == idB); //true
csmBool bc = (idB == idC); //false
// C++ CubismIdHandle idA = CubismFramework::GetIdManager()->GetId("ParamAngleX") CubismIdHandle idB = CubismFramework::GetIdManager()->GetId("ParamAngleX") CubismIdHandle idC = CubismFramework::GetIdManager()->GetId("ParamAngleY") csmBool ab = (idA == idB); //true csmBool bc = (idB == idC); //false
// C++
CubismIdHandle idA = CubismFramework::GetIdManager()->GetId("ParamAngleX")

CubismIdHandle idB = CubismFramework::GetIdManager()->GetId("ParamAngleX")

CubismIdHandle idC = CubismFramework::GetIdManager()->GetId("ParamAngleY")

csmBool ab = (idA == idB); //true
csmBool bc = (idB == idC); //false

值操作函数有两种方法:通过Index访问和通过CubismIdHandle访问。

Web

CubismIdHandle类型的实际状态是CubismId类的物体类型,可以通过管理类的函数CubismIdManager.getId函数获取。
若CubismIdManager.getId函数是相同的字符串,则返回相同的副本,
因此,如果CubismIdHandles相互比较,并且物体相同,则可以保证它们是相同的字符串。

您可以使用static的CubismFramework.getIdManager函数访问CubismIdManager副本。

值操作函数有两种方法:通过Index访问和通过CubismIdHandle访问。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
let idA: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleX");
let idB: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleX");
let idC: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleY");
let ab = idA.isEqual(idB); //true
let bc = idB.isEqual(idC); //false
// TypeScript let idA: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleX"); let idB: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleX"); let idC: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleY"); let ab = idA.isEqual(idB); //true let bc = idB.isEqual(idC); //false
// TypeScript
let idA: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleX");

let idB: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleX");

let idC: CubismIdHandle = CubismFramework.getIdManager().getId("ParamAngleY");

let ab = idA.isEqual(idB); //true
let bc = idB.isEqual(idC); //false

Java

与上述两种不同的是,SDK for Java无法定义类型,因此不存在CubismIdHandle类型。
管理类的CubismIdManager.getId函数返回CubismId类型。

CubismId覆盖了equals函数,因此如果将CubismId与equals函数进行比较,可以保证它们是同一个字符串。

您可以使用static的CubismFramework.getIdManager函数访问CubismIdManager副本。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
CubismId idA = CubismFramework.getIdManager().getId("ParamAngleX");
CubismId idB = CubismFramework.getIdManager().getId("ParamAngleX");
CubismId idC = CubismFramework.getIdManager().getId("ParamAngleY");
boolean ab = idA.equals(idB); // true
boolean bc = idB.equals(idC); // false
// Java CubismId idA = CubismFramework.getIdManager().getId("ParamAngleX"); CubismId idB = CubismFramework.getIdManager().getId("ParamAngleX"); CubismId idC = CubismFramework.getIdManager().getId("ParamAngleY"); boolean ab = idA.equals(idB); // true boolean bc = idB.equals(idC); // false
// Java
CubismId idA = CubismFramework.getIdManager().getId("ParamAngleX");

CubismId idB = CubismFramework.getIdManager().getId("ParamAngleX");

CubismId idC = CubismFramework.getIdManager().getId("ParamAngleY");

boolean ab = idA.equals(idB); // true
boolean bc = idB.equals(idC); // false

值操作函数有两种方法:通过Index访问和通过CubismId
访问。

设置参数

参数通常从动态中播放,但您也可以直接指定值。
根据应用值的计算方法,有三种类型的参数操作函数,如下所示。

1. 覆盖值

使用以下任意函数。

  • Native(C++)的CubismModel::SetParameterValue函数
  • Web(TypeScript)的CubismModel.setParameterValueById函数
  • Java的CubismModel.setParameterValue函数

在第一参数中设置参数ID或索引,在第二参数中设置值,在第三参数中设置影响程度。
影响程度可以省略,在这种情况下它将是1。
例如,如果将其设置为0.5,则会在保留前一个值的50%影响的同时进行设置。

示例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
_model->SetParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 30.0f, 1.0f);
// C++ _model->SetParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 30.0f, 1.0f);
// C++
_model->SetParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 30.0f, 1.0f);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
_model.setParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 30.0, 1.0);
// TypeScript _model.setParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 30.0, 1.0);
// TypeScript
_model.setParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 30.0, 1.0);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
model.setParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 30.0f, 1.0f);
// Java model.setParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 30.0f, 1.0f);
// Java
model.setParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 30.0f, 1.0f);

2. 加算到当前值

使用以下任意函数。

  • Native(C++)的CubismModel::AddParameterValue函数
  • Web(TypeScript)的CubismModel.addParameterValueById函数
  • Java的CubismModel.addParameterValue函数

参数与以下任意函数相同。

  • Native(C++)的CubismModel::SetParameterValue函数
  • Web(TypeScript)的CubismModel.setParameterValueById函数
  • Java的CubismModel.setParameterValue函数

此函数设置的值将加算到该参数中当前设置的值。

示例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
_model->AddParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 1.0f, 1.0f);
// C++ _model->AddParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 1.0f, 1.0f);
// C++
_model->AddParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 1.0f, 1.0f);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
_model.addParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 1.0, 1.0);
// TypeScript _model.addParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 1.0, 1.0);
// TypeScript
_model.addParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 1.0, 1.0);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
model.addParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 1.0f, 1.0f);
// Java model.addParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 1.0f, 1.0f);
// Java
model.addParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 1.0f, 1.0f);

3. 正片叠底当前值

使用以下任意函数。

  • Native(C++)的CubismModel::MultiplyParameterValue函数
  • Web(TypeScript)的CubismModel.multiplyParameterValueById函数
  • Java的CubismModel.multiplyParameterValue函数

参数与以下任意函数相同。

  • CubismModel::MultiplyParameterValue函数
  • Web(TypeScript)的CubismModel.multiplyParameterValueById函数
  • Java的CubismModel.multiplyParameterValue函数

此函数设置的值将正片叠底到该参数中当前设置的值。

示例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
_model->MultiplyParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 2.0f, 1.0f);
// C++ _model->MultiplyParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 2.0f, 1.0f);
// C++
_model->MultiplyParameterValue(CubismFramework::GetIdManager()->GetId("ParamAngleX"), 2.0f, 1.0f);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
_model.multiplyParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 2.0, 1.0);
// TypeScript _model.multiplyParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 2.0, 1.0);
// TypeScript
_model.multiplyParameterValueById(CubismFramework.getIdManager().getId("ParamAngleX"), 2.0, 1.0);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
model.multiplyParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 2.0f, 1.0f);
// Java model.multiplyParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 2.0f, 1.0f);
// Java
model.multiplyParameterValue(CubismFramework.getIdManager().getId("ParamAngleX"), 2.0f, 1.0f);

此外,使用以下任意函数来获取当前参数值。

  • Native(C++)的CubismModel::GetParameterValue函数
  • Web(TypeScript)的CubismModel.getParameterValueById函数
  • Java的CubismModel.getParameterValue函数

通过参数索引指定

参数ID的指定方式有两种,一种是通过字符串生成的ID类型指定,另一种是通过索引指定。
例如提前获取索引等,在缓存后使用索引会更快,所以建议在调用频率高的时候使用索引。
参数索引可以通过以下任意函数获取。

  • Native(C++)的CubismModel::GetParameterIndex函数
  • Web(TypeScript)的CubismModel.getParameterIndex函数
  • Java的CubismModel.getParameterIndex函数

示例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
// 原始化时
csmInt32 paramAngleX;
paramAngleX = _model->GetParameterIndex(CubismFramework::GetIdManager()->GetId("ParamAngleX"));
// 设置参数时
_model->SetParameterValue( paramAngleX, 30.0f , 1.0f);
// C++ // 原始化时 csmInt32 paramAngleX; paramAngleX = _model->GetParameterIndex(CubismFramework::GetIdManager()->GetId("ParamAngleX")); // 设置参数时 _model->SetParameterValue( paramAngleX, 30.0f , 1.0f);
// C++
// 原始化时
csmInt32 paramAngleX;
paramAngleX = _model->GetParameterIndex(CubismFramework::GetIdManager()->GetId("ParamAngleX"));

// 设置参数时
_model->SetParameterValue( paramAngleX, 30.0f , 1.0f);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
// 原始化时
let paramAngleX: number;
paramAngleX = _model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));
// 设置参数时
_model.setParameterValueByIndex(paramAngleX, 30.0, 1.0);
// TypeScript // 原始化时 let paramAngleX: number; paramAngleX = _model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX")); // 设置参数时 _model.setParameterValueByIndex(paramAngleX, 30.0, 1.0);
// TypeScript
// 原始化时
let paramAngleX: number;
paramAngleX = _model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));

// 设置参数时
_model.setParameterValueByIndex(paramAngleX, 30.0, 1.0);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
// 原始化时
int paramAngleXIndex;
paramAngleXIndex = model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));
// 设置参数时
model.setParameterValue(paramAngleXIndex, 30.0f, 1.0f);
// Java // 原始化时 int paramAngleXIndex; paramAngleXIndex = model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX")); // 设置参数时 model.setParameterValue(paramAngleXIndex, 30.0f, 1.0f);
// Java
// 原始化时
int paramAngleXIndex;
paramAngleXIndex = model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));
// 设置参数时
model.setParameterValue(paramAngleXIndex, 30.0f, 1.0f);

保存和恢复参数值

要临时保存模型的当前参数值时,可以使用以下任意参数。

  • Native(C++)的CubismModel::SaveParameters函数
  • Web(TypeScript)的CubismModel.saveParameters函数
  • Java的CubismModel.saveParameters函数

要恢复临时保存的模型参数值时,可以使用以下任意参数。

  • Native(C++)的CubismModel::LoadParameters函数
  • Web(TypeScript)的CubismModel.loadParameters函数
  • Java的CubismModel.loadParameters函数

示例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
// 原始化时
csmInt32 paramAngleX;
paramAngleX = _model->GetParameterIndex(CubismFramework::GetIdManager()->GetId("ParamAngleX"));
// 设置参数为30
_model->SetParameterValue( paramAngleX, 30.0f ,1.0f );
// 临时保存所有当前参数值
_model->SaveParameters();
// 设置为0
_model->SetParameterValue( paramAngleX, 0.0f ,1.0f );
//output: value = 0
printf("value = %f",_model->GetParameterValue( paramAngleX ) );
// 恢复上次saveParam时的状态
_model->LoadParameters();
//output: value = 30
printf("value = %f",_model->GetParameterValue( paramAngleX ) );
// C++ // 原始化时 csmInt32 paramAngleX; paramAngleX = _model->GetParameterIndex(CubismFramework::GetIdManager()->GetId("ParamAngleX")); // 设置参数为30 _model->SetParameterValue( paramAngleX, 30.0f ,1.0f ); // 临时保存所有当前参数值 _model->SaveParameters(); // 设置为0 _model->SetParameterValue( paramAngleX, 0.0f ,1.0f ); //output: value = 0 printf("value = %f",_model->GetParameterValue( paramAngleX ) ); // 恢复上次saveParam时的状态 _model->LoadParameters(); //output: value = 30 printf("value = %f",_model->GetParameterValue( paramAngleX ) );
// C++
// 原始化时
csmInt32 paramAngleX;
paramAngleX = _model->GetParameterIndex(CubismFramework::GetIdManager()->GetId("ParamAngleX"));

// 设置参数为30
_model->SetParameterValue( paramAngleX, 30.0f ,1.0f );

// 临时保存所有当前参数值
_model->SaveParameters();

// 设置为0
_model->SetParameterValue( paramAngleX, 0.0f ,1.0f );

//output: value = 0
printf("value = %f",_model->GetParameterValue( paramAngleX ) );

// 恢复上次saveParam时的状态
_model->LoadParameters();

//output: value = 30
printf("value = %f",_model->GetParameterValue( paramAngleX ) );
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
// 原始化时
let paramAngleX: number;
paramAngleX = _model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));
// 设置参数为30
_model.setParameterValueByIndex(paramAngleX, 30.0, 1.0);
// 临时保存所有当前参数值
_model.saveParameters();
// 设置为0
_model.setParameterValue(paramAngleX, 0.0, 1.0);
// output: value = 0
LAppPal.printLog("value = {0}", _model.getParameterValueByIndex(paramAngleX));
// 恢复上次saveParam时的状态
_model.loadParameters();
// output: value = 30
LAppPal.printLog("value = {0}", _model.getParameterValueByIndex(paramAngleX));
// TypeScript // 原始化时 let paramAngleX: number; paramAngleX = _model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX")); // 设置参数为30 _model.setParameterValueByIndex(paramAngleX, 30.0, 1.0); // 临时保存所有当前参数值 _model.saveParameters(); // 设置为0 _model.setParameterValue(paramAngleX, 0.0, 1.0); // output: value = 0 LAppPal.printLog("value = {0}", _model.getParameterValueByIndex(paramAngleX)); // 恢复上次saveParam时的状态 _model.loadParameters(); // output: value = 30 LAppPal.printLog("value = {0}", _model.getParameterValueByIndex(paramAngleX));
// TypeScript
// 原始化时
let paramAngleX: number;
paramAngleX = _model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));

// 设置参数为30
_model.setParameterValueByIndex(paramAngleX, 30.0, 1.0);

// 临时保存所有当前参数值
_model.saveParameters();

// 设置为0
_model.setParameterValue(paramAngleX, 0.0, 1.0);

// output: value = 0
LAppPal.printLog("value = {0}", _model.getParameterValueByIndex(paramAngleX));

// 恢复上次saveParam时的状态
_model.loadParameters();

// output: value = 30
LAppPal.printLog("value = {0}", _model.getParameterValueByIndex(paramAngleX));
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
// 原始化时
int paramAngleXIndex;
paramAngleXIndex = model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));
// 设置参数为30
model.setParameterValue(paramAngleXIndex, 30.0f, 1.0f);
// 临时保存所有当前参数值
model.saveParameters();
// 设置为0
model.setParameterValue(paramAngleXIndex, 0.0f, 1.0f);
// output: value = 0
LAppPal.printLog("value = " + model.getParametetValue(paramAngleXIndex));
// 恢复上次saveParameters时的状态
model.loadParameters();
// output: value = 30
LAppPal.printLog("value = " + model.getParameterValue(paramAngleXIndex));
// Java // 原始化时 int paramAngleXIndex; paramAngleXIndex = model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX")); // 设置参数为30 model.setParameterValue(paramAngleXIndex, 30.0f, 1.0f); // 临时保存所有当前参数值 model.saveParameters(); // 设置为0 model.setParameterValue(paramAngleXIndex, 0.0f, 1.0f); // output: value = 0 LAppPal.printLog("value = " + model.getParametetValue(paramAngleXIndex)); // 恢复上次saveParameters时的状态 model.loadParameters(); // output: value = 30 LAppPal.printLog("value = " + model.getParameterValue(paramAngleXIndex));
// Java
// 原始化时
int paramAngleXIndex;
paramAngleXIndex = model.getParameterIndex(CubismFramework.getIdManager().getId("ParamAngleX"));

// 设置参数为30
model.setParameterValue(paramAngleXIndex, 30.0f, 1.0f);

// 临时保存所有当前参数值
model.saveParameters();

// 设置为0
model.setParameterValue(paramAngleXIndex, 0.0f, 1.0f);

// output: value = 0
LAppPal.printLog("value = " + model.getParametetValue(paramAngleXIndex));

// 恢复上次saveParameters时的状态
model.loadParameters();

// output: value = 30
LAppPal.printLog("value = " + model.getParameterValue(paramAngleXIndex));

如何在LAppModel::Update中使用SaveParameters和LoadParameters

SaveParameters和LoadParameters作为API保存和调用值,
但在实际的LAppModel::Update函数中,调用LoadParameters重置为之前的状态,
并且应用动态播放后,运行SaveParameters。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
void LAppModel::Update()
{
const csmFloat32 deltaTimeSeconds = LAppPal::GetDeltaTime();
_userTimeSeconds += deltaTimeSeconds;
_dragManager->Update(deltaTimeSeconds);
_dragX = _dragManager->GetX();
_dragY = _dragManager->GetY();
csmBool motionUpdated = false;
//-----------------------------------------------------------------
_model->LoadParameters();
if (_motionManager->IsFinished())
{
StartRandomMotion(MotionGroupIdle, PriorityIdle);
}
else
{
motionUpdated = _motionManager->UpdateMotion(_model, deltaTimeSeconds);
}
_model->SaveParameters();
//-----------------------------------------------------------------
if (!motionUpdated)
{
if (_eyeBlink != NULL)
{
_eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // Set
}
}
if (_expressionManager != NULL)
{
_expressionManager->UpdateMotion(_model, deltaTimeSeconds); // Add Set Mult
}
_model->AddParameterValue(_idParamAngleX, _dragX * 30);
_model->AddParameterValue(_idParamAngleY, _dragY * 30);
_model->AddParameterValue(_idParamAngleZ, _dragX * _dragY * -30);
_model->AddParameterValue(_idParamBodyAngleX, _dragX * 10);
_model->AddParameterValue(_idParamEyeBallX, _dragX);
_model->AddParameterValue(_idParamEyeBallY, _dragY);
if (_breath != NULL)
{
_breath->UpdateParameters(_model, deltaTimeSeconds); // Add
}
if (_physics != NULL)
{
_physics->Evaluate(_model, deltaTimeSeconds); // Set
}
if (_lipSync)
{
csmFloat32 value = 0;
for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
{
_model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
}
}
if (_pose != NULL)
{
_pose->UpdateParameters(_model, deltaTimeSeconds); // 不对参数进行操作
}
_model->Update();
}
// C++ void LAppModel::Update() { const csmFloat32 deltaTimeSeconds = LAppPal::GetDeltaTime(); _userTimeSeconds += deltaTimeSeconds; _dragManager->Update(deltaTimeSeconds); _dragX = _dragManager->GetX(); _dragY = _dragManager->GetY(); csmBool motionUpdated = false; //----------------------------------------------------------------- _model->LoadParameters(); if (_motionManager->IsFinished()) { StartRandomMotion(MotionGroupIdle, PriorityIdle); } else { motionUpdated = _motionManager->UpdateMotion(_model, deltaTimeSeconds); } _model->SaveParameters(); //----------------------------------------------------------------- if (!motionUpdated) { if (_eyeBlink != NULL) { _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // Set } } if (_expressionManager != NULL) { _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // Add Set Mult } _model->AddParameterValue(_idParamAngleX, _dragX * 30); _model->AddParameterValue(_idParamAngleY, _dragY * 30); _model->AddParameterValue(_idParamAngleZ, _dragX * _dragY * -30); _model->AddParameterValue(_idParamBodyAngleX, _dragX * 10); _model->AddParameterValue(_idParamEyeBallX, _dragX); _model->AddParameterValue(_idParamEyeBallY, _dragY); if (_breath != NULL) { _breath->UpdateParameters(_model, deltaTimeSeconds); // Add } if (_physics != NULL) { _physics->Evaluate(_model, deltaTimeSeconds); // Set } if (_lipSync) { csmFloat32 value = 0; for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i) { _model->AddParameterValue(_lipSyncIds[i], value, 0.8f); } } if (_pose != NULL) { _pose->UpdateParameters(_model, deltaTimeSeconds); // 不对参数进行操作 } _model->Update(); }
// C++
void LAppModel::Update()
{
    const csmFloat32 deltaTimeSeconds = LAppPal::GetDeltaTime();
    _userTimeSeconds += deltaTimeSeconds;

    _dragManager->Update(deltaTimeSeconds);
    _dragX = _dragManager->GetX();
    _dragY = _dragManager->GetY();

    csmBool motionUpdated = false;

    //-----------------------------------------------------------------
    _model->LoadParameters(); 
    if (_motionManager->IsFinished())
    {
        StartRandomMotion(MotionGroupIdle, PriorityIdle);
    }
    else
    {
        motionUpdated = _motionManager->UpdateMotion(_model, deltaTimeSeconds); 
    }
    _model->SaveParameters();
    //-----------------------------------------------------------------
    
    if (!motionUpdated)
    {
        if (_eyeBlink != NULL)
        {
            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // Set
        }
    }

    if (_expressionManager != NULL)
    {
        _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // Add Set Mult
    }

    _model->AddParameterValue(_idParamAngleX, _dragX * 30);
    _model->AddParameterValue(_idParamAngleY, _dragY * 30);
    _model->AddParameterValue(_idParamAngleZ, _dragX * _dragY * -30);

    _model->AddParameterValue(_idParamBodyAngleX, _dragX * 10); 
    
    _model->AddParameterValue(_idParamEyeBallX, _dragX);
    _model->AddParameterValue(_idParamEyeBallY, _dragY);

    if (_breath != NULL)
    {
        _breath->UpdateParameters(_model, deltaTimeSeconds); // Add
    }

    if (_physics != NULL)
    {
        _physics->Evaluate(_model, deltaTimeSeconds); // Set
    }

    if (_lipSync)
    {
        csmFloat32 value = 0; 

        for (csmUint32 i = 0; i < _lipSyncIds.GetSize(); ++i)
        {
            _model->AddParameterValue(_lipSyncIds[i], value, 0.8f);
        }
    }

    if (_pose != NULL)
    {
        _pose->UpdateParameters(_model, deltaTimeSeconds); // 不对参数进行操作
    }

    _model->Update();

}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
public update(): void
{
if(this._state != LoadStep.CompleteSetup) return;
const deltaTimeSeconds: number = LAppPal.getDeltaTime();
this._userTimeSeconds += deltaTimeSeconds;
this._dragManager.update(deltaTimeSeconds);
this._dragX = this._dragManager.getX();
this._dragY = this._dragManager.getY();
let motionUpdated = false;
//--------------------------------------------------------------------------
this._model.loadParameters();
if(this._motionManager.isFinished())
{
this.startRandomMotion(LAppDefine.MotionGroupIdle, LAppDefine.PriorityIdle);
}
else
{
motionUpdated = this._motionManager.updateMotion(this._model, deltaTimeSeconds);
}
this._model.saveParameters();
//--------------------------------------------------------------------------
if(!motionUpdated)
{
if(this._eyeBlink != null)
{
this._eyeBlink.updateParameters(this._model, deltaTimeSeconds); // Set
}
}
if(this._expressionManager != null)
{
this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // Add Set Mult
}
this._model.addParameterValueById(this._idParamAngleX, this._dragX * 30);
this._model.addParameterValueById(this._idParamAngleY, this._dragY * 30);
this._model.addParameterValueById(this._idParamAngleZ, this._dragX * this._dragY * -30);
this._model.addParameterValueById(this._idParamBodyAngleX, this._dragX * 10);
this._model.addParameterValueById(this._idParamEyeBallX, this._dragX);
this._model.addParameterValueById(this._idParamEyeBallY, this._dragY);
if(this._breath != null)
{
this._breath.updateParameters(this._model, deltaTimeSeconds); // Add
}
if(this._physics != null)
{
this._physics.evaluate(this._model, deltaTimeSeconds); // Set
}
if(this._lipsync)
{
let value: number = 0;
for(let i: number = 0; i < this._lipSyncIds.getSize(); ++i)
{
this._model.addParameterValueById(this._lipSyncIds.at(i), value, 0.8);
}
}
if(this._pose != null)
{
this._pose.updateParameters(this._model, deltaTimeSeconds); // 不对参数进行操作
}
this._model.update();
}
// TypeScript public update(): void { if(this._state != LoadStep.CompleteSetup) return; const deltaTimeSeconds: number = LAppPal.getDeltaTime(); this._userTimeSeconds += deltaTimeSeconds; this._dragManager.update(deltaTimeSeconds); this._dragX = this._dragManager.getX(); this._dragY = this._dragManager.getY(); let motionUpdated = false; //-------------------------------------------------------------------------- this._model.loadParameters(); if(this._motionManager.isFinished()) { this.startRandomMotion(LAppDefine.MotionGroupIdle, LAppDefine.PriorityIdle); } else { motionUpdated = this._motionManager.updateMotion(this._model, deltaTimeSeconds); } this._model.saveParameters(); //-------------------------------------------------------------------------- if(!motionUpdated) { if(this._eyeBlink != null) { this._eyeBlink.updateParameters(this._model, deltaTimeSeconds); // Set } } if(this._expressionManager != null) { this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // Add Set Mult } this._model.addParameterValueById(this._idParamAngleX, this._dragX * 30); this._model.addParameterValueById(this._idParamAngleY, this._dragY * 30); this._model.addParameterValueById(this._idParamAngleZ, this._dragX * this._dragY * -30); this._model.addParameterValueById(this._idParamBodyAngleX, this._dragX * 10); this._model.addParameterValueById(this._idParamEyeBallX, this._dragX); this._model.addParameterValueById(this._idParamEyeBallY, this._dragY); if(this._breath != null) { this._breath.updateParameters(this._model, deltaTimeSeconds); // Add } if(this._physics != null) { this._physics.evaluate(this._model, deltaTimeSeconds); // Set } if(this._lipsync) { let value: number = 0; for(let i: number = 0; i < this._lipSyncIds.getSize(); ++i) { this._model.addParameterValueById(this._lipSyncIds.at(i), value, 0.8); } } if(this._pose != null) { this._pose.updateParameters(this._model, deltaTimeSeconds); // 不对参数进行操作 } this._model.update(); }
// TypeScript
public update(): void
{
    if(this._state != LoadStep.CompleteSetup) return;
    
    const deltaTimeSeconds: number = LAppPal.getDeltaTime();
    this._userTimeSeconds += deltaTimeSeconds;

    
    this._dragManager.update(deltaTimeSeconds);
    this._dragX = this._dragManager.getX();
    this._dragY = this._dragManager.getY();

    let motionUpdated = false;

    //--------------------------------------------------------------------------
    this._model.loadParameters();
    if(this._motionManager.isFinished())
    {
        this.startRandomMotion(LAppDefine.MotionGroupIdle, LAppDefine.PriorityIdle);
        
    }
    else
    {
        motionUpdated = this._motionManager.updateMotion(this._model, deltaTimeSeconds);
    }
    this._model.saveParameters();
    //--------------------------------------------------------------------------

    if(!motionUpdated)
    {
        if(this._eyeBlink != null)
        {
            this._eyeBlink.updateParameters(this._model, deltaTimeSeconds); // Set
        }
    }

    if(this._expressionManager != null)
    {
        this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // Add Set Mult
    }

    this._model.addParameterValueById(this._idParamAngleX, this._dragX * 30);
    this._model.addParameterValueById(this._idParamAngleY, this._dragY * 30);
    this._model.addParameterValueById(this._idParamAngleZ, this._dragX * this._dragY * -30);

    this._model.addParameterValueById(this._idParamBodyAngleX, this._dragX * 10);

    this._model.addParameterValueById(this._idParamEyeBallX, this._dragX);
    this._model.addParameterValueById(this._idParamEyeBallY, this._dragY);

    if(this._breath != null)
    {
        this._breath.updateParameters(this._model, deltaTimeSeconds); // Add
    }

    if(this._physics != null)
    {
        this._physics.evaluate(this._model, deltaTimeSeconds); // Set
    }

    if(this._lipsync)
    {
        let value: number = 0;

        for(let i: number = 0; i < this._lipSyncIds.getSize(); ++i)
        {
            this._model.addParameterValueById(this._lipSyncIds.at(i), value, 0.8);
        }
    }
    
    if(this._pose != null)
    {
        this._pose.updateParameters(this._model, deltaTimeSeconds); // 不对参数进行操作
    }

    this._model.update();
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
public void update() {
final float deltaTimeSeconds = LAppPal.getDeltaTime();
userTimeSeconds += deltaTimeSeconds;
dragManager.update(deltaTimeSeconds);
dragX = dragManager.getX();
dragY = dragManager.getY();
boolean isMotionUpdated = false;
//--------------------------------------------------------------
model.loadParameters();
// 如果没有动态播放,则从待机动态开始随机播放
if (motionManager.isFinished()) {
startRandomMotion(LAppDefine.MotionGroup.IDLE.getId(), LAppDefine.Priority.IDLE.getPriority());
} else {
isMotionUpdated = motionManager.updateMotion(model, deltaTimeSeconds);
}
model.saveParameters();
// -------------------------------------------------------------
// 仅在没有主动态更新时眨眼
if (!isMotionUpdated) {
if (eyeBlink != null) {
eyeBlink.updateParameters(model, deltaTimeSeconds); // Set
}
}
if (expressionManager != null) {
expressionManager.updateMotion(model, deltaTimeSeconds); // Add Set Mult
}
// 通过拖动调整人脸方向
model.addParameterValue(idParamAngleX, dragX * 30);
model.addParameterValue(idParamAngleY, dragY * 30);
model.addParameterValue(idParamAngleZ, dragX * dragY * (-30));
// 通过拖动调整身体方向
model.addParameterValue(idParamBodyAngleX, dragX * 10);
// 通过拖动调整眼睛方向
model.addParameterValue(idParamEyeBallX, dragX);
model.addParameterValue(idParamEyeBallY, dragY);
if (breath != null) {
breath.updateParameters(model, deltaTimeSeconds); // Add
}
if (physics != null) {
physics.evaluate(model, deltaTimeSeconds); // Set
}
if (lipSync) {
// 实时进行口形同步时,从系统获取音量,并输入0~1范围内的值。
float value = 0.0f;
for (CubismId lipSyncId : lipSyncIds) {
model.addParameterValue(lipSyncId, value, 0.8f);
}
}
if (pose != null) {
pose.updateParameters(model, deltaTimeSeconds); // 不对参数进行操作
}
model.update();
}
// Java public void update() { final float deltaTimeSeconds = LAppPal.getDeltaTime(); userTimeSeconds += deltaTimeSeconds; dragManager.update(deltaTimeSeconds); dragX = dragManager.getX(); dragY = dragManager.getY(); boolean isMotionUpdated = false; //-------------------------------------------------------------- model.loadParameters(); // 如果没有动态播放,则从待机动态开始随机播放 if (motionManager.isFinished()) { startRandomMotion(LAppDefine.MotionGroup.IDLE.getId(), LAppDefine.Priority.IDLE.getPriority()); } else { isMotionUpdated = motionManager.updateMotion(model, deltaTimeSeconds); } model.saveParameters(); // ------------------------------------------------------------- // 仅在没有主动态更新时眨眼 if (!isMotionUpdated) { if (eyeBlink != null) { eyeBlink.updateParameters(model, deltaTimeSeconds); // Set } } if (expressionManager != null) { expressionManager.updateMotion(model, deltaTimeSeconds); // Add Set Mult } // 通过拖动调整人脸方向 model.addParameterValue(idParamAngleX, dragX * 30); model.addParameterValue(idParamAngleY, dragY * 30); model.addParameterValue(idParamAngleZ, dragX * dragY * (-30)); // 通过拖动调整身体方向 model.addParameterValue(idParamBodyAngleX, dragX * 10); // 通过拖动调整眼睛方向 model.addParameterValue(idParamEyeBallX, dragX); model.addParameterValue(idParamEyeBallY, dragY); if (breath != null) { breath.updateParameters(model, deltaTimeSeconds); // Add } if (physics != null) { physics.evaluate(model, deltaTimeSeconds); // Set } if (lipSync) { // 实时进行口形同步时,从系统获取音量,并输入0~1范围内的值。 float value = 0.0f; for (CubismId lipSyncId : lipSyncIds) { model.addParameterValue(lipSyncId, value, 0.8f); } } if (pose != null) { pose.updateParameters(model, deltaTimeSeconds); // 不对参数进行操作 } model.update(); }
// Java
public void update() {
    final float deltaTimeSeconds = LAppPal.getDeltaTime();
    userTimeSeconds += deltaTimeSeconds;
  
    dragManager.update(deltaTimeSeconds);
    dragX = dragManager.getX();
    dragY = dragManager.getY();
  
    boolean isMotionUpdated = false;
  
    //--------------------------------------------------------------
    model.loadParameters();
  
    // 如果没有动态播放,则从待机动态开始随机播放
    if (motionManager.isFinished()) {
        startRandomMotion(LAppDefine.MotionGroup.IDLE.getId(), LAppDefine.Priority.IDLE.getPriority());
    } else {
        isMotionUpdated = motionManager.updateMotion(model, deltaTimeSeconds);
    }
    model.saveParameters();
    // -------------------------------------------------------------

  // 仅在没有主动态更新时眨眼
  if (!isMotionUpdated) {
    if (eyeBlink != null) {
      eyeBlink.updateParameters(model, deltaTimeSeconds); // Set
    }
  }
  
  if (expressionManager != null) {
    expressionManager.updateMotion(model, deltaTimeSeconds); // Add Set Mult
  }
  
  // 通过拖动调整人脸方向
  model.addParameterValue(idParamAngleX, dragX * 30);
  model.addParameterValue(idParamAngleY, dragY * 30);
  model.addParameterValue(idParamAngleZ, dragX * dragY * (-30));
  
  // 通过拖动调整身体方向
  model.addParameterValue(idParamBodyAngleX, dragX * 10);
  
  // 通过拖动调整眼睛方向
  model.addParameterValue(idParamEyeBallX, dragX);
  model.addParameterValue(idParamEyeBallY, dragY);
  
  if (breath != null) {
    breath.updateParameters(model, deltaTimeSeconds); // Add
  }
  
  if (physics != null) {
    physics.evaluate(model, deltaTimeSeconds); // Set
  }
  
  if (lipSync) {
    // 实时进行口形同步时,从系统获取音量,并输入0~1范围内的值。
    float value = 0.0f;
    
    for (CubismId lipSyncId : lipSyncIds) {
      model.addParameterValue(lipSyncId, value, 0.8f);
    }
  }

  if (pose != null) {
    pose.updateParameters(model, deltaTimeSeconds); // 不对参数进行操作
  }
  
  model.update();
}

此方法的目的是通过使用进入Update的其他操作之前的值
对不播放动态或动态播放未指定的参数进行覆盖,创建加算/正片叠底计算的基础。

没有此功能时,如果Add到动态中未指定的参数,则每次更新都会Add该值,并且该值将超出范围。

即使仅在动态播放前Load,您也可以创建加算/正片叠底的基础,
但动态播放后进入Save,则可以保留动态的最终状态。

获取和设置部件的不透明度

要设置部件的不透明度时,可以使用以下任意参数。

  • Native(C++)的CubismModel::SetPartOpacity函数
  • Web(TypeScript)的CubismModel.setPartOpacityById函数
  • Java的CubismModel.setPartOpactiy函数

要获取部件的不透明度时,可以使用以下任意参数。

  • Native(C++)的CubismModel::GetPartOpacity函数
  • Web(TypeScript)的CubismModel.getPartOpacityById函数
  • Java的CubismModel.getPartOpacity函数

示例

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
// 设置脸部部件的不透明度为0.5
_model->SetPartOpacity( CubismFramework::GetIdManager()->GetId("PartArmLB001"),0.5f );
// C++ // 设置脸部部件的不透明度为0.5 _model->SetPartOpacity( CubismFramework::GetIdManager()->GetId("PartArmLB001"),0.5f );
// C++
// 设置脸部部件的不透明度为0.5
_model->SetPartOpacity( CubismFramework::GetIdManager()->GetId("PartArmLB001"),0.5f );
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
// 设置脸部部件的不透明度为0.5
_model.setPartOpacityById(CubismFramework.getIdManager().getId("PartArmLB001"), 0.5);
// TypeScript // 设置脸部部件的不透明度为0.5 _model.setPartOpacityById(CubismFramework.getIdManager().getId("PartArmLB001"), 0.5);
// TypeScript
// 设置脸部部件的不透明度为0.5
_model.setPartOpacityById(CubismFramework.getIdManager().getId("PartArmLB001"), 0.5);
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Java
// 设置脸部部件的不透明度为0.5
model.setPartOpacity(CubismFramework.getIdManager().getId("PartArmLB001"), 0.5f);
// Java // 设置脸部部件的不透明度为0.5 model.setPartOpacity(CubismFramework.getIdManager().getId("PartArmLB001"), 0.5f);
// Java
// 设置脸部部件的不透明度为0.5
model.setPartOpacity(CubismFramework.getIdManager().getId("PartArmLB001"), 0.5f);

参数的应用时机和成本

设置参数时,只重写参数值,不计算顶点。
参数变更后,使用以下任意函数计算顶点。

  • Native(C++)的CubismModel::Updatel函数
  • Web(TypeScript)的CubismModel.updatel函数
  • Java的CubismModel.updatel函数

之后,通过以下任意函数绘制应用参数后的模型。

  • Native(C++)的CubismRenderer::DrawModel函数
  • Web(TypeScript)的CubismRenderer.drawModel函数
  • Java的CubismRenderer.drawModel函数

参数计算顺序的重要性

参数操作分为三种类型:覆盖、加算和正片叠底。
进行第一次正片叠底计算不会影响以后的加算或覆盖。
如果最后执行覆盖,则到该点为止的所有计算结果都将被忽略。
应用覆盖、加算和正片叠底很常见。

在难以将计算内容作为程序组件等检查的情况下,
您需要知道哪个操作执行哪个计算,并设置按顺序应用组件的顺序。

让我们看看是什么样的代码差异导致了上面Gif所示的眼睛张开差异。
这是将眨眼和表情应用于SDK中包含的范例模型haru的示例。
表情设置处于播放2倍眼睛开合的f06.exp3.json的状态。
只贴出C++代码,因为计算顺序是唯一的问题。

覆盖动作的自动眨眼后,进行正片叠底动作表情设置的A的Update

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
// 眨眼
if (!motionUpdated)
{
if (_eyeBlink != NULL)
{
// 当主动态没有更新时
_eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 眨眼
}
}
if (_expressionManager != NULL)
{
_expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
}
// C++ // 眨眼 if (!motionUpdated) { if (_eyeBlink != NULL) { // 当主动态没有更新时 _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 眨眼 } } if (_expressionManager != NULL) { _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 通过表情更新参数(相对变化) }
// C++
	// 眨眼
    if (!motionUpdated)
    {
        if (_eyeBlink != NULL)
        {
            // 当主动态没有更新时
            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 眨眼
        }
    }

    if (_expressionManager != NULL)
    {
        _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
    }
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
// 眨眼
if (!motionUpdated)
{
if (this._eyeBlink != NULL)
{
// 当主动态没有更新时
this._eyeBlink->UpdateParameters(this._model, deltaTimeSeconds); // 眨眼
}
}
if (this._expressionManager != NULL)
{
this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
}
// TypeScript // 眨眼 if (!motionUpdated) { if (this._eyeBlink != NULL) { // 当主动态没有更新时 this._eyeBlink->UpdateParameters(this._model, deltaTimeSeconds); // 眨眼 } } if (this._expressionManager != NULL) { this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // 通过表情更新参数(相对变化) }
// TypeScript
	// 眨眼
    if (!motionUpdated)
    {
        if (this._eyeBlink != NULL)
        {
            // 当主动态没有更新时
            this._eyeBlink->UpdateParameters(this._model, deltaTimeSeconds); // 眨眼
        }
    }

    if (this._expressionManager != NULL)
    {
        this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
    }

设置正片叠底动作的表情后,进行覆盖动作的自动眨眼的B的Update

B的Update(Native)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C++
if (_expressionManager != NULL)
{
_expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
}
// 眨眼
if (!motionUpdated)
{
if (_eyeBlink != NULL)
{
// 当主动态没有更新时
_eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 眨眼
}
}
// C++ if (_expressionManager != NULL) { _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 通过表情更新参数(相对变化) } // 眨眼 if (!motionUpdated) { if (_eyeBlink != NULL) { // 当主动态没有更新时 _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 眨眼 } }
// C++
	if (_expressionManager != NULL)
    {
        _expressionManager->UpdateMotion(_model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
    }

    // 眨眼
    if (!motionUpdated)
    {
        if (_eyeBlink != NULL)
        {
            // 当主动态没有更新时
            _eyeBlink->UpdateParameters(_model, deltaTimeSeconds); // 眨眼
        }
    }
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// TypeScript
if (this._expressionManager != NULL)
{
this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
}
// 眨眼
if (!motionUpdated)
{
if (this._eyeBlink != NULL)
{
// 当主动态没有更新时
this._eyeBlink.updateParameters(this._model, deltaTimeSeconds); // 眨眼
}
}
// TypeScript if (this._expressionManager != NULL) { this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // 通过表情更新参数(相对变化) } // 眨眼 if (!motionUpdated) { if (this._eyeBlink != NULL) { // 当主动态没有更新时 this._eyeBlink.updateParameters(this._model, deltaTimeSeconds); // 眨眼 } }
// TypeScript
	if (this._expressionManager != NULL)
    {
        this._expressionManager.updateMotion(this._model, deltaTimeSeconds); // 通过表情更新参数(相对变化)
    }

    // 眨眼
    if (!motionUpdated)
    {
        if (this._eyeBlink != NULL)
        {
            // 当主动态没有更新时
            this._eyeBlink.updateParameters(this._model, deltaTimeSeconds); // 眨眼
        }
    }

在A中,您可以看到由于眨眼后表情的效果,眼睛睁大了。
另一方面,在B的计算中,被眨眼覆盖,并被抑制到标准的眼睛开合。
仅计算顺序不同,导致模型所表达的细微差别很大。

请与设计师共享动态、表情、功能的计算顺序。

请问这篇文章对您有帮助吗?
关于本报道,敬请提出您的意见及要求。