毛毛虫在破茧后,会是美丽的蝴蝶还是扑火的飞蛾?|

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 ActorItr(GetWorld()); ActorItr; ++ActorItr)
{
...
}
如果用不带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 中国大陆许可协议进行许可。

posted @   42今天吃什么  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起