-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathEnhancedGizmoSceneBinding.cpp
More file actions
282 lines (258 loc) · 12.4 KB
/
Copy pathEnhancedGizmoSceneBinding.cpp
File metadata and controls
282 lines (258 loc) · 12.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#include <atomic>
namespace
{
std::atomic_bool g_collectGizmoColliders{ false };
}
#include "EnhancedGizmoSceneBinding.h"
#include "SceneManager.h"
#include "Scene.h"
#include "Entity.h"
#include "CameraComponent.h"
#include "LightComponent.h"
#include "LightRenderProxy.h"
#include "BoxColliderComponent.h"
#include "SphereColliderComponent.h"
#include "CapsuleColliderComponent.h"
#include "CharacterControllerComponent.h"
#include <mathematics/scalar.hpp>
#include <mathematics/transform.hpp>
#include <algorithm>
#include <cmath>
#include <memory>
namespace
{
// 기즈모가 화면에서 일정 비율을 차지하게 하는 월드 크기. 스냅샷의 FOV
// 계약은 도 단위이고 삼각함수 경계에서만 라디안으로 바꾼다.
float EnhancedGizmoSceneScale(const math::vector3& gizmoPosition,
const FrameCameraSnapshot& snapshot, float targetScreenHeightRatio)
{
const float distanceLength = math::distance(snapshot.eyePosition, gizmoPosition);
const float verticalFovRadians = math::radians(snapshot.fov);
const float screenHeight = 2.0f * distanceLength * tanf(verticalFovRadians * 0.5f);
return screenHeight * targetScreenHeightRatio;
}
math::vector3 EnhancedGizmoTransformScale(const math::matrix4x4& transform)
{
return math::vector3{ math::length(transform.right()),
math::length(transform.up()), math::length(transform.forward()) };
}
}
bool BuildEnhancedGizmoSceneData(const FrameCameraSnapshot& snapshot,
bool collectColliders,
std::shared_ptr<const EnhancedGizmoIconTextures> iconTextures,
EnhancedGizmoLineCollector& lineCollector,
EnhancedGizmoSceneData& out)
{
Scene* activeScene = SceneManagers->GetActiveScene();
if (nullptr == activeScene) return false;
// packet이 raw Texture*를 쓰는 pass 형식과 공유 소유권을 함께 싣는다.
// EditorAssetPresentation이 shutdown되어도 이미 발행된 packet은 안전하다.
out.iconTextures = std::move(iconTextures);
const EnhancedGizmoIconTextures* textures = out.iconTextures.get();
// ── 아이콘 대상 — 카메라·라이트 오브젝트 ──
//
// Scene 구조 변경은 렌더 배리어 안에서만 적용된다. 이 함수가 라이브 렌더
// 스냅샷을 만드는 동안 슬롯 unique_ptr은 이동/파괴되지 않으므로 Scene의
// 단독 소유 배열을 비소유로 직접 읽는다.
{
for (const auto& object : activeScene->m_Entities)
{
if (!object) continue;
Texture* iconTexture = nullptr;
bool isIconTarget = false;
if (nullptr != object->GetComponent<CameraComponent>())
{
// nullptr를 넘기면 캐시의 1x1 흰색 폴백이 알파 0.5인 아이콘
// 크기 사각형으로 보인다. Host가 주입한 실제 자산을 건넨다.
iconTexture = textures ? textures->camera.get() : nullptr;
isIconTarget = true;
++out.cameraIcons;
}
else if (auto* light = object->GetComponent<LightComponent>())
{
constexpr int kMainLightIndex = 0;
const bool isMainLight = (kMainLightIndex == light->m_lightIndex);
switch (light->m_lightType)
{
case DirectionalLight:
iconTexture = isMainLight
? (textures ? textures->mainLight.get() : nullptr)
: (textures ? textures->directionalLight.get() : nullptr);
break;
case PointLight:
iconTexture = textures ? textures->pointLight.get() : nullptr;
break;
case SpotLight:
iconTexture = textures ? textures->spotLight.get() : nullptr;
break;
default:
break;
}
isIconTarget = true;
++out.lightIcons;
}
if (!isIconTarget) continue;
EnhancedGizmoIcon icon{};
icon.position = object->Transform_().GetWorldPosition();
icon.position.y -= 0.5f; // DX11 호출부의 보정 그대로
icon.size = 1.f;
icon.texture = iconTexture;
out.icons.push_back(icon);
}
}
// ── 선택 오브젝트의 기즈모 — DX11 GizmoLinePass의 스위치 그대로 ──
if (auto selectedObject = activeScene->GetSelectedEntity())
{
// ★ E7 — 옛 GameObjectType::Light / ::Camera 검사를 걷었다. 두 분기 다
// 바로 아래에서 이미 해당 컴포넌트를 조회하고 있어 타입 검사가 중복이었다.
// "라이트인가"의 정본은 저장된 enum이 아니라 컴포넌트 보유 여부다
// (K1-a 마스크로 O(1)). 배타(else if)도 함께 풀었다 — 컴포넌트가 정본이면
// 둘 다 가진 오브젝트에 둘 다 그리는 것이 옳고, 저작 자산에 그런 조합은 없다.
{
if (auto* lightComponent = selectedObject->GetComponent<LightComponent>())
{
// ★ 기즈모는 렌더가 받을 값을 그대로 읽는다.
//
// 예전에는 LightComponent::m_direction을 읽었는데, 그 필드는
// OnInitialized의 ApplyLightData가 한 번 채우고 그 뒤로 아무도
// 갱신하지 않는 캐시였다 — 오브젝트를 회전시켜도 기즈모만 초기
// 방향에 굳어 있었다. 조명은 멀쩡했으니 증상이 기즈모에만 났다.
//
// 고치는 방식이 요점이다. 방향식을 여기 한 벌 더 적으면 세 번째
// 사본이 되고, 규약이 바뀔 때 또 어긋난다. 대신 렌더 프록시가
// 읽는 바로 그 함수를 부른다 — 몇 줄 뒤 ProxyCommand가 부를
// 것과 같은 함수이므로 결과가 비트 단위로 같고, 앞으로 방향
// 규약을 바꿔도 ReadFrom 한 곳만 고치면 둘 다 따라온다.
//
// 프록시 **객체**(m_lightProxyMap)를 읽지 않는 이유도 분명하다.
// 이 수집은 게임 스레드에서 프레임 패킷을 만드는 중에 도는데,
// 이번 프레임 커맨드는 아직 CapturePending 전이라 큐에 있다.
// 맵을 뒤지면 한 프레임 늦은 값을 스핀락까지 잡고 읽게 된다.
const LightRenderProxy::Values lightValues =
LightRenderProxy::ReadFrom(lightComponent);
const math::vector3& worldPosition = lightValues.worldPosition;
const math::vector3& lightDirection = lightValues.direction;
const float gizmoScale =
EnhancedGizmoSceneScale(worldPosition, snapshot, 0.05f);
switch (lightValues.lightType)
{
case DirectionalLight:
lineCollector.AddWireCircleWithDirectionLines(worldPosition, gizmoScale,
lightDirection, lightDirection, { 1, 0, 1, 1 });
++out.selectionShapes;
break;
case PointLight:
lineCollector.AddWireSphere(worldPosition, lightValues.range,
{ 1, 1, 0, 1 });
++out.selectionShapes;
break;
case SpotLight:
lineCollector.AddWireCone(worldPosition, lightDirection,
lightValues.range, lightValues.spotLightAngle,
{ 0, 1, 1, 1 });
++out.selectionShapes;
break;
default:
break;
}
}
}
{
if (auto* cameraComponent = selectedObject->GetComponent<CameraComponent>())
{
auto camera = cameraComponent->GetCamera();
if (nullptr != camera && !camera->m_isOrthographic)
{
if (const auto frustum = cameraComponent->TryGetFrustum())
{
lineCollector.AddBoundingFrustum(*frustum, { 1, 0, 1, 1 });
++out.selectionShapes;
}
}
}
}
}
// ── 콜라이더 와이어 — DX11의 디버그 모드 수집 그대로 ──
if (collectColliders)
{
for (auto* box : activeScene->GetBoxColliderComponents())
{
if (!box) continue;
const math::matrix4x4& world = box->GetOwner()->Transform_().GetWorldMatrix();
const math::matrix4x4 offset = math::compose({ 1.f, 1.f, 1.f },
box->GetRotationOffset(), box->GetPositionOffset());
lineCollector.AddWireBox(offset * world,
box->GetExtents(),
{ 1.f, 0.f, 0.f, 1.f });
++out.colliderShapes;
}
for (auto* sphere : activeScene->GetSphereColliderComponents())
{
if (!sphere) continue;
const math::matrix4x4& world = sphere->GetOwner()->Transform_().GetWorldMatrix();
const math::matrix4x4 offset = math::compose({ 1.f, 1.f, 1.f },
sphere->GetRotationOffset(), sphere->GetPositionOffset());
const math::matrix4x4 transformMatrix = offset * world;
const math::vector3 center = transformMatrix.translation();
const math::vector3 scale = EnhancedGizmoTransformScale(transformMatrix);
const float radius =
sphere->GetRadius() * (std::max)({ scale.x, scale.y, scale.z });
lineCollector.AddWireSphere(center, radius, { 0.f, 1.f, 0.f, 1.f });
++out.colliderShapes;
}
for (auto* capsule : activeScene->GetCapsuleColliderComponents())
{
if (!capsule) continue;
const math::matrix4x4& world = capsule->GetOwner()->Transform_().GetWorldMatrix();
const math::matrix4x4 offset = math::compose({ 1.f, 1.f, 1.f },
capsule->GetRotationOffset(), capsule->GetPositionOffset());
const math::matrix4x4 transformMatrix = offset * world;
const math::vector3 scale = EnhancedGizmoTransformScale(transformMatrix);
const float radius = capsule->GetRadius() * (std::max)({ scale.x, scale.z });
const float height = capsule->GetHeight() * scale.y;
lineCollector.AddWireCapsule(transformMatrix, radius, height, { 0.f, 0.f, 1.f, 1.f });
++out.colliderShapes;
}
for (auto* characterController : activeScene->GetCharacterControllerComponents())
{
if (!characterController) continue;
const math::matrix4x4& world =
characterController->GetOwner()->Transform_().GetWorldMatrix();
const math::matrix4x4 offset = math::compose({ 1.f, 1.f, 1.f },
characterController->GetRotationOffset(),
characterController->GetPositionOffset());
const math::matrix4x4 transformMatrix = offset * world;
const math::vector3 scale = EnhancedGizmoTransformScale(transformMatrix);
const float radius =
characterController->m_radius * (std::max)({ scale.x, scale.z });
const float height = characterController->m_height * scale.y;
lineCollector.AddWireCapsule(transformMatrix, radius, height, { 0.f, 1.f, 1.f, 1.f });
++out.colliderShapes;
}
}
return true;
}
bool CaptureEnhancedGizmoSceneData(const FrameCameraSnapshot& snapshot,
bool collectColliders,
std::shared_ptr<const EnhancedGizmoIconTextures> iconTextures,
EnhancedGizmoSceneData& out)
{
// 에디터 패스가 아니라 Core 수집기다(E4-3a) — GT가 표시 계층을
// 인스턴스화하던 마지막 경로가 이것이었다.
EnhancedGizmoLineCollector lineCollector;
if (!BuildEnhancedGizmoSceneData(snapshot, collectColliders,
std::move(iconTextures), lineCollector, out))
{
return false;
}
out.lineVertices = lineCollector.GetVertices();
return true;
}
void SetCollectGizmoColliders(bool enabled) noexcept
{
g_collectGizmoColliders.store(enabled, std::memory_order_release);
}
bool ShouldCollectGizmoColliders() noexcept
{
return g_collectGizmoColliders.load(std::memory_order_acquire);
}