engine: sync editor rendering and ui changes
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
|
||||
#include "Passes/SceneViewportSelectionOutlinePass.h"
|
||||
|
||||
#include "Viewport/SceneViewportShaderPaths.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
@@ -45,7 +41,7 @@ private:
|
||||
} // namespace
|
||||
|
||||
SceneViewportSelectionOutlinePassRenderer::SceneViewportSelectionOutlinePassRenderer()
|
||||
: m_outlinePass(GetSceneViewportObjectIdOutlineShaderPath()) {
|
||||
: m_outlinePass() {
|
||||
}
|
||||
|
||||
void SceneViewportSelectionOutlinePassRenderer::Shutdown() {
|
||||
|
||||
@@ -20,7 +20,10 @@ enum class SceneViewportOverlayDepthMode : uint8_t {
|
||||
|
||||
enum class SceneViewportOverlaySpriteTextureKind : uint8_t {
|
||||
Camera = 0,
|
||||
Light = 1
|
||||
DirectionalLight = 1,
|
||||
PointLight = 2,
|
||||
SpotLight = 3,
|
||||
Light = DirectionalLight
|
||||
};
|
||||
|
||||
enum class SceneViewportOverlayHandleKind : uint8_t {
|
||||
|
||||
@@ -29,12 +29,24 @@ bool DrawSceneViewportSpriteIcon(
|
||||
min,
|
||||
max,
|
||||
UI::EditorTextureIconKind::CameraGizmo);
|
||||
case SceneViewportOverlaySpriteTextureKind::Light:
|
||||
case SceneViewportOverlaySpriteTextureKind::DirectionalLight:
|
||||
return UI::DrawEditorTextureIcon(
|
||||
drawList,
|
||||
min,
|
||||
max,
|
||||
UI::EditorTextureIconKind::MainLightGizmo);
|
||||
UI::EditorTextureIconKind::DirectionalLightGizmo);
|
||||
case SceneViewportOverlaySpriteTextureKind::PointLight:
|
||||
return UI::DrawEditorTextureIcon(
|
||||
drawList,
|
||||
min,
|
||||
max,
|
||||
UI::EditorTextureIconKind::PointLightGizmo);
|
||||
case SceneViewportOverlaySpriteTextureKind::SpotLight:
|
||||
return UI::DrawEditorTextureIcon(
|
||||
drawList,
|
||||
min,
|
||||
max,
|
||||
UI::EditorTextureIconKind::SpotLightGizmo);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,16 @@ inline bool ShouldBeginSceneViewportNavigationDrag(
|
||||
return hasInteractiveViewport && hovered && !activeDrag && !otherDrag && !gizmoActive && clicked;
|
||||
}
|
||||
|
||||
inline bool ShouldBeginSceneViewportHeldNavigationDrag(
|
||||
bool hasInteractiveViewport,
|
||||
bool hovered,
|
||||
bool activeDrag,
|
||||
bool otherDrag,
|
||||
bool gizmoActive,
|
||||
bool buttonDown) {
|
||||
return hasInteractiveViewport && hovered && !activeDrag && !otherDrag && !gizmoActive && buttonDown;
|
||||
}
|
||||
|
||||
inline bool IsSceneViewportPanDragButtonDown(
|
||||
const SceneViewportNavigationRequest& request,
|
||||
int button) {
|
||||
@@ -139,13 +149,21 @@ inline SceneViewportNavigationUpdate UpdateSceneViewportNavigationState(
|
||||
request.state.panDragging,
|
||||
request.gizmoActive,
|
||||
request.clickedRight);
|
||||
update.beginMiddlePanDrag = ShouldBeginSceneViewportNavigationDrag(
|
||||
request.hasInteractiveViewport,
|
||||
request.viewportHovered,
|
||||
request.state.panDragging,
|
||||
request.state.lookDragging,
|
||||
request.gizmoActive,
|
||||
request.clickedMiddle);
|
||||
update.beginMiddlePanDrag =
|
||||
ShouldBeginSceneViewportNavigationDrag(
|
||||
request.hasInteractiveViewport,
|
||||
request.viewportHovered,
|
||||
request.state.panDragging,
|
||||
request.state.lookDragging,
|
||||
request.gizmoActive,
|
||||
request.clickedMiddle) ||
|
||||
ShouldBeginSceneViewportHeldNavigationDrag(
|
||||
request.hasInteractiveViewport,
|
||||
request.viewportHovered,
|
||||
request.state.panDragging,
|
||||
request.state.lookDragging,
|
||||
request.gizmoActive,
|
||||
request.middleMouseDown);
|
||||
update.beginPanDrag = update.beginLeftPanDrag || update.beginMiddlePanDrag;
|
||||
|
||||
if (update.beginLookDrag) {
|
||||
|
||||
@@ -73,6 +73,42 @@ void AppendWorldLine(
|
||||
line.depthMode = depthMode;
|
||||
}
|
||||
|
||||
constexpr Math::Color kSelectedLightHelperColor(1.0f, 0.92f, 0.24f, 1.0f);
|
||||
constexpr float kSelectedLightHelperLineThickness = 1.8f;
|
||||
constexpr size_t kSelectedLightHelperSegmentCount = 32u;
|
||||
|
||||
void AppendWireCircle(
|
||||
SceneViewportOverlayFrameData& frameData,
|
||||
const Math::Vector3& center,
|
||||
const Math::Vector3& basisA,
|
||||
const Math::Vector3& basisB,
|
||||
float radius,
|
||||
const Math::Color& color,
|
||||
float thicknessPixels,
|
||||
SceneViewportOverlayDepthMode depthMode) {
|
||||
const Math::Vector3 axisA = basisA.Normalized();
|
||||
const Math::Vector3 axisB = basisB.Normalized();
|
||||
if (radius <= Math::EPSILON ||
|
||||
axisA.SqrMagnitude() <= Math::EPSILON ||
|
||||
axisB.SqrMagnitude() <= Math::EPSILON) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t segmentIndex = 0; segmentIndex < kSelectedLightHelperSegmentCount; ++segmentIndex) {
|
||||
const float angle0 =
|
||||
static_cast<float>(segmentIndex) / static_cast<float>(kSelectedLightHelperSegmentCount) *
|
||||
Math::PI * 2.0f;
|
||||
const float angle1 =
|
||||
static_cast<float>(segmentIndex + 1u) / static_cast<float>(kSelectedLightHelperSegmentCount) *
|
||||
Math::PI * 2.0f;
|
||||
const Math::Vector3 p0 =
|
||||
center + axisA * std::cos(angle0) * radius + axisB * std::sin(angle0) * radius;
|
||||
const Math::Vector3 p1 =
|
||||
center + axisA * std::cos(angle1) * radius + axisB * std::sin(angle1) * radius;
|
||||
AppendWorldLine(frameData, p0, p1, color, thicknessPixels, depthMode);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendWorldSprite(
|
||||
SceneViewportOverlayFrameData& frameData,
|
||||
const Math::Vector3& worldPosition,
|
||||
@@ -164,6 +200,20 @@ void AppendSceneIconOverlay(
|
||||
projectedPoint.ndcDepth);
|
||||
}
|
||||
|
||||
SceneViewportOverlaySpriteTextureKind ResolveLightSceneIconTextureKind(
|
||||
const Components::LightComponent& light) {
|
||||
switch (light.GetLightType()) {
|
||||
case Components::LightType::Directional:
|
||||
return SceneViewportOverlaySpriteTextureKind::DirectionalLight;
|
||||
case Components::LightType::Point:
|
||||
return SceneViewportOverlaySpriteTextureKind::PointLight;
|
||||
case Components::LightType::Spot:
|
||||
return SceneViewportOverlaySpriteTextureKind::SpotLight;
|
||||
default:
|
||||
return SceneViewportOverlaySpriteTextureKind::DirectionalLight;
|
||||
}
|
||||
}
|
||||
|
||||
void AppendCameraFrustumOverlay(
|
||||
SceneViewportOverlayFrameData& frameData,
|
||||
const Components::CameraComponent& camera,
|
||||
@@ -251,10 +301,10 @@ void AppendDirectionalLightOverlay(
|
||||
}
|
||||
|
||||
const Math::Vector3 position = transform->GetPosition();
|
||||
const Math::Vector3 lightDirection = (transform->GetForward() * -1.0f).Normalized();
|
||||
const Math::Vector3 lightRayDirection = transform->GetForward().Normalized();
|
||||
const Math::Vector3 right = transform->GetRight().Normalized();
|
||||
const Math::Vector3 up = transform->GetUp().Normalized();
|
||||
if (lightDirection.SqrMagnitude() <= Math::EPSILON ||
|
||||
if (lightRayDirection.SqrMagnitude() <= Math::EPSILON ||
|
||||
right.SqrMagnitude() <= Math::EPSILON ||
|
||||
up.SqrMagnitude() <= Math::EPSILON) {
|
||||
return;
|
||||
@@ -265,8 +315,6 @@ void AppendDirectionalLightOverlay(
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr Math::Color kDirectionalLightColor(1.0f, 0.92f, 0.24f, 1.0f);
|
||||
constexpr float kLineThickness = 1.8f;
|
||||
constexpr size_t kRingSegmentCount = 32u;
|
||||
constexpr std::array<float, 6> kRayAngles = {{
|
||||
0.0f,
|
||||
@@ -281,7 +329,7 @@ void AppendDirectionalLightOverlay(
|
||||
const float ringOffset = worldUnitsPerPixel * 54.0f;
|
||||
const float innerRayRadius = ringRadius * 0.52f;
|
||||
const float rayLength = worldUnitsPerPixel * 96.0f;
|
||||
const Math::Vector3 ringCenter = position + lightDirection * ringOffset;
|
||||
const Math::Vector3 ringCenter = position + lightRayDirection * ringOffset;
|
||||
|
||||
for (size_t segmentIndex = 0; segmentIndex < kRingSegmentCount; ++segmentIndex) {
|
||||
const float angle0 =
|
||||
@@ -296,8 +344,8 @@ void AppendDirectionalLightOverlay(
|
||||
frameData,
|
||||
p0,
|
||||
p1,
|
||||
kDirectionalLightColor,
|
||||
kLineThickness,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
}
|
||||
|
||||
@@ -305,15 +353,15 @@ void AppendDirectionalLightOverlay(
|
||||
frameData,
|
||||
position,
|
||||
ringCenter,
|
||||
kDirectionalLightColor,
|
||||
kLineThickness,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
AppendWorldLine(
|
||||
frameData,
|
||||
ringCenter,
|
||||
ringCenter + lightDirection * rayLength,
|
||||
kDirectionalLightColor,
|
||||
kLineThickness,
|
||||
ringCenter + lightRayDirection * rayLength,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
|
||||
for (float angle : kRayAngles) {
|
||||
@@ -322,9 +370,119 @@ void AppendDirectionalLightOverlay(
|
||||
AppendWorldLine(
|
||||
frameData,
|
||||
rayStart,
|
||||
rayStart + lightDirection * rayLength,
|
||||
kDirectionalLightColor,
|
||||
kLineThickness,
|
||||
rayStart + lightRayDirection * rayLength,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendPointLightOverlay(
|
||||
SceneViewportOverlayFrameData& frameData,
|
||||
const Components::GameObject& gameObject,
|
||||
const Components::LightComponent& light) {
|
||||
const Components::TransformComponent* transform = gameObject.GetTransform();
|
||||
if (transform == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Math::Vector3 position = transform->GetPosition();
|
||||
const Math::Vector3 right = transform->GetRight().Normalized();
|
||||
const Math::Vector3 up = transform->GetUp().Normalized();
|
||||
const Math::Vector3 forward = transform->GetForward().Normalized();
|
||||
if (right.SqrMagnitude() <= Math::EPSILON ||
|
||||
up.SqrMagnitude() <= Math::EPSILON ||
|
||||
forward.SqrMagnitude() <= Math::EPSILON) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float range = (std::max)(light.GetRange(), 0.001f);
|
||||
AppendWireCircle(
|
||||
frameData,
|
||||
position,
|
||||
right,
|
||||
up,
|
||||
range,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
AppendWireCircle(
|
||||
frameData,
|
||||
position,
|
||||
right,
|
||||
forward,
|
||||
range,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
AppendWireCircle(
|
||||
frameData,
|
||||
position,
|
||||
up,
|
||||
forward,
|
||||
range,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
}
|
||||
|
||||
void AppendSpotLightOverlay(
|
||||
SceneViewportOverlayFrameData& frameData,
|
||||
const Components::GameObject& gameObject,
|
||||
const Components::LightComponent& light) {
|
||||
const Components::TransformComponent* transform = gameObject.GetTransform();
|
||||
if (transform == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Math::Vector3 position = transform->GetPosition();
|
||||
const Math::Vector3 forward = transform->GetForward().Normalized();
|
||||
const Math::Vector3 right = transform->GetRight().Normalized();
|
||||
const Math::Vector3 up = transform->GetUp().Normalized();
|
||||
if (forward.SqrMagnitude() <= Math::EPSILON ||
|
||||
right.SqrMagnitude() <= Math::EPSILON ||
|
||||
up.SqrMagnitude() <= Math::EPSILON) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float range = (std::max)(light.GetRange(), 0.001f);
|
||||
const float halfAngleRadians =
|
||||
std::clamp(light.GetSpotAngle(), 1.0f, 179.0f) * Math::DEG_TO_RAD * 0.5f;
|
||||
const float coneRadius = std::tan(halfAngleRadians) * range;
|
||||
const Math::Vector3 coneBaseCenter = position + forward * range;
|
||||
|
||||
AppendWorldLine(
|
||||
frameData,
|
||||
position,
|
||||
coneBaseCenter,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
AppendWireCircle(
|
||||
frameData,
|
||||
coneBaseCenter,
|
||||
right,
|
||||
up,
|
||||
coneRadius,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
|
||||
static constexpr std::array<float, 4> kConeEdgeAngles = {{
|
||||
0.0f,
|
||||
Math::PI * 0.5f,
|
||||
Math::PI,
|
||||
Math::PI * 1.5f
|
||||
}};
|
||||
for (float angle : kConeEdgeAngles) {
|
||||
const Math::Vector3 coneEdgePoint =
|
||||
coneBaseCenter + right * std::cos(angle) * coneRadius + up * std::sin(angle) * coneRadius;
|
||||
AppendWorldLine(
|
||||
frameData,
|
||||
position,
|
||||
coneEdgePoint,
|
||||
kSelectedLightHelperColor,
|
||||
kSelectedLightHelperLineThickness,
|
||||
SceneViewportOverlayDepthMode::AlwaysOnTop);
|
||||
}
|
||||
}
|
||||
@@ -421,7 +579,7 @@ public:
|
||||
context.viewportHeight,
|
||||
*gameObject,
|
||||
kLightIconSize,
|
||||
SceneViewportOverlaySpriteTextureKind::Light);
|
||||
ResolveLightSceneIconTextureKind(*light));
|
||||
}
|
||||
|
||||
for (uint64_t entityId : *context.selectedObjectIds) {
|
||||
@@ -435,17 +593,25 @@ public:
|
||||
}
|
||||
|
||||
Components::LightComponent* light = gameObject->GetComponent<Components::LightComponent>();
|
||||
if (light == nullptr ||
|
||||
!light->IsEnabled() ||
|
||||
light->GetLightType() != Components::LightType::Directional) {
|
||||
if (light == nullptr || !light->IsEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AppendDirectionalLightOverlay(
|
||||
frameData,
|
||||
*gameObject,
|
||||
*context.overlay,
|
||||
context.viewportHeight);
|
||||
switch (light->GetLightType()) {
|
||||
case Components::LightType::Directional:
|
||||
AppendDirectionalLightOverlay(
|
||||
frameData,
|
||||
*gameObject,
|
||||
*context.overlay,
|
||||
context.viewportHeight);
|
||||
break;
|
||||
case Components::LightType::Point:
|
||||
AppendPointLightOverlay(frameData, *gameObject, *light);
|
||||
break;
|
||||
case Components::LightType::Spot:
|
||||
AppendSpotLightOverlay(frameData, *gameObject, *light);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,9 +22,11 @@ class RHITexture;
|
||||
|
||||
namespace Editor {
|
||||
|
||||
inline constexpr std::array<SceneViewportOverlaySpriteTextureKind, 2> kSceneViewportOverlaySpriteTextureKinds = {
|
||||
inline constexpr std::array<SceneViewportOverlaySpriteTextureKind, 4> kSceneViewportOverlaySpriteTextureKinds = {
|
||||
SceneViewportOverlaySpriteTextureKind::Camera,
|
||||
SceneViewportOverlaySpriteTextureKind::Light
|
||||
SceneViewportOverlaySpriteTextureKind::DirectionalLight,
|
||||
SceneViewportOverlaySpriteTextureKind::PointLight,
|
||||
SceneViewportOverlaySpriteTextureKind::SpotLight
|
||||
};
|
||||
|
||||
inline constexpr size_t kSceneViewportOverlaySpriteResourceCount =
|
||||
@@ -35,8 +37,12 @@ inline size_t GetSceneViewportOverlaySpriteResourceIndex(
|
||||
switch (textureKind) {
|
||||
case SceneViewportOverlaySpriteTextureKind::Camera:
|
||||
return 0u;
|
||||
case SceneViewportOverlaySpriteTextureKind::Light:
|
||||
case SceneViewportOverlaySpriteTextureKind::DirectionalLight:
|
||||
return 1u;
|
||||
case SceneViewportOverlaySpriteTextureKind::PointLight:
|
||||
return 2u;
|
||||
case SceneViewportOverlaySpriteTextureKind::SpotLight:
|
||||
return 3u;
|
||||
default:
|
||||
return 0u;
|
||||
}
|
||||
@@ -63,8 +69,14 @@ inline SceneViewportOverlaySpriteAssetSpec GetSceneViewportOverlaySpriteAssetSpe
|
||||
case SceneViewportOverlaySpriteTextureKind::Camera:
|
||||
spec.resourcePath = GetSceneViewportCameraGizmoIconPath();
|
||||
break;
|
||||
case SceneViewportOverlaySpriteTextureKind::Light:
|
||||
spec.resourcePath = GetSceneViewportMainLightGizmoIconPath();
|
||||
case SceneViewportOverlaySpriteTextureKind::DirectionalLight:
|
||||
spec.resourcePath = GetSceneViewportDirectionalLightGizmoIconPath();
|
||||
break;
|
||||
case SceneViewportOverlaySpriteTextureKind::PointLight:
|
||||
spec.resourcePath = GetSceneViewportPointLightGizmoIconPath();
|
||||
break;
|
||||
case SceneViewportOverlaySpriteTextureKind::SpotLight:
|
||||
spec.resourcePath = GetSceneViewportSpotLightGizmoIconPath();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -39,22 +39,28 @@ inline Containers::String GetSceneViewportInfiniteGridShaderPath() {
|
||||
"infinite-grid.shader");
|
||||
}
|
||||
|
||||
inline Containers::String GetSceneViewportObjectIdOutlineShaderPath() {
|
||||
return Detail::BuildSceneViewportEditorResourcePath(
|
||||
std::filesystem::path("shaders") /
|
||||
"scene-viewport" /
|
||||
"object-id-outline" /
|
||||
"object-id-outline.shader");
|
||||
}
|
||||
|
||||
inline Containers::String GetSceneViewportCameraGizmoIconPath() {
|
||||
return Detail::BuildSceneViewportEditorResourcePath(
|
||||
std::filesystem::path("Icons") / "camera_gizmo.png");
|
||||
}
|
||||
|
||||
inline Containers::String GetSceneViewportMainLightGizmoIconPath() {
|
||||
inline Containers::String GetSceneViewportDirectionalLightGizmoIconPath() {
|
||||
return Detail::BuildSceneViewportEditorResourcePath(
|
||||
std::filesystem::path("Icons") / "main_light_gizmo.png");
|
||||
std::filesystem::path("Icons") / "directional_light_gizmo.png");
|
||||
}
|
||||
|
||||
inline Containers::String GetSceneViewportPointLightGizmoIconPath() {
|
||||
return Detail::BuildSceneViewportEditorResourcePath(
|
||||
std::filesystem::path("Icons") / "point_light_gizmo.png");
|
||||
}
|
||||
|
||||
inline Containers::String GetSceneViewportSpotLightGizmoIconPath() {
|
||||
return Detail::BuildSceneViewportEditorResourcePath(
|
||||
std::filesystem::path("Icons") / "spot_light_gizmo.png");
|
||||
}
|
||||
|
||||
inline Containers::String GetSceneViewportMainLightGizmoIconPath() {
|
||||
return GetSceneViewportDirectionalLightGizmoIconPath();
|
||||
}
|
||||
|
||||
} // namespace Editor
|
||||
|
||||
Reference in New Issue
Block a user