UE知识点
FPlane
UE的平面使用Ax+By+Cz=W表示,当W=0时,表明该Plane过原点;当W>0时,表明Plane正空间不包含原点;当W<0时,表明Plane正空间包含原点。
MS_ALIGN(16) struct FPlane : public FVector { public: /** The w-component. */ float W;//W存储的是Plane上的一点与Normal(法线)的点积。 } FMatrix ViewPlanesMatrix = FMatrix( FPlane(0, 0, 1, 0), //X平面 FPlane(1, 0, 0, 0), //Y平面 FPlane(0, 1, 0, 0), //Z平面 FPlane(0, 0, 0, 1)); //W平面,这个其实就是单纯的满足矩阵的要求,表示是一个点。
一种可以获取物体屏幕坐标的方法:
bool GetActorPosInScreenSpace(const APlayerController* Player, const AActor& Actor, FVector2D& OutScreenPos) { FVector WorldPosition = Actor->GetActorLocation(); ULocalPlayer* const LP = Player ? Player->GetLocalPlayer() : nullptr; if (LP && LP->ViewportClient) { // get the projection data FSceneViewProjectionData ProjectionData; if (LP->GetProjectionData(LP->ViewportClient->Viewport, eSSP_FULL, /*out*/ ProjectionData)) { FMatrix const ViewProjectionMatrix = ProjectionData.ComputeViewProjectionMatrix(); const bool bResult = FSceneView::ProjectWorldToScreen(WorldPosition, ProjectionData.GetConstrainedViewRect(), ViewProjectionMatrix, OutScreenPos); FPlane Result = ViewProjectionMatrix.TransformFVector4(FVector4(WorldPosition, 1.f)); if (Result.W > 0.0f) { // the result of this will be x and y coords in -1..1 projection space const float RHW = 1.0f / Result.W; FPlane PosInScreenSpace = FPlane(Result.X * RHW, Result.Y * RHW, Result.Z * RHW, Result.W); OutScreenPos = FVector2D{ PosInScreenSpace.X, PosInScreenSpace.Y }; return true; } } } OutScreenPos = FVector2D::ZeroVector; return false; }
UE4的投影矩阵
正交矩阵
class FOrthoMatrix : public FMatrix { public: /** * Constructor * * @param Width view space width * @param Height view space height * @param ZScale scale in the Z axis * @param ZOffset offset in the Z axis */ FOrthoMatrix(float Width,float Height,float ZScale,float ZOffset); }; //逆矩阵 class FReversedZOrthoMatrix : public FMatrix { public: FReversedZOrthoMatrix(float Width,float Height,float ZScale,float ZOffset); };
透视矩阵
class FPerspectiveMatrix : public FMatrix { public: // Note: the value of this must match the mirror in Common.usf! #define Z_PRECISION 0.0f /** * Constructor * * @param HalfFOVX Half FOV in the X axis * @param HalfFOVY Half FOV in the Y axis * @param MultFOVX multiplier on the X axis * @param MultFOVY multiplier on the y axis * @param MinZ distance to the near Z plane * @param MaxZ distance to the far Z plane */ FPerspectiveMatrix(float HalfFOVX, float HalfFOVY, float MultFOVX, float MultFOVY, float MinZ, float MaxZ); /** * Constructor * * @param HalfFOV half Field of View in the Y direction * @param Width view space width * @param Height view space height * @param MinZ distance to the near Z plane * @param MaxZ distance to the far Z plane * @note that the FOV you pass in is actually half the FOV, unlike most perspective matrix functions (D3DXMatrixPerspectiveFovLH). */ FPerspectiveMatrix(float HalfFOV, float Width, float Height, float MinZ, float MaxZ); /** * Constructor * * @param HalfFOV half Field of View in the Y direction * @param Width view space width * @param Height view space height * @param MinZ distance to the near Z plane * @note that the FOV you pass in is actually half the FOV, unlike most perspective matrix functions (D3DXMatrixPerspectiveFovLH). */ FPerspectiveMatrix(float HalfFOV, float Width, float Height, float MinZ); }; class FReversedZPerspectiveMatrix : public FMatrix { public: FReversedZPerspectiveMatrix(float HalfFOVX, float HalfFOVY, float MultFOVX, float MultFOVY, float MinZ, float MaxZ); FReversedZPerspectiveMatrix(float HalfFOV, float Width, float Height, float MinZ, float MaxZ); FReversedZPerspectiveMatrix(float HalfFOV, float Width, float Height, float MinZ); };
坐标转换
FMinimalViewInfo MinimalViewInfo = FMinimalViewInfo();//实例化一个视野信息(FMinimalViewInfo),配置以下参数给它 InViewLocation = MinimalViewInfo.Location//相机位置信息; InViewRotation = MinimalViewInfo.Rotation//相机旋转信息; InFOV = MinimalViewInfo.FOV//相机的FOV; InDesiredFOV = MinimalViewInfo.DesiredFOV//相机的FOV; InAspectRatio = MinimalViewInfo.AspectRatio//相机横纵比; FMatrix ViewMatrix; FMatrix ProjectionMatrix; FMatrix ViewProjectionMatrix; //得到了三个转化矩阵 //ViewMatrix:从世界空间转化到摄像机空间的矩阵 //ProjectionMatrix:从摄像机空间转化到裁剪空间的矩阵 //ViewProjectionMatrix: 从世界空间转化到裁剪空间的矩阵,即以上两个矩阵相乘 //计算以上三个矩阵的方法 CalculateViewProjectionMatrices(const FMinimalViewInfo& MinimalViewInfo, FMatrix& OutViewMatrix, FMatrix& OutProjectionMatrix,FMatrix& OutViewProjectionMatrix) { //透视投影矩阵 OutProjectionMatrix = FReversedZPerspectiveMatrix( FMath::Max(0.001f, InFOV) * (float)PI / 360.0f, InAspectRatio, 1.0f, GNearClippingPlane); //正交投影矩阵 const float YScale = 1.0f / InAspectRatio; const float OrthoWidth = MinimalViewInfo.OrthoWidth / 2.0f; const float OrthoHeight = MinimalViewInfo.OrthoWidth / 2.0f * YScale; const float NearPlane = MinimalViewInfo.OrthoNearClipPlane; const float FarPlane = MinimalViewInfo.OrthoFarClipPlane; const float ZScale = 1.0f / (FarPlane - NearPlane); const float ZOffset = -NearPlane; InOutProjectionData.ProjectionMatrix = FReversedZOrthoMatrix( OrthoWidth, OrthoHeight, ZScale, ZOffset ); //ViewRotationMatrix是一个旋转矩阵,可以理解为不包含平移矩阵的ViewMatrix FMatrix ViewRotationMatrix = FInverseRotationMatrix(InViewRotation) * ViewMatrixNormalized; OutViewMatrix = FTranslationMatrix(-InViewLocation) * ViewRotationMatrix; //本质是一个求逆的过程 OutViewProjectionMatrix = OutViewMatrix * OutProjectionMatrix; } UGameplayStatics::GetViewProjectionMatrix(MinimalViewInfo, ViewMatrix, ProjectionMatrix, ViewProjectionMatrix); //得到各个转化矩阵后就可以利用矩阵变换点或者向量了: FVector PosInViewSpace = ViewMatrix.TransformPosition("你想变换的坐标") ; FVector VecInViewSpace = ViewMatrix.TransformVector("你想变换的向量");
实现一个目标指示器
void TargetIndicator(const AActor* Target,const AActor* Player) { if(!Target||!Player) { return; } FVector PlayerLocation = Player->GetActorLocation(); FVector TargetLocation = Target->GetActorLocation(); FRotator ViewRotation = Player->PlayerCameraManager->GetCameraRotation(); FVector OwnerForwardVec = ViewRotation.Vector(); FVector OwnerRightVec = UKismetMathLibrary::GetRightVector(ViewRotation); //蓝图可以用Get Unit Direction节点实现 FVector Direction = (TargetLocation - PlayerLocation).GetSafeNormal2D(); //求向量夹角 float DotForwardValue = FVector::DotProduct(OwnerForwardVec.GetSafeNormal2D(), Direction); float DotRightValue = FVector::DotProduct(OwnerRightVec.GetSafeNormal2D(), Direction); //UE的三角函数分为Radius(Sin()/ASin()),用弧度值来计算,横轴是(0,kPI),纵轴是(0,1) //Degree(DegSin()/DegASin())是用的是角度,例如Sin是 Sin=a/c计算,输入参数是角度,得到的是[0,1] float Angle = UKismetMathLibrary::DegAcos(DotForwardValue); //DotRightValue>0在右边,<0在左边 Angle*=DotRightValue>=0.f?1.f:-1.f;; CanvasPanel_Direction->SetRenderTransformAngle(Angle); }
判断子类
IsChildOf()判断一个UClass是不是另一个UClass的子类,实际上是通过UClass里存的父类的StaticClass做比较,如果不相等,再用父类的父类的StaticClass做比较,直到取不到父类为止。
IsA()判断一个实例是不是子类,比如MyActor实例是不是UObject的子类
MyActor->IsA<UObject>();
CDO类默认对象
一般在StaticClass里取,在蓝图里的修改不会影响它的值
AMyActor::StaticClass()->GetDefaultObject
Subsystem的生命周期
- UEngineSubsystem(继承自 UDynamicSubsystem,UDynamicSubsystem继承自 USubsystem)
- UEngine* GEngine
代表引擎,数量1。 Editor或Runtime模式都是全局唯一,从进程启动开始创建,进程退出时销毁。 - UEngine::Init()
- UEditorSubsystem(继承自 UDynamicSubsystem,UDynamicSubsystem继承自 USubsystem)
- UEditorEngine* GEditor
代表编辑器,数量1。 顾名思义,只在编辑器下存在且全局唯一,从编辑器启动开始创建,到编辑器退出时销毁。 - UGameInstanceSubsystem (继承自 USubsystem)
- UGameInstance* GameInstance
代表一场游戏,数量1。 从游戏的启动开始创建,游戏退出时销毁。这里的一场游戏指的是Runtime或PIE模式的运行的都算,一场游戏里可能会创建多个World切换。 - UWorldSubsystem (继承自 USubsystem)
- UWorld* World
代表一个世界,数量可能>1。其生命周期,跟GameMode是一起的。(EWorldType:Game,Editor,PIE,EditorPreview,GamePreview等 ) - ULocalPlayerSubsystem (继承自 USubsystem)
- ULocalPlayer* LocalPlayer:代表本地玩家,数量可能>1。
UE支持本地分屏多玩家类型的游戏,但往往最常见的是就只有一个。LocalPlayer虽然往往跟PlayerController一起访问,但是其生命周期其实是跟UGameInstance一起的(默认一开始的时候就创建好一定数量的本地玩家),或者更准确的说是跟LocalPlayer的具体数量挂钩(当然你也可以运行时动态调用AddLocalPlayer)。
UMG
UserWidget
整个用户界面,以树状结构存储
Panel Widget
不会渲染出来,用来对子类Widget布局,例如Canvas Panel
Common Widget
常用的一些Widget控件,如:Text,Button这些,它们会被渲染出来
RetainerBox
两个作用 第一,控制UI更新频率,Pase=0,Pase Count=2,在60HZ游戏中,RetainerBox容器内的UI每秒更新30次(Render on Phase开启才有效);第二,把渲染后的UI当成Texture
Invalidation Box(无效化方框)
任何被无效化方框缓存的控件都不会进行预处理(pre-passed)、更新或绘制。目前的UI界面默认每一帧对每一个控件都会渲染。如果控件只是偶尔变动,就可以将它们放置在无效化方框中进行缓存,这样就不会在绘制、更新或预通道(prepass)中处理它们。
有几个重要属性
CanCache:true方框内所有子控件可更新,false不可更新。
Cache Relative Transforms:如果无效化方框经常改变位置,可以勾上。
Is Volatile:如果为真,会防止控件或其子控件的几何体或布局信息被缓存。如果控件会逐帧发生改变,但你仍希望该控件处于无效面板中,应该将其设置为"易变",而不是每帧对它进行无效化处理(后者会导致无效面板无法缓存任何内容)。
遍历场景中的物体
以Character为例
for (TActorIterator
{
...
}
如果用不带GetWorld()的方式遍历,当编辑器中打开蓝图后(双击蓝图),该蓝图也会出被遍历出来。
BP和BP_C
BP:以.uasset为后缀的文件,是蓝图的设计文件,蓝图在这里进行编辑
BP_C:蓝图在运行时生成的类,实际上引擎使用的是这个类
可以把BP理解为修改器,可以对BP_C进行修改,所以每次编译完BP保存才会在BP_C里面生效
PIE、EditorGame和Game的区别
PIE:Play In Editor,一般的编辑器启动点击play
同一个进程,可能有多个GameInstance,很多时候不能用传统单例,就是因为这个模式
资产的加载和反序列化走Editor模式,可以直接读取Editor资产,不用Cook
GC走Editor体系,代码有大量编辑器逻辑,可能影响垃圾回收
EditorGame:可以直接打开游戏
只有一个GameInstance
资产加载和PIE一样
GC走发布体系,基本和最终发布的游戏一致
Game:正常打不开,需要打一次包,然后用Sandbox参数,命令行输入-Sandbox="打包的路径",就可以调试发布版本了
只有一个GameInstance
需要Cooked资产
GC完全和发布的游戏一致
参考链接
找不到了,侵删
本文作者:42今天吃什么
本文链接:https://www.cnblogs.com/forty-two/p/18689633
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理