虚幻引擎5的抢先体验

UE5开启了抢先体验版,我也入了坑。
在开启汽车之旅之前,我先唠叨些,使用UE5相关的问题,做以记录。

虚幻引擎5 新功能

先说说,UE5最为亮眼的两大新特性:LumenNanite

Lumen:崭新的实时全局光照。

Lumen是一套动态全局光照技术,Lumen可以实现实时光线反弹,在Lumen帮助下可以包含多次反弹的全局光照,没有光照贴图并无需烘焙,启用Lumen之后,只要移动光源,光线反弹效果会跟着实时变化。

Lumen能够对场景和光照变化做出实时反应,且无需专门的光线追踪硬件。Lumen能在任何场景中渲染间接镜面反射,也可以无限反弹的漫反射。

这就意味着我们可以使用Lumen创建出更动态的场景,我们可以随意改变白天或者晚上的光照角度,系统会根据情况调整间接光照。Lumen的出现将为美术与设计行业的工作人员节省了大量时间。

Lumen很牛逼,但是在使用时候也是存在一些问题的。
我在做草地,双面渲染的时候,背面特别暗,导致在UE4中效果,在UE5中显示不出来。究其原因,Lumen不支持植物透光…

在项目中,使用了Lumen,自己加环境光和自发光板,不会补光,导致光线反射处出现噪点,简单的补光都搞不定,真是当不上技美了…

Nanite:多边形虚拟化的技术。

一个虚拟场景是由很多模型构成的,而这些模型的基础是三角形,所以三角形的数量通常都非常的多。这造成了一个问题:由于三角形的数量非常多,但是我们所能看到的三角形数量非常的少。这使得我们需要把很多不必要的三角形剔除,增加渲染的效率并节省时间。

而Nanite技术可以虚拟化几何体,Nanite能极快的渲染超多的三角面,并且能够将很多的三角面无损压缩成很少。Nanite能够展示像素级别的细节,这使得几何体中的三角形也常是像素大小的,这个级别的几何体细节也要求阴影能够精确到像素。

做过测试,将百万级三角面的模型,导入到工程,将模型拖到场景中进行显示,三角面骤降几千面,不得不承认,UE的强大,这一技术真实工业级模型的福音~但是讲百万级的三角面的模型导入工程时,UE5崩溃了3、4次,这个代价还是完全可以接受的。

还有相关的其他的更新。

  • UI更为现代化,使用起来更为舒服。
  • 超大世界协作提供方案:世界分区
  • 动画系统增强
  • 程序式音频 MetaSounds
  • 随身携带的Bridge Megascans云资产库

有些功能,我还没使用过,这里不做过多评论了。

虚幻引擎5 填坑

UE修改缓存存储位置

无论是安装版的还是源码版的UE5,默认引擎会把生成的缓存文件寄存在该目录下,该目录默认在系统盘中,久而久之会积累巨大从而严重影响运行速度。所以我们将这个目录指向项目目录下。

UE默认的项目缓存文件夹

C:\Users\你的用户名\AppData\Local\UnrealEngine

修改缓存文件夹路径

在UE安装目录下找到BaseEngine.ini文件
搜索
%ENGINEVERSIONAGNOSTICUSERDIR%DerivedDataCache
替换
%GAMEDIR%DerivedDataCache

UE在VS编译时乱码

这个没啥好办法解决,我是UE和VS都是使用的英文版的…

如果你使用的是源码版的,可以修改源码。

在工程中查找文件 Engine\Source\Developer\DesktopPlatform\Private\Windows\DesktopPlatformWindows.cpp
查找函数
FString FWindowsPlatformProcess::ReadPipe( void* ReadPipe )将
Output += FUTF8ToTCHAR((const ANSICHAR*)Buffer).Get();
修改为
Output += FString(string2wstring(std::string((const ANSICHAR*)Buffer), "Chinese_China.936").c_str());

UE5的源码编译

编译UE5,会使用你120多G的硬盘空间。并且几个小时的时间。

因为要编写UE服务端,所以需要UE5的源码版开发。
我在编译后,修改过UE5的路径,导致再次编译又花费了几个小时,并且编译最后出现了下面的错误。

Severity Code    Description Project File    Line    Suppression State
Error   MSB3073 The command "..\..\Build\BatchFiles\Build.bat -Target="UnrealEditor Win64 DebugGame" -Target="ShaderCompileWorker Win64 Development -Quiet" -WaitMutex -FromMsBuild" exited with code 6.    UE5 C:\Develop\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.MakeFile.Targets 44解决办法,删除目录
Engine\Intermediate\Build\Win64\UE4Editor\Development\VisualStudioDTE
重新 Build 一下就可以了。

虚幻引擎5 C++ 工程搭建

汽车基础交互-工程场景 展示:

创建工程,这里我们创建一个C++移动端空工程,命名为UEVehicleProject

添加"PhysXVehicles"模块,这里UE5是必须的,在UE4是可以不用添加的。
使用VS2019打开UEVehicleProject.sln
打开UEVehicleProject.Build.cs文件。添加"PhysXVehicles"模块。

...
public UEVehicleProject(ReadOnlyTargetRules Target) : base(Target)
{PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "PhysXVehicles" });...
}
...

打开UEVehicleProject.uproject文件。添加"PhysXVehicles"模块。

{"FileVersion": 3,"EngineAssociation": "5.0","Category": "","Description": "","Modules": [{"Name": "UEVehicleProject","Type": "Runtime","LoadingPhase": "Default"}],"Plugins": [{"Name": "PhysXVehicles","Enabled": true},{"Name": "Bridge","Enabled": true,"SupportedTargetPlatforms": ["Win64","Mac","Linux"]}]
}

当然,也可以在UE5工程中添加"PhysXVehicles"模块。

虚幻引擎5 C++ 工程基础

先说一下,该篇博客提交的汽车基础交互都要做什么。都是为以后驾驶交互和人车交互打基础。

  • 灯光交互:
    车辆前后灯控制,夜间行驶时照明功能。
    刹车灯控制,在刹车时亮起,停车后熄灭。
    倒车灯控制,汽车倒车时亮起。
  • 车门交互:
    对左前门控制开关,人员进入驾驶位时使用。
    对右前门控制开关,防止有右驾驶座位的车辆使用。
  • 换色交互:
    汽车车体更换不同颜色。

先创建几个汽车相关的类。

  • ABaseVehicle 类:基础车辆类,继承 AWheeledVehicle。
  • UFrontWheel 类:车前轮类,继承 UVehicleWheel。
  • URearWheel 类:车后轮类,继承 UVehicleWheel。

编写代码之前,需要先讲一下汽车的骨骼和动画蓝图。
汽车的骨骼,汽车前后车轮的骨骼节点是必须的,因为行驶时,以完成车轮的转动、转向需要,轱辘内的刹车片和左右车门,是根据需求添加的,要看都想完成什么样的操作。

再看一下汽车的蓝图动画,来控制车门的开关。

了解了要实现的功能和规则,我们来逐渐完善ABaseVehicle、UFrontWheel、URearWheel类,本篇博客只涉及到ABaseVehicle类的编写。
最终,我们会搞一个蓝图类BP_SUV,来继承C++类ABaseVehicle。指定车体模型,微调车灯、方向盘、仪表盘、尾气特效…等组件的位置。来完成不同车型(轿车、吉普、SUV…)的实现。这里以一辆SUV为例。

虚幻引擎5 C++ 汽车灯光交互

汽车灯光交互-前后灯控制 展示:

汽车灯光交互-刹车灯控制 展示:

汽车灯光交互-倒车灯控制 展示:

现在我们开始正式编码。
首先看一下ABaseVehicle 的构造函数。

...
ABaseVehicle::ABaseVehicle()
{InitBaseValue();                           // 初始化 基础 数值InitBaseMesh();                             // 初始化 基础 模型InitCameraComponent();                      // 初始化 摄像机 组件InitLightComponent();                      // 初始化 灯光 组件InitBrakeSystemComponent();                 // 初始化 刹车系统 组件InitSteeringWheelComponent();             // 初始化 方向盘 组件InitExhaustComponent();                        // 初始化 尾气 组件InitDashboardComponent();                   // 初始化 仪表盘 组件InitSoundComponent();                      // 初始化 声音 组件InitVehicleMovementComponent();             // 初始化 轮胎系统 组件InitDoorComponent();                      // 初始化 车门 组件InitColorComponent();                       // 初始化 颜色 组件
}
...

这里我们灯光的交互,所以我们只关注InitBaseMesh()和InitLightComponent()函数,后续只要是涉及到的部分都会进行讲解,稍安勿躁。

BaseVehicle.h 中相关模型、车灯的定义。

...
UCLASS()
class UEVEHICLEPROJECT_API ABaseVehicle : public AWheeledVehicle
{GENERATED_BODY()
public:ABaseVehicle();...//  车灯控制UFUNCTION(BlueprintCallable, Category = "VehicleFunc")void VehicleLights(bool position_lights, bool brake_lights, bool reverse_lights);...
protected:virtual void BeginPlay() override;...void InitBaseMesh();                                 // 初始化 基础 模型...void InitLightComponent();                               // 初始化 灯光 组件...
protected:// 骨骼模型   UPROPERTY(VisibleAnywhere, Category = "BaseMesh", meta = (AllowPrivateAccess = "true"))USkeletalMeshComponent*       VehicleMesh;...// 刹车灯UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*            BrakeLightL;UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*         BrakeLightR;// 倒车灯UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*           ReverseLightL;UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*           ReverseLightR;// 前灯UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*          FrontLightL;UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*         FrontLightR;// 尾灯UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*            RearLightL;UPROPERTY(VisibleAnywhere, Category = "Light", meta = (AllowPrivateAccess = "true"))USpotLightComponent*          RearLightR;...// 刹车灯材质int                                       BrakeLightMaterialID;UMaterialInstance*                     BrakeLightMaterialOff;UMaterialInstance*                        BrakeLightMaterialOn;// 倒车灯材质int                                        ReverseLightMaterialID;UMaterialInstance*                       ReverseLightMaterialOff;UMaterialInstance*                      ReverseLightMaterialOn;// 前灯材质int                                       FrontLightMaterialID;UMaterialInstance*                     FrontLightMaterialOff;UMaterialInstance*                        FrontLightMaterialOn;// 尾灯材质int                                     RearLightMaterialID;UMaterialInstance*                      RearLightMaterialOff;UMaterialInstance*                     RearLightMaterialOn;bool                                    PositionLights;...// 动画蓝图 UObject*                              VehicleAnimBP;...
};

BaseVehicle.cpp 相关的实现。

InitBaseMesh()函数,模型和动画蓝图初始化。

void ABaseVehicle::InitBaseMesh()
{VehicleMesh = GetMesh();static ConstructorHelpers::FObjectFinder<USkeletalMesh> sm_vehicle(TEXT("/Game/Meshs/Hatchback/Hatchback.Hatchback"));VehicleMesh->SetSkeletalMesh(sm_vehicle.Object);// 设置动画蓝图static ConstructorHelpers::FObjectFinder<UBlueprint> vehicleAminBP(TEXT("/Game/Animations/AnimBlueprint_vehicle.AnimBlueprint_vehicle"));FString strVehicleAnimBP = "Class'/Game/Animations/AnimBlueprint_vehicle.AnimBlueprint_vehicle'";VehicleAnimBP = vehicleAminBP.Object->GeneratedClass;VehicleMesh->SetAnimInstanceClass((UClass*)VehicleAnimBP);
}

InitLightComponent()函数,灯光组件的初始化。

void ABaseVehicle::InitLightComponent()
{// 记录车灯是否打开,使其不受刹车、倒车影响// 本再InitBaseValue() 函数中初始化,简化讲解写在这里。PositionLights = false;///// 刹车灯BrakeLightL = CreateDefaultSubobject<USpotLightComponent>(TEXT("BrakeLightL"));// 大体位置、角度,不同类型车 蓝图调整位置BrakeLightL->SetRelativeLocation(FVector(-199.0f, 72.0f, 95.0f));BrakeLightL->SetRelativeRotation(FRotator(0.0f, 160.0f, 0.0f));BrakeLightL->Mobility = EComponentMobility::Movable;            // 可移动// 光的设置BrakeLightL->Intensity = 25.0f;                                                // 强调BrakeLightL->LightColor = FColor(255, 0, 0);                           // 红色BrakeLightL->AttenuationRadius = 495.0f;                           // 影响半径BrakeLightL->InnerConeAngle = 0.f;                                       // 聚光源的内锥角BrakeLightL->OuterConeAngle = 90.f;                                   // 聚光源的外锥角BrakeLightL->SetupAttachment(VehicleMesh);BrakeLightR = CreateDefaultSubobject<USpotLightComponent>(TEXT("BrakeLightR"));// 大体位置、角度,不同类型车 蓝图调整位置BrakeLightR->SetRelativeLocation(FVector(-199.0f, -72.0f, 95.0f));BrakeLightR->SetRelativeRotation(FRotator(0.0f, -160.0f, 0.0f));BrakeLightR->Mobility = EComponentMobility::Movable;           // 可移动// 光的设置BrakeLightR->Intensity = 25.0f;                                                // 强调BrakeLightR->LightColor = FColor(255, 0, 0);                           // 红色BrakeLightR->AttenuationRadius = 495.0f;                           // 影响半径BrakeLightR->InnerConeAngle = 0.f;                                       // 聚光源的内锥角BrakeLightR->OuterConeAngle = 90.f;                                   // 聚光源的外锥角BrakeLightR->SetupAttachment(VehicleMesh);///// 倒车灯ReverseLightL = CreateDefaultSubobject<USpotLightComponent>(TEXT("ReverseLightL"));// 大体位置、角度,不同类型车 蓝图调整位置ReverseLightL->SetRelativeLocation(FVector(-203.0f, -60.0f, 93.0f));ReverseLightL->SetRelativeRotation(FRotator(0.0f, 180.0f, 0.0f));ReverseLightL->Mobility = EComponentMobility::Movable;         // 可移动// 光的设置ReverseLightL->Intensity = 25.0f;                                              // 强调ReverseLightL->LightColor = FColor(255, 255, 255);                 // 白色ReverseLightL->AttenuationRadius = 495.0f;                         // 影响半径ReverseLightL->InnerConeAngle = 0.f;                                     // 聚光源的内锥角ReverseLightL->OuterConeAngle = 90.f;                                 // 聚光源的外锥角ReverseLightL->SetupAttachment(VehicleMesh);ReverseLightR = CreateDefaultSubobject<USpotLightComponent>(TEXT("ReverseLightR"));// 大体位置、角度,不同类型车 蓝图调整位置ReverseLightR->SetRelativeLocation(FVector(-203.0f, 60.0f, 93.0f));ReverseLightR->SetRelativeRotation(FRotator(0.0f, 180.0f, 0.0f));ReverseLightR->Mobility = EComponentMobility::Movable;         // 可移动// 光的设置ReverseLightR->Intensity = 25.0f;                                              // 强调ReverseLightR->LightColor = FColor(255, 255, 255);                 // 白色ReverseLightR->AttenuationRadius = 495.0f;                         // 影响半径ReverseLightR->InnerConeAngle = 0.f;                                     // 聚光源的内锥角ReverseLightR->OuterConeAngle = 90.f;                                 // 聚光源的外锥角ReverseLightR->SetupAttachment(VehicleMesh);///// 前灯FrontLightL = CreateDefaultSubobject<USpotLightComponent>(TEXT("FrontLightL"));// 大体位置、角度,不同类型车 蓝图调整位置FrontLightL->SetRelativeLocation(FVector(197.0f, -70.0f, 69.0f));FrontLightL->SetRelativeRotation(FRotator(0.0f, 0.0f, 0.0f));FrontLightL->Mobility = EComponentMobility::Movable;         // 可移动// 光的设置FrontLightL->Intensity = 100000.0f;                                                // 强调FrontLightL->LightColor = FColor(255, 255, 255);                   // 白色FrontLightL->AttenuationRadius = 5000.0f;                          // 影响半径FrontLightL->InnerConeAngle = 0.f;                                       // 聚光源的内锥角FrontLightL->OuterConeAngle = 50.f;                                   // 聚光源的外锥角FrontLightL->SetupAttachment(VehicleMesh);FrontLightR = CreateDefaultSubobject<USpotLightComponent>(TEXT("FrontLightR"));// 大体位置、角度,不同类型车 蓝图调整位置FrontLightR->SetRelativeLocation(FVector(197.0f, 70.0f, 69.0f));FrontLightR->SetRelativeRotation(FRotator(0.0f, 0.0f, 0.0f));FrontLightR->Mobility = EComponentMobility::Movable;            // 可移动// 光的设置FrontLightR->Intensity = 100000.0f;                                                // 强调FrontLightR->LightColor = FColor(255, 255, 255);                   // 白色FrontLightR->AttenuationRadius = 5000.0f;                          // 影响半径FrontLightR->InnerConeAngle = 0.f;                                       // 聚光源的内锥角FrontLightR->OuterConeAngle = 50.f;                                   // 聚光源的外锥角FrontLightR->SetupAttachment(VehicleMesh);///// 尾灯RearLightL = CreateDefaultSubobject<USpotLightComponent>(TEXT("RearLightL"));// 大体位置、角度,不同类型车 蓝图调整位置RearLightL->SetRelativeLocation(FVector(-203.0f, -70.0f, 90.0f));RearLightL->SetRelativeRotation(FRotator(0.0f, 180.0f, 0.0f));RearLightL->Mobility = EComponentMobility::Movable;         // 可移动// 光的设置RearLightL->Intensity = 15.0f;                                             // 强调RearLightL->LightColor = FColor(255, 0, 0);                            // 红色RearLightL->AttenuationRadius = 495.0f;                            // 影响半径RearLightL->InnerConeAngle = 0.f;                                    // 聚光源的内锥角RearLightL->OuterConeAngle = 90.f;                                    // 聚光源的外锥角RearLightL->SetupAttachment(VehicleMesh);RearLightR = CreateDefaultSubobject<USpotLightComponent>(TEXT("RearLightR"));// 大体位置、角度,不同类型车 蓝图调整位置RearLightR->SetRelativeLocation(FVector(-203.0f, 70.0f, 90.0f));RearLightR->SetRelativeRotation(FRotator(0.0f, 180.0f, 0.0f));RearLightR->Mobility = EComponentMobility::Movable;           // 可移动// 光的设置RearLightR->Intensity = 15.0f;                                             // 强调RearLightR->LightColor = FColor(255, 0, 0);                            // 红色RearLightR->AttenuationRadius = 495.0f;                            // 影响半径RearLightR->InnerConeAngle = 0.f;                                    // 聚光源的内锥角RearLightR->OuterConeAngle = 90.f;                                    // 聚光源的外锥角RearLightR->SetupAttachment(VehicleMesh);/* ---------------------------------------------------------------------------------------------------------------------- */// 灯光材质设置///// 刹车灯材质static ConstructorHelpers::FObjectFinder<UMaterialInstance> temp_red(TEXT("/Game/Materials/Vehicle/Material_Instances/MI_Reflector_RED.MI_Reflector_RED"));static ConstructorHelpers::FObjectFinder<UMaterialInstance> temp_red_emmisive(TEXT("/Game/Materials/Vehicle/Material_Instances/MI_Reflector_RED_Emmisive.MI_Reflector_RED_Emmisive"));static ConstructorHelpers::FObjectFinder<UMaterialInstance> temp_grey(TEXT("/Game/Materials/Vehicle/Material_Instances/MI_Reflector_Grey.MI_Reflector_Grey"));static ConstructorHelpers::FObjectFinder<UMaterialInstance> temp_grey_emmisive(TEXT("/Game/Materials/Vehicle/Material_Instances/MI_Reflector_Grey_Emmisive.MI_Reflector_Grey_Emmisive"));BrakeLightMaterialID = 12;if (temp_red.Succeeded() == false)BrakeLightMaterialOff = nullptr;elseBrakeLightMaterialOff = temp_red.Object;//BrakeLightMaterialOff = UMaterialInstanceDynamic::Create(temp_red.Object, nullptr);           //创建动态材质实例if (temp_red_emmisive.Succeeded() == false)BrakeLightMaterialOn = nullptr;elseBrakeLightMaterialOn = temp_red_emmisive.Object;//BrakeLightMaterialOn = UMaterialInstanceDynamic::Create(temp_red_emmisive.Object, nullptr);          //创建动态材质实例///// 倒车灯材质ReverseLightMaterialID = 10;if (temp_grey.Succeeded() == false)ReverseLightMaterialOff = nullptr;elseReverseLightMaterialOff = temp_grey.Object;//ReverseLightMaterialOff = UMaterialInstanceDynamic::Create(temp_grey.Object, nullptr);         //创建动态材质实例if (temp_grey_emmisive.Succeeded() == false)ReverseLightMaterialOn = nullptr;elseReverseLightMaterialOn = temp_grey_emmisive.Object;//ReverseLightMaterialOn = UMaterialInstanceDynamic::Create(temp_grey_emmisive.Object, nullptr);         //创建动态材质实例///// 前灯材质FrontLightMaterialID = 9;if (temp_grey.Succeeded() == false)FrontLightMaterialOff = nullptr;elseFrontLightMaterialOff = temp_grey.Object;//FrontLightMaterialOff = UMaterialInstanceDynamic::Create(temp_grey.Object, nullptr);           //创建动态材质实例if (temp_grey_emmisive.Succeeded() == false)FrontLightMaterialOn = nullptr;elseFrontLightMaterialOn = temp_grey_emmisive.Object;//FrontLightMaterialOn = UMaterialInstanceDynamic::Create(temp_grey_emmisive.Object, nullptr);           //创建动态材质实例///// 尾灯材质RearLightMaterialID = 11;if (temp_red.Succeeded() == false)RearLightMaterialOff = nullptr;elseRearLightMaterialOff = temp_red.Object;//RearLightMaterialOff = UMaterialInstanceDynamic::Create(temp_red.Object, nullptr);         //创建动态材质实例//static UMaterialInterface* temp_rearmaterial_on = LoadObject<UMaterialInterface>(nullptr, TEXT("/Game/Materials/Material_Instances/MI_Reflector_RED_Emmisive_low.MI_Reflector_RED_Emmisive_low"));//if (temp_rearmaterial_on == nullptr)if (temp_grey_emmisive.Succeeded() == false)RearLightMaterialOn = nullptr;elseRearLightMaterialOn = temp_grey_emmisive.Object;//RearLightMaterialOn = UMaterialInstanceDynamic::Create(temp_grey_emmisive.Object, nullptr);         //创建动态材质实例
}

VehicleLights(bool position_lights, bool brake_lights, bool reverse_lights)函数,车灯控制函数。

  • position_lights 前后灯开关
  • brake_lights 刹车灯开关
  • reverse_lights 倒车灯开关
void ABaseVehicle::VehicleLights(bool position_lights, bool brake_lights, bool reverse_lights)
{PositionLights = position_lights;UMaterialInstance* brakeLightMaterial = nullptr;UMaterialInstance* reverseLightMaterial = nullptr;UMaterialInstance* frontLightMaterial = nullptr;UMaterialInstance* rearLightMaterial = nullptr;if (position_lights){rearLightMaterial = RearLightMaterialOn;frontLightMaterial = FrontLightMaterialOn;}else{rearLightMaterial = RearLightMaterialOff;frontLightMaterial = FrontLightMaterialOff;}if (reverse_lights){reverseLightMaterial = ReverseLightMaterialOn;}else{reverseLightMaterial = ReverseLightMaterialOff;}if (brake_lights){brakeLightMaterial = BrakeLightMaterialOn;}else{brakeLightMaterial = BrakeLightMaterialOff;}VehicleMesh->SetMaterial(RearLightMaterialID, rearLightMaterial);VehicleMesh->SetMaterial(FrontLightMaterialID, frontLightMaterial);VehicleMesh->SetMaterial(BrakeLightMaterialID, brakeLightMaterial);VehicleMesh->SetMaterial(ReverseLightMaterialID, reverseLightMaterial);FrontLightL->SetVisibility(position_lights);FrontLightR->SetVisibility(position_lights);RearLightL->SetVisibility(position_lights);RearLightR->SetVisibility(position_lights);BrakeLightL->SetVisibility(brake_lights);BrakeLightR->SetVisibility(brake_lights);RearLightL->SetVisibility(reverse_lights);RearLightR->SetVisibility(reverse_lights);
}

BeginPlay()函数中,调用一下 VehicleLights()函数,关闭所有车灯。

void ABaseVehicle::BeginPlay()
{Super::BeginPlay();...VehicleLights(false, false, false);...
}

虚幻引擎5 C++ 汽车车门交互

汽车车门交互-左右门控制 展示:

车门的交互,关注构造函数中的InitDoorComponent()函数。

BaseVehicle.h 中相关车门的定义。

...UENUM(BlueprintType)
enum class EVehicleDoorType : uint8
{EVDT_LeftDoor,                         // 左门EVDT_RightDoor,                            // 右门EVDT_Count
};UENUM(BlueprintType)
enum class EControlDoorType : uint8
{ECDT_OpenDoor,                         // 开门ECDT_CloseDoor,                            // 关门ECDT_Count
};UCLASS()
class UEVEHICLEPROJECT_API ABaseVehicle : public AWheeledVehicle
{GENERATED_BODY()
public:ABaseVehicle();...// 车门控制 UFUNCTION(BlueprintCallable, Category = "VehicleFunc")void VehicleDoorControl(EVehicleDoorType door_type, EControlDoorType door_control);// 车门过程控制 需蓝图实现UFUNCTION(BlueprintImplementableEvent)      void VehicleDoorProcess(EVehicleDoorType door_type, float door_alpha, UObject* anim_bp);...
protected:...virtual void Tick(float DeltaTime) override;...UFUNCTION()void OpenDoorTimeLineCallBack(float interpolatedVal);UFUNCTION()void OpenDoorTimelineFinishedCallback();UFUNCTION()void CloseDoorTimeLineCallBack(float interpolatedVal);UFUNCTION()void CloseDoorTimelineFinishedCallback();UFUNCTION()...void InitDoorComponent();                         // 初始化 车门 组件...
protected:...   // 开关门控制 // 声明TimeLine的CurveFloat(也即函数曲线)UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Door", meta = (AllowPrivateAccess = "true"))UCurveFloat*                                  OpenDoorTimeLineCurve;UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Door", meta = (AllowPrivateAccess = "true"))...UCurveFloat*                                    CloseDoorTimeLineCurve;// 车门控制FTimeline                                     OpenDoorTimeLine;FTimeline                                      CloseDoorTimeLine;EVehicleDoorType                              VehicleDoorType;...
};

InitDoorComponent()函数,车门组件的初始化。
控制车门开关的实现,是用TimeLine来控制动画蓝图实现的,而开关门的动画曲线可以控制开关门的平滑过渡,只是功能的实现,对曲线也没做处理。

void ABaseVehicle::InitDoorComponent()
{FOnTimelineFloat   OpenDoorTimeLineCallBack;FOnTimelineEventStatic OpenDoorTimelineFinishedCallback;OpenDoorTimeLineCallBack.BindUFunction(this, FName{ TEXT("OpenDoorTimeLineCallBack") });OpenDoorTimelineFinishedCallback.BindUFunction(this, FName{ TEXT("OpenDoorTimelineFinishedCallback") });static ConstructorHelpers::FObjectFinder<UCurveFloat> opendoor_curve(TEXT("/Game/Blueprints/Vehicles/Door/OpenDoorTimeLineCurve.OpenDoorTimeLineCurve"));check(opendoor_curve.Succeeded());OpenDoorTimeLineCurve = opendoor_curve.Object;OpenDoorTimeLine.SetLooping(false);OpenDoorTimeLine.SetTimelineLength(1.0f);//OpenDoorTimeLine.SetTimelineLengthMode(ETimelineLengthMode::TL_LastKeyFrame);//OpenDoorTimeLine.SetPlaybackPosition(0.0f, false, false);OpenDoorTimeLine.AddInterpFloat(OpenDoorTimeLineCurve, OpenDoorTimeLineCallBack);OpenDoorTimeLine.SetTimelineFinishedFunc(OpenDoorTimelineFinishedCallback);FOnTimelineFloat        CloseDoorTimeLineCallBack;FOnTimelineEventStatic CloseDoorTimelineFinishedCallback;CloseDoorTimeLineCallBack.BindUFunction(this, FName{ TEXT("CloseDoorTimeLineCallBack") });CloseDoorTimelineFinishedCallback.BindUFunction(this, FName{ TEXT("CloseDoorTimelineFinishedCallback") });static ConstructorHelpers::FObjectFinder<UCurveFloat> closedoor_curve(TEXT("/Game/Blueprints/Vehicles/Door/CloseDoorTimeLineCurve.CloseDoorTimeLineCurve"));check(closedoor_curve.Succeeded());CloseDoorTimeLineCurve = closedoor_curve.Object;CloseDoorTimeLine.SetLooping(false);CloseDoorTimeLine.SetTimelineLength(1.0f);//CloseDoorTimeLine.SetTimelineLengthMode(ETimelineLengthMode::TL_LastKeyFrame);//CloseDoorTimeLine.SetPlaybackPosition(0.0f, false, false);CloseDoorTimeLine.AddInterpFloat(CloseDoorTimeLineCurve, CloseDoorTimeLineCallBack);CloseDoorTimeLine.SetTimelineFinishedFunc(CloseDoorTimelineFinishedCallback);
}

VehicleDoorControl(EVehicleDoorType door_type, EControlDoorType door_control)函数,控制车门的开关。只要启动TimeLine即可。

  • door_type 车门类型(左门、右门)
  • door_control 车门控制(开门、关闭)
void ABaseVehicle::VehicleDoorControl(EVehicleDoorType door_type, EControlDoorType door_control)
{VehicleDoorType = door_type;switch (door_control){case EControlDoorType::ECDT_OpenDoor:OpenDoorTimeLine.PlayFromStart();break;case EControlDoorType::ECDT_CloseDoor:CloseDoorTimeLine.PlayFromStart();break;case EControlDoorType::ECDT_Count:break;default:break;}
}

VehicleDoorProcess(EVehicleDoorType door_type, float door_alpha, UObject* anim_bp)函数,蓝图中实现的。TimeLine的回调函数中调用。

回调函数的实现,
由于后续我只想控制,驾驶位车门的开关,其他门并不想处理,因此我拿一个变量VehicleDoorType记录了当前是那个门的开关,如果想控制多个门还是将回调分开的好一些。

void ABaseVehicle::OpenDoorTimeLineCallBack(float interpolatedVal)
{float alpha = OpenDoorTimeLineCurve->GetFloatValue(interpolatedVal);VehicleDoorProcess(VehicleDoorType, alpha, VehicleMesh->GetAnimInstance());
}void ABaseVehicle::OpenDoorTimelineFinishedCallback()
{}void ABaseVehicle::CloseDoorTimeLineCallBack(float interpolatedVal)
{float alpha = CloseDoorTimeLineCurve->GetFloatValue(interpolatedVal);VehicleDoorProcess(VehicleDoorType, 1-alpha, VehicleMesh->GetAnimInstance());
}void ABaseVehicle::CloseDoorTimelineFinishedCallback()
{}

Tick(float DeltaTime)函数,需要调用开关门的TimeLine的TikeTimeLine()函数。

void ABaseVehicle::Tick(float DeltaTime)
{Super::Tick(DeltaTime);OpenDoorTimeLine.TickTimeline(DeltaTime);CloseDoorTimeLine.TickTimeline(DeltaTime);...
}

虚幻引擎5 C++ 汽车换色交互

汽车换色交互-车身过度换色 展示:

车门的交互,关注构造函数中的InitColorComponent()函数。

BaseVehicle.h 中相关换色的定义。

...UCLASS()
class UEVEHICLEPROJECT_API ABaseVehicle : public AWheeledVehicle
{GENERATED_BODY()
public:ABaseVehicle();...// 车身过度换色UFUNCTION(BlueprintCallable, Category = "VehicleFunc")void VehicleTransitionColor(const FLinearColor& target_color);
protected:...virtual void Tick(float DeltaTime) override;...UFUNCTION()void TransitionColorTimeLineCallback(float interpolatedVal);UFUNCTION()void TransitionColorTimelineFinishedCallback();...void InitColorComponent();                          // 初始化 颜色 组件
protected:...// 车身换色UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VehicleColor", meta = (AllowPrivateAccess = "true"))UCurveFloat*                                 TransitionColorTimeLineCurve;UPROPERTY(VisibleAnywhere, Category = "VehicleColor", meta = (AllowPrivateAccess = "true"))UChildActorComponent*                            WaveStartPoint;UPROPERTY(VisibleAnywhere, Category = "VehicleColor", meta = (AllowPrivateAccess = "true"))float                                          WaveSpeed;UPROPERTY(VisibleAnywhere, Category = "VehicleColor", meta = (AllowPrivateAccess = "true"))float                                           WaveOffsetEndValue;...// 车身换色FTimeline                                      TransitionColorTimeLine;
};

InitColorComponent()函数,换色组件的初始化。
控制车身换色的实现,也是用TimeLine来实现的,只不过控制的是材质实例。

void ABaseVehicle::InitColorComponent()
{WaveStartPoint = CreateDefaultSubobject<UChildActorComponent>(TEXT("WaveStartPoint"));WaveStartPoint->SetRelativeLocation(FVector(127.f, 0.0f, 113.f));WaveStartPoint->SetupAttachment(VehicleMesh);WaveSpeed = 0.5f;WaveOffsetEndValue = 1.0f;FOnTimelineFloat   TransitionColorTimeLineCallBack;FOnTimelineEventStatic TransitionColorTimelineFinishedCallback;TransitionColorTimeLineCallBack.BindUFunction(this, FName{ TEXT("TransitionColorTimeLineCallBack") });TransitionColorTimelineFinishedCallback.BindUFunction(this, FName{ TEXT("TransitionColorTimelineFinishedCallback") });static ConstructorHelpers::FObjectFinder<UCurveFloat> transitioncolor_curve(TEXT("/Game/Blueprints/Vehicles/Color/TransitionColorTimeLineCurve.TransitionColorTimeLineCurve"));check(transitioncolor_curve.Succeeded());TransitionColorTimeLineCurve = transitioncolor_curve.Object;TransitionColorTimeLine.SetLooping(false);TransitionColorTimeLine.SetTimelineLength(1.0f);//TransitionColorTimeLine.SetTimelineLengthMode(ETimelineLengthMode::TL_TimelineLength);//TransitionColorTimeLine.SetPlaybackPosition(0.0f, false, false);TransitionColorTimeLine.AddInterpFloat(TransitionColorTimeLineCurve, TransitionColorTimeLineCallBack);TransitionColorTimeLine.SetTimelineFinishedFunc(TransitionColorTimelineFinishedCallback);
}

VehicleTransitionColor(const FLinearColor& target_color)函数,车身过度换色。
实现方式,该函数获得材质实例中当前车身颜色,然后设置材质实例相关参数,并通过TimeLine修改材质实例参数实现的。
材质的实现这里就不多说了,如果后续有相关UE材质的博客,会考虑写篇文章。原理获取模型顶点然后通过修改材质中的World Positon Offset(世界偏移)来实现。

  • target_color 目标颜色。
void ABaseVehicle::VehicleTransitionColor(const FLinearColor& target_color)
{FVector v_wave_start_point = WaveStartPoint->GetComponentToWorld().GetLocation();float WaveOffset = 0.0f;bool StartWave = true;TArray<class UMaterialInterface*> arrMs = VehicleMesh->GetMaterials();UMaterialInstanceDynamic* mid_body = VehicleMesh->CreateAndSetMaterialInstanceDynamic(0);FName bodyname = mid_body->GetFName();FLinearColor lc_current_color{0.0f, 0.0f, 0.0f};if (mid_body->GetVectorParameterValue(FHashedMaterialParameterInfo(FName{ TEXT("Color2") }), lc_current_color)){//UMaterialInstanceDynamic* mid_body = (UMaterialInstanceDynamic*)(mi_body);mid_body->SetVectorParameterValue(TEXT("WaveStartPoint"), v_wave_start_point);mid_body->SetVectorParameterValue(TEXT("Color1"), lc_current_color);mid_body->SetVectorParameterValue(TEXT("Color2"), target_color);mid_body->SetScalarParameterValue(TEXT("WaveOffset"), WaveOffset);TransitionColorTimeLine.PlayFromStart();}
}

回调函数的实现,通过TimeLine修改材质实例"WaveOffset"参数实现的。

void ABaseVehicle::TransitionColorTimeLineCallback(float interpolatedVal)
{float WaveOffset = TransitionColorTimeLineCurve->GetFloatValue(interpolatedVal);UMaterialInstanceDynamic* mid_body = VehicleMesh->CreateAndSetMaterialInstanceDynamic(0);if (mid_body != nullptr){mid_body->SetScalarParameterValue(TEXT("WaveOffset"), WaveOffset);}
}void ABaseVehicle::TransitionColorTimelineFinishedCallback()
{}

Tick(float DeltaTime)函数,需要调用车身换色的TimeLine的TikeTimeLine()函数。

void ABaseVehicle::Tick(float DeltaTime)
{Super::Tick(DeltaTime);...TransitionColorTimeLine.TickTimeline(DeltaTime);
}

虚幻UnrealEngine5 C++ 汽车基础交互相关推荐

  1. UnrealEngine5实操--基础概念(持续补充)

    UnrealEngine5实操--基础概念 Unreal 术语 UE5 上手指南 关卡快速搭建 视口标准按键操作 Editor 视角移动速度调节 Unreal Editor 快速测距 Actor 操作 ...

  2. 虚幻引擎虚拟现实开发基础学习教程

    流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:3.93 GB |时长:5h 15m 了 ...

  3. 智能汽车基础软件打响「市场争夺战」,TOP10本土供应商抢跑

    基础软件是汽车行业进入软件定义时代的关键一环,也是整个产业链除芯片硬核之外,最基本的底层能力标签.从广义范畴来说,底层硬件BSP.RTOS.OS.AutoSAR以及中间件都属于基础软件赛道. 其中,底 ...

  4. 汽车基础软件「众生相」

    基于SOA的软件架构,标准化基础软件(比如,OS及定制系统).AutoSAR及开发工具.专用中间件形成了域控制器的核心软件平台,已经成为智能汽车的软件新赛道.这其中,一部分供应商可以提供全栈方案,一部 ...

  5. 汽车基础软件赛道正在经历一轮洗牌

    http://www.evinchina.com/newsshow-1733.html 导读:基于SOA的软件架构,标准化基础软件(比如,OS及定制系统).AutoSAR及开发工具.专用中间件形成了域 ...

  6. 虚幻引擎编辑器开发基础(一)

    虚幻引擎编辑器开发基础(一) 文章目录 虚幻引擎编辑器开发基础(一) 一.前言 二.插件与模块 2.1 插件(Plguin) 2.1.1 插件的作用 2.1.2 插件的类型 2.1.3 插件结构 2. ...

  7. 阡陌路-车行天下之汽车基础知识

    阡陌路-车行天下之汽车基础知识 (2013-06-29 10:37:23)转载▼ 标签: 汽车 基础 分类: 指南区 汽车基础知识 1.什么是ABS ABS是Anti-LockBrakeSystem的 ...

  8. js初识、JS基础交互、JavaScript 元素操作

    js初识 js外链引入 外链引入.js 通过script标签的src属性引入外部js文件在外部新建一个后缀名为js的文件注意:用于引入外部js文件的script标签,就不要再写其他的js代码,不会执行 ...

  9. 《中国汽车基础软件发展白皮书2.0》正式发布!(附下载)

    构建汽车产业新生态 2021年9月25-28日,"2021世界智能网联汽车大会"在北京顺利举办,9月26日,中国汽车基础软件生态委员会(以下简称"AUTOSEMO&quo ...

最新文章

  1. python语法大全-python语法大全,python语法手册
  2. Python学到什么程度可以面试工作?
  3. 已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭
  4. PAT1006 换个格式输出整数
  5. 【翻译自mos文章】使用aum( Automatic Undo Management) 时遇到 ORA-01555错误--- 原因和解决方式。...
  6. php显示当前访问人数,PHP与jquery实时显示网站在线人数实例详解
  7. 简述C#中IO的应用 RabbitMQ安装笔记 一次线上问题引发的对于C#中相等判断的思考 ef和mysql使用(一) ASP.NET/MVC/Core的HTTP请求流程...
  8. 安装java没有jdk_安装Java 环境 JDK 最完整配置方法
  9. 从单张图重建三维人体模型综述(二)
  10. 三角函数的思维导图(上)
  11. 各类免费的的机器人仿真软件优缺点汇总
  12. html给文字设置自己下载的字体
  13. mac 装java eclipse_Mac安装Eclipse教程
  14. 解决sublime中文输入问题
  15. 【开源】技术宅硬核跨年,DIY墨水屏日历:自动刷新位置、天气,随机播放2000多条「毒鸡汤」...
  16. 用html做高考加油网页,大学学长制作励志视频为高三学子加油
  17. 蓝底寸照该如何在手机上修改照片底色
  18. 【算法训练营学习笔记-Week06】一遍不懂就多刷几遍
  19. 在html页面引入外部html的方法 (使用第三方插件)
  20. ATSHA204A加密芯片攻略——使用篇

热门文章

  1. STM32串口中 USART_GetITStatus 与 USART_GetFlagStatus的区别
  2. 一张足够长厚5mm的纸折叠多少次高度可以超过珠穆朗玛峰
  3. 源代码的学习(如何学习)
  4. 团队成员分工及绩效评估
  5. 康迈斯多通路基因抗衰老之九:PQQ PRO线粒体能量
  6. Android中自动拦截电话
  7. 线程同步的注解:@ThreadSafe、@Immutable、@NotThreadSafe、@GuardedBy
  8. Visual Studio 卸载 Visual Assist番茄助手
  9. 【Yolact训练自己的数据从实战到调参】
  10. win7怎么升级win10?