场景编辑器Atmospheric Directional Light UI
前言
项目工具需要做个一个可视化调整角度的UI。
这里想参考一下:Atmospheric Directional Lights的UI。
于是,查阅了一下源码,在这做一下记录。
一、相关源码
首先,在编辑器操作中,发现当DirectionalLight勾选了以下开关才可以改变上述UI的方向。
- Atmosphere Sun Light
根据bUsedAsAtmosphereSunLight去查找如何被调用:
在在LevelEditorViewport.cpp文件中,可以追溯到函数:
static UDirectionalLightComponent* GetAtmosphericLight(const uint8 DesiredLightIndex, UWorld* ViewportWorld)
再继续追踪这个函数的使用,有以下几个地方:
在InputKey函数中,发现这个是判断是否开启UI。
在MouseMove中可以看到计算如下:可以大概猜测出,下面计算的是UI的方向。
接着可以看到UI的绘制部分:通过搜索UserIsControllingAtmosphericLightTimer
- FLevelEditorViewportClient::Draw中具体代码如下:
// void FLevelEditorViewportClient::Draw(const FSceneView* View,FPrimitiveDrawInterface* PDI)
if (UserIsControllingAtmosphericLightTimer > 0.0f)
{
// Draw a gizmo helping to figure out where is the light when moving it using a shortcut.
FQuat ViewRotation = FQuat(GetViewRotation());
FVector ViewPosition = GetViewLocation();
const float GizmoDistance = 50.0f;
const float GizmoSideOffset = 15.0f;
const float GizmoRadius = 10.0f;
const float ThicknessLight = 0.05f;
const float ThicknessBold = 0.2f;
// Always draw the gizmo right in in front of the camera with a little side shift.
const FVector X(1.0f, 0.0f, 0.0f);
const FVector Y(0.0f, 1.0f, 0.0f);
const FVector Z(0.0f, 0.0f, 1.0f);
const FVector Base = ViewPosition + GizmoDistance * ViewRotation.GetForwardVector() + GizmoSideOffset * (-ViewRotation.GetUpVector() + ViewRotation.GetRightVector());
// Draw world main axis
FRotator IdentityX(0.0f, 0.0f, 0.0f);
FRotator IdentityY(0.0f, 90.0f, 0.0f);
FRotator IdentityZ(90.0f, 0.0f, 0.0f);
DrawDirectionalArrow(PDI, FQuatRotationTranslationMatrix(FQuat(IdentityX), Base), FColor(255, 0, 0, 127), GizmoRadius, 0.3f, SDPG_World, ThicknessBold);
DrawDirectionalArrow(PDI, FQuatRotationTranslationMatrix(FQuat(IdentityY), Base), FColor(0, 255, 0, 127), GizmoRadius, 0.3f, SDPG_World, ThicknessBold);
DrawDirectionalArrow(PDI, FQuatRotationTranslationMatrix(FQuat(IdentityZ), Base), FColor(0, 0, 255, 127), GizmoRadius, 0.3f, SDPG_World, ThicknessBold);
// Render polar coordinate circles
DrawCircle(PDI, Base, X, Y, FLinearColor(0.2f, 0.2f, 1.0f), GizmoRadius, 32, SDPG_World, ThicknessBold);
DrawCircle(PDI, Base, X, Y, FLinearColor(0.2f, 0.2f, 0.75f), GizmoRadius*0.75f, 32, SDPG_World, ThicknessLight);
DrawCircle(PDI, Base, X, Y, FLinearColor(0.2f, 0.2f, 0.50f), GizmoRadius*0.50f, 32, SDPG_World, ThicknessLight);
DrawCircle(PDI, Base, X, Y, FLinearColor(0.2f, 0.2f, 0.25f), GizmoRadius*0.25f, 32, SDPG_World, ThicknessLight);
DrawArc(PDI, Base, Z, Y, -90.0f, 90.0f, GizmoRadius, 32, FLinearColor(1.0f, 0.2f, 0.2f), SDPG_World);
DrawArc(PDI, Base, Z, X, -90.0f, 90.0f, GizmoRadius, 32, FLinearColor(0.2f, 1.0f, 0.2f), SDPG_World);
// Draw the light incoming light direction. The arrow is offset outward to help depth perception when it intersects with other gizmo elements.
const FLinearColor ArrowColor = -UserControlledAtmosphericLightMatrix.GetRotation().GetForwardVector() * 0.5f + 0.5f;
const FVector ArrowOrigin = Base - UserControlledAtmosphericLightMatrix.GetRotation().GetForwardVector()*GizmoRadius*1.25;
const FQuatRotationTranslationMatrix ArrowToWorld(UserControlledAtmosphericLightMatrix.GetRotation(), ArrowOrigin);
DrawDirectionalArrow(PDI, ArrowToWorld, ArrowColor, GizmoRadius, 0.3f, SDPG_World, ThicknessBold);
// Now draw x, y and z axis to help getting a sense of depth when look at the vectors on screen.
FVector LightArrowTip = -UserControlledAtmosphericLightMatrix.GetRotation().GetForwardVector()*GizmoRadius;
FVector P0 = Base + LightArrowTip * FVector(1.0f, 0.0f, 0.0f);
FVector P1 = Base + LightArrowTip * FVector(1.0f, 1.0f, 0.0f);
FVector P2 = Base + LightArrowTip * FVector(1.0f, 1.0f, 1.0f);
PDI->DrawLine(Base, P0, FLinearColor(1.0f, 0.0f, 0.0f), SDPG_World, ThicknessLight);
PDI->DrawLine(P0, P1, FLinearColor(0.0f, 1.0f, 0.0f), SDPG_World, ThicknessLight);
PDI->DrawLine(P1, P2, FLinearColor(0.0f, 0.0f, 1.0f), SDPG_World, ThicknessLight);
}
小结
- LevelEditorViewport::InputKey,通过热键判断是否开启UI显示。
- LevelEditorViewport::MouseMove,计算鼠标移动,来求得Transform矩阵用于渲染。
- LevelEditorViewport::Draw,渲染调整角度的UI。
通过以上的代码分析,很快可以在场景编辑器中模仿实现一个简单的角度控制的UI。