虚幻UnrealEngine5 C++ 汽车基础交互 您所在的位置:网站首页 ue4飞机仪表盘 虚幻UnrealEngine5 C++ 汽车基础交互

虚幻UnrealEngine5 C++ 汽车基础交互

2024-04-01 03:10| 来源: 网络整理| 查看: 265

虚幻引擎5的抢先体验

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

虚幻引擎5 新功能

先说说,UE5最为亮眼的两大新特性:Lumen 和 Nanite。

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 sm_vehicle(TEXT("/Game/Meshs/Hatchback/Hatchback.Hatchback")); VehicleMesh->SetSkeletalMesh(sm_vehicle.Object); // 设置动画蓝图 static ConstructorHelpers::FObjectFinder 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(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(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(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(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(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(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(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(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 temp_red(TEXT("/Game/Materials/Vehicle/Material_Instances/MI_Reflector_RED.MI_Reflector_RED")); static ConstructorHelpers::FObjectFinder temp_red_emmisive(TEXT("/Game/Materials/Vehicle/Material_Instances/MI_Reflector_RED_Emmisive.MI_Reflector_RED_Emmisive")); static ConstructorHelpers::FObjectFinder temp_grey(TEXT("/Game/Materials/Vehicle/Material_Instances/MI_Reflector_Grey.MI_Reflector_Grey")); static ConstructorHelpers::FObjectFinder 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; else BrakeLightMaterialOff = temp_red.Object; //BrakeLightMaterialOff = UMaterialInstanceDynamic::Create(temp_red.Object, nullptr); //创建动态材质实例 if (temp_red_emmisive.Succeeded() == false) BrakeLightMaterialOn = nullptr; else BrakeLightMaterialOn = temp_red_emmisive.Object; //BrakeLightMaterialOn = UMaterialInstanceDynamic::Create(temp_red_emmisive.Object, nullptr); //创建动态材质实例 /// // 倒车灯材质 ReverseLightMaterialID = 10; if (temp_grey.Succeeded() == false) ReverseLightMaterialOff = nullptr; else ReverseLightMaterialOff = temp_grey.Object; //ReverseLightMaterialOff = UMaterialInstanceDynamic::Create(temp_grey.Object, nullptr); //创建动态材质实例 if (temp_grey_emmisive.Succeeded() == false) ReverseLightMaterialOn = nullptr; else ReverseLightMaterialOn = temp_grey_emmisive.Object; //ReverseLightMaterialOn = UMaterialInstanceDynamic::Create(temp_grey_emmisive.Object, nullptr); //创建动态材质实例 /// // 前灯材质 FrontLightMaterialID = 9; if (temp_grey.Succeeded() == false) FrontLightMaterialOff = nullptr; else FrontLightMaterialOff = temp_grey.Object; //FrontLightMaterialOff = UMaterialInstanceDynamic::Create(temp_grey.Object, nullptr); //创建动态材质实例 if (temp_grey_emmisive.Succeeded() == false) FrontLightMaterialOn = nullptr; else FrontLightMaterialOn = temp_grey_emmisive.Object; //FrontLightMaterialOn = UMaterialInstanceDynamic::Create(temp_grey_emmisive.Object, nullptr); //创建动态材质实例 /// // 尾灯材质 RearLightMaterialID = 11; if (temp_red.Succeeded() == false) RearLightMaterialOff = nullptr; else RearLightMaterialOff = temp_red.Object; //RearLightMaterialOff = UMaterialInstanceDynamic::Create(temp_red.Object, nullptr); //创建动态材质实例 //static UMaterialInterface* temp_rearmaterial_on = LoadObject(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; else RearLightMaterialOn = 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 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 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(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 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 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); }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有