导入UnrealEngine
本章介绍如何将CriLipsMake2输出的Mpeg4-Visemes动画曲线文件(.csv)导入到UnrealEngine。
作为DataTable资产导入
这是SDK附带的示例项目所采用的方法。直接处理CSV文件,便于替换解析后的数据等操作。
将CSV中的数值直接分配给角色模型。

首先,在Source/RealLipsync/Public/SmpUtils.h中以LipsMP4Viseme类型定义数据表结构。
本次仅将音素序列作为导入对象。
USTRUCT(BlueprintType, Category = "Sample")
struct REALLIPSYNC_API FLipsMP4Viseme
: public FTableRowBase
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float Sil = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float PP = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float FF = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float TH = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float DD = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float KK = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float CH = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float SS = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float NN = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float RR = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float AA = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float E = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float IH = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float OH = 0.0f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sample")
float OU = 0.0f;
};
将CriLipsMake2输出的CSV文件作为LipsMP4Viseme导入到项目中。

为了在BluePrint中使用,在Source/RealLipsync/Private/SmpUtils.cpp中实现根据播放时刻查找行的GetDataTableValue()。
FLipsMP4Viseme USmpUtils::GetDataTableValue(UDataTable* InDataTable, float InTime)
{
check(IsValid(InDataTable));
if (InTime < 0.0f)
{
return FLipsMP4Viseme();
}
TArray<TPair<float, FName>> TimeNamePairs;
for (const auto& Name : InDataTable->GetRowNames())
{
float Time = FCString::Atof(*Name.ToString());
TimeNamePairs.Add(TPair<float, FName>(Time, Name));
}
TimeNamePairs.Sort([](const TPair<float, FName>& A, const TPair<float, FName>& B) {
return A.Key < B.Key;
});
for (int32 i = 0; i < TimeNamePairs.Num(); ++i)
{
if (InTime <= TimeNamePairs[i].Key)
{
return *InDataTable->FindRow<FLipsMP4Viseme>(TimeNamePairs[i].Value, FString());
}
}
if (TimeNamePairs.Num() > 0)
{
return *InDataTable->FindRow<FLipsMP4Viseme>(TimeNamePairs.Last().Value, FString());
}
return FLipsMP4Viseme();
}
在ModelBP中,将播放音频时获取的数据表内容分配给角色的音素变形目标。
