1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "render_system.h"
17
18 #include <algorithm>
19
20 #if (CORE3D_VALIDATION_ENABLED == 1)
21 #include <cinttypes>
22 #include <string>
23 #endif
24
25 #include <3d/ecs/components/camera_component.h>
26 #include <3d/ecs/components/dynamic_environment_blender_component.h>
27 #include <3d/ecs/components/environment_component.h>
28 #include <3d/ecs/components/fog_component.h>
29 #include <3d/ecs/components/joint_matrices_component.h>
30 #include <3d/ecs/components/layer_component.h>
31 #include <3d/ecs/components/light_component.h>
32 #include <3d/ecs/components/material_component.h>
33 #include <3d/ecs/components/mesh_component.h>
34 #include <3d/ecs/components/name_component.h>
35 #include <3d/ecs/components/node_component.h>
36 #include <3d/ecs/components/planar_reflection_component.h>
37 #include <3d/ecs/components/post_process_component.h>
38 #include <3d/ecs/components/post_process_configuration_component.h>
39 #include <3d/ecs/components/reflection_probe_component.h>
40 #include <3d/ecs/components/render_configuration_component.h>
41 #include <3d/ecs/components/render_handle_component.h>
42 #include <3d/ecs/components/render_mesh_component.h>
43 #include <3d/ecs/components/skin_component.h>
44 #include <3d/ecs/components/skin_joints_component.h>
45 #include <3d/ecs/components/uri_component.h>
46 #include <3d/ecs/components/world_matrix_component.h>
47 #include <3d/ecs/systems/intf_node_system.h>
48 #include <3d/ecs/systems/intf_render_preprocessor_system.h>
49 #include <3d/ecs/systems/intf_skinning_system.h>
50 #include <3d/implementation_uids.h>
51 #include <3d/intf_graphics_context.h>
52 #include <3d/render/intf_render_data_store_default_camera.h>
53 #include <3d/render/intf_render_data_store_default_light.h>
54 #include <3d/render/intf_render_data_store_default_material.h>
55 #include <3d/render/intf_render_data_store_default_scene.h>
56 #include <3d/util/intf_mesh_util.h>
57 #include <3d/util/intf_picking.h>
58 #include <3d/util/intf_render_util.h>
59 #include <base/containers/string.h>
60 #include <base/math/float_packer.h>
61 #include <base/math/matrix_util.h>
62 #include <base/math/quaternion_util.h>
63 #include <base/math/vector.h>
64 #include <base/math/vector_util.h>
65 #include <core/ecs/intf_ecs.h>
66 #include <core/ecs/intf_entity_manager.h>
67 #include <core/implementation_uids.h>
68 #include <core/intf_engine.h>
69 #include <core/log.h>
70 #include <core/namespace.h>
71 #include <core/perf/cpu_perf_scope.h>
72 #include <core/perf/intf_performance_data_manager.h>
73 #include <core/plugin/intf_plugin_register.h>
74 #include <core/property_tools/property_api_impl.inl>
75 #include <core/property_tools/property_macros.h>
76 #include <core/util/intf_frustum_util.h>
77 #include <render/datastore/intf_render_data_store_manager.h>
78 #include <render/datastore/intf_render_data_store_pod.h>
79 #include <render/datastore/intf_render_data_store_post_process.h>
80 #include <render/datastore/render_data_store_render_pods.h>
81 #include <render/device/intf_gpu_resource_manager.h>
82 #include <render/device/intf_shader_manager.h>
83 #include <render/device/pipeline_state_desc.h>
84 #include <render/implementation_uids.h>
85 #include <render/intf_render_context.h>
86 #include <render/nodecontext/intf_render_node_graph_manager.h>
87 #include <render/resource_handle.h>
88
89 #include "ecs/components/previous_joint_matrices_component.h"
90 #include "ecs/systems/render_preprocessor_system.h"
91 #include "util/component_util_functions.h"
92 #include "util/log.h"
93 #include "util/mesh_util.h"
94 #include "util/scene_util.h"
95 #include "util/uri_lookup.h"
96
97 CORE_BEGIN_NAMESPACE()
98 DECLARE_PROPERTY_TYPE(RENDER_NS::IRenderDataStoreManager*);
99 CORE_END_NAMESPACE()
100
101 CORE3D_BEGIN_NAMESPACE()
102 using namespace RENDER_NS;
103 using namespace BASE_NS;
104 using namespace CORE_NS;
105
106 namespace {
107 static const RenderSubmeshWithHandleReference INIT {};
108 static constexpr uint32_t NEEDS_COLOR_PRE_PASS { 1u << 0u };
109 static constexpr uint64_t SHADOW_CAMERA_START_UNIQUE_ID { 100 };
110 #if (CORE3D_VALIDATION_ENABLED == 1)
111 static constexpr uint32_t MAX_BATCH_SUBMESH_COUNT { 64u };
112 #endif
113
114 static constexpr uint32_t MAX_BATCH_OBJECT_COUNT { PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE /
115 PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
116
117 // typename for POD data. (e.g. "PostProcess") (core/render/intf_render_data_store_pod.h)
118 static constexpr string_view POST_PROCESS_NAME { "PostProcess" };
119 static constexpr string_view POD_DATA_STORE_NAME { "RenderDataStorePod" };
120 static constexpr string_view PP_DATA_STORE_NAME { "RenderDataStorePostProcess" };
121
122 // In addition to the base our renderableQuery has two required components and three optional components:
123 // (0) RenderMeshComponent
124 // (1) WorldMatrixComponent
125 // (2) PreviousWorldMatrixComponent
126 // (3) LayerComponent (optional)
127 // (4) JointMatrixComponent (optional)
128 // (5) PreviousJointMatrixComponent (optional)
129 static constexpr const auto RQ_RMC = 0U;
130 static constexpr const auto RQ_WM = 1U;
131 static constexpr const auto RQ_L = 2U;
132 static constexpr const auto RQ_JM = 3U;
133 static constexpr const auto RQ_PJM = 4U;
134
FillShaderData(IEntityManager & em,IUriComponentManager & uriManager,IRenderHandleComponentManager & renderHandleMgr,const IShaderManager & shaderMgr,const string_view renderSlot,RenderSystem::DefaultMaterialShaderData::SingleShaderData & shaderData)135 void FillShaderData(IEntityManager& em, IUriComponentManager& uriManager,
136 IRenderHandleComponentManager& renderHandleMgr, const IShaderManager& shaderMgr, const string_view renderSlot,
137 RenderSystem::DefaultMaterialShaderData::SingleShaderData& shaderData)
138 {
139 const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(renderSlot);
140 const IShaderManager::RenderSlotData rsd = shaderMgr.GetRenderSlotData(renderSlotId);
141
142 auto uri = "3dshaders://" + renderSlot;
143 auto resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
144 if (!EntityUtil::IsValid(resourceEntity)) {
145 resourceEntity = em.Create();
146 renderHandleMgr.Create(resourceEntity);
147 renderHandleMgr.Write(resourceEntity)->reference = rsd.shader;
148 uriManager.Create(resourceEntity);
149 uriManager.Write(resourceEntity)->uri = uri;
150 }
151 shaderData.shader = em.GetReferenceCounted(resourceEntity);
152
153 uri = "3dshaderstates://";
154 uri += renderSlot;
155 resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
156 if (!EntityUtil::IsValid(resourceEntity)) {
157 resourceEntity = em.Create();
158 renderHandleMgr.Create(resourceEntity);
159 renderHandleMgr.Write(resourceEntity)->reference = rsd.graphicsState;
160 uriManager.Create(resourceEntity);
161 uriManager.Write(resourceEntity)->uri = uri;
162 }
163 shaderData.gfxState = em.GetReferenceCounted(resourceEntity);
164
165 uri += "_DBL";
166 resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
167 if (!EntityUtil::IsValid(resourceEntity)) {
168 // fetch double sided mode (no culling gfx state) (NOTE: could be fetched with name)
169 if (rsd.graphicsState) {
170 GraphicsState gfxState = shaderMgr.GetGraphicsState(rsd.graphicsState);
171 gfxState.rasterizationState.cullModeFlags = CullModeFlagBits::CORE_CULL_MODE_NONE;
172 const uint64_t gfxStateHash = shaderMgr.HashGraphicsState(gfxState);
173 auto handlDbl = shaderMgr.GetGraphicsStateHandleByHash(gfxStateHash);
174 if (handlDbl) {
175 resourceEntity = em.Create();
176 renderHandleMgr.Create(resourceEntity);
177 renderHandleMgr.Write(resourceEntity)->reference = handlDbl;
178 uriManager.Create(resourceEntity);
179 uriManager.Write(resourceEntity)->uri = uri;
180 }
181 }
182 }
183 shaderData.gfxStateDoubleSided = em.GetReferenceCounted(resourceEntity);
184 }
185
CreateReflectionPlaneGpuImageDesc(bool depthImage)186 constexpr GpuImageDesc CreateReflectionPlaneGpuImageDesc(bool depthImage)
187 {
188 GpuImageDesc desc;
189 desc.depth = 1;
190 desc.format = depthImage ? Format::BASE_FORMAT_D16_UNORM : Format::BASE_FORMAT_B10G11R11_UFLOAT_PACK32;
191 desc.memoryPropertyFlags =
192 depthImage ? MemoryPropertyFlags(MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
193 MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
194 : MemoryPropertyFlags(MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
195 desc.usageFlags = depthImage ? ImageUsageFlags(ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
196 ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)
197 : ImageUsageFlags(ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
198 ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT);
199 desc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
200 desc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
201 desc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
202 desc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
203 return desc;
204 }
205
GetRenderCameraFlagsFromComponentFlags(const uint32_t pipelineFlags)206 constexpr uint32_t GetRenderCameraFlagsFromComponentFlags(const uint32_t pipelineFlags)
207 {
208 uint32_t flags = 0;
209 if (pipelineFlags & CameraComponent::PipelineFlagBits::MSAA_BIT) {
210 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT;
211 }
212 if (pipelineFlags & CameraComponent::PipelineFlagBits::CLEAR_DEPTH_BIT) {
213 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_CLEAR_DEPTH_BIT;
214 }
215 if (pipelineFlags & CameraComponent::PipelineFlagBits::CLEAR_COLOR_BIT) {
216 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_CLEAR_COLOR_BIT;
217 }
218 if (pipelineFlags & CameraComponent::PipelineFlagBits::HISTORY_BIT) {
219 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_HISTORY_BIT;
220 }
221 if (pipelineFlags & CameraComponent::PipelineFlagBits::JITTER_BIT) {
222 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_JITTER_BIT;
223 }
224 if (pipelineFlags & CameraComponent::PipelineFlagBits::VELOCITY_OUTPUT_BIT) {
225 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_VELOCITY_NORMAL_BIT;
226 }
227 if (pipelineFlags & CameraComponent::PipelineFlagBits::DEPTH_OUTPUT_BIT) {
228 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_DEPTH_BIT;
229 }
230 if (pipelineFlags & CameraComponent::PipelineFlagBits::MULTI_VIEW_ONLY_BIT) {
231 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_MULTI_VIEW_ONLY_BIT;
232 }
233 if ((pipelineFlags & CameraComponent::PipelineFlagBits::DISALLOW_REFLECTION_BIT) == 0U) {
234 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_ALLOW_REFLECTION_BIT;
235 }
236 if (pipelineFlags & CameraComponent::PipelineFlagBits::CUBEMAP_BIT) {
237 flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_CUBEMAP_BIT;
238 }
239 // NOTE: color pre pass bit is not currently enabled from here
240 return flags;
241 }
242
GetRenderCameraCullTypeFromComponent(const CameraComponent::Culling cameraCullType)243 constexpr inline RenderCamera::CameraCullType GetRenderCameraCullTypeFromComponent(
244 const CameraComponent::Culling cameraCullType)
245 {
246 RenderCamera::CameraCullType cullType(RenderCamera::CameraCullType::CAMERA_CULL_NONE);
247 if (cameraCullType == CameraComponent::Culling::VIEW_FRUSTUM) {
248 cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
249 }
250 return cullType;
251 }
252
GetRenderCameraRenderPipelineTypeFromComponent(const CameraComponent::RenderingPipeline cameraRenderPipelineType)253 constexpr inline RenderCamera::RenderPipelineType GetRenderCameraRenderPipelineTypeFromComponent(
254 const CameraComponent::RenderingPipeline cameraRenderPipelineType)
255 {
256 RenderCamera::RenderPipelineType pipelineType(RenderCamera::RenderPipelineType::FORWARD);
257 if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::LIGHT_FORWARD) {
258 pipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
259 } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::FORWARD) {
260 pipelineType = RenderCamera::RenderPipelineType::FORWARD;
261 } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::DEFERRED) {
262 pipelineType = RenderCamera::RenderPipelineType::DEFERRED;
263 } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::CUSTOM) {
264 pipelineType = RenderCamera::RenderPipelineType::CUSTOM;
265 }
266 return pipelineType;
267 }
268
ValidateRenderCamera(RenderCamera & camera)269 void ValidateRenderCamera(RenderCamera& camera)
270 {
271 if (camera.renderPipelineType == RenderCamera::RenderPipelineType::DEFERRED) {
272 if (camera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT) {
273 camera.flags = camera.flags & (~RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT);
274 #if (CORE3D_VALIDATION_ENABLED == 1)
275 CORE_LOG_ONCE_I("valid_r_c" + to_string(camera.id),
276 "MSAA flag with deferred pipeline dropped (cam id %" PRIu64 ")", camera.id);
277 #endif
278 }
279 }
280 }
281
GetPostProcessName(const IPostProcessComponentManager * postProcessMgr,const IPostProcessConfigurationComponentManager * postProcessConfigMgr,const INameComponentManager * nameMgr,const string_view sceneName,const Entity & entity)282 fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> GetPostProcessName(
283 const IPostProcessComponentManager* postProcessMgr,
284 const IPostProcessConfigurationComponentManager* postProcessConfigMgr, const INameComponentManager* nameMgr,
285 const string_view sceneName, const Entity& entity)
286 {
287 if (postProcessMgr && postProcessConfigMgr && nameMgr) {
288 if (postProcessMgr->HasComponent(entity) || postProcessConfigMgr->HasComponent(entity)) {
289 if (ScopedHandle<const NameComponent> nameHandle = nameMgr->Read(entity);
290 nameHandle && (!nameHandle->name.empty())) {
291 return fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> { nameHandle->name };
292 } else {
293 // checks if any of the post process mgrs has valid entity for camera
294 fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> ret =
295 DefaultMaterialCameraConstants::CAMERA_POST_PROCESS_PREFIX_NAME;
296 ret.append(sceneName);
297 ret.append(to_hex(entity.id));
298 return ret;
299 }
300 }
301 }
302 return (DefaultMaterialCameraConstants::CAMERA_POST_PROCESS_PREFIX_NAME);
303 }
304
GetPostProcessRenderNodeGraph(const IPostProcessConfigurationComponentManager * postProcessConfigMgr,const Entity & entity)305 string GetPostProcessRenderNodeGraph(
306 const IPostProcessConfigurationComponentManager* postProcessConfigMgr, const Entity& entity)
307 {
308 if (postProcessConfigMgr) {
309 if (const auto handle = postProcessConfigMgr->Read(entity); handle) {
310 return handle->customRenderNodeGraphFile;
311 }
312 }
313 return {};
314 }
315
GetCameraName(INameComponentManager & nameMgr,const Entity & entity)316 inline fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> GetCameraName(
317 INameComponentManager& nameMgr, const Entity& entity)
318 {
319 fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> ret;
320 if (ScopedHandle<const NameComponent> nameHandle = nameMgr.Read(entity);
321 nameHandle && (!nameHandle->name.empty())) {
322 ret.append(nameHandle->name);
323 } else {
324 ret.append(to_hex(entity.id));
325 }
326 return ret;
327 }
328
329 // does not update all the variables
FillRenderCameraBaseFromCameraComponent(const IRenderHandleComponentManager & renderHandleMgr,const ICameraComponentManager & cameraMgr,const IGpuResourceManager & gpuResourceMgr,const CameraComponent & cc,RenderCamera & renderCamera,const bool checkCustomTargets)330 void FillRenderCameraBaseFromCameraComponent(const IRenderHandleComponentManager& renderHandleMgr,
331 const ICameraComponentManager& cameraMgr, const IGpuResourceManager& gpuResourceMgr, const CameraComponent& cc,
332 RenderCamera& renderCamera, const bool checkCustomTargets)
333 {
334 renderCamera.layerMask = cc.layerMask;
335 renderCamera.viewport = { cc.viewport[0u], cc.viewport[1u], cc.viewport[2u], cc.viewport[3u] };
336 renderCamera.scissor = { cc.scissor[0u], cc.scissor[1u], cc.scissor[2u], cc.scissor[3u] };
337 // if component has a non-zero resolution use it.
338 if (cc.renderResolution[0u] && cc.renderResolution[1u]) {
339 renderCamera.renderResolution = { cc.renderResolution[0u], cc.renderResolution[1u] };
340 } else {
341 // otherwise check if render target is known, either a custom target or default backbuffer for main camera.
342 RenderHandleReference target;
343 if (checkCustomTargets && !cc.customColorTargets.empty()) {
344 target = renderHandleMgr.GetRenderHandleReference(cc.customColorTargets[0]);
345 } else if (cc.customDepthTarget) {
346 target = renderHandleMgr.GetRenderHandleReference(cc.customDepthTarget);
347 } else if (cc.sceneFlags & CameraComponent::MAIN_CAMERA_BIT) {
348 target = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_BACKBUFFER");
349 }
350 if (target) {
351 const auto& imageDesc = gpuResourceMgr.GetImageDescriptor(target);
352 renderCamera.renderResolution = { imageDesc.width, imageDesc.height };
353 #if (CORE3D_VALIDATION_ENABLED == 1)
354 CORE_LOG_ONCE_E(to_hex(cameraMgr.GetEcs().GetId()) + "_render_system",
355 "CORE3D_VALIDATION: camera render resolution resized to match target %ux%u",
356 renderCamera.renderResolution.x, renderCamera.renderResolution.y);
357 #endif
358 }
359 }
360
361 renderCamera.zNear = cc.zNear;
362 renderCamera.zFar = cc.zFar;
363 renderCamera.flags = GetRenderCameraFlagsFromComponentFlags(cc.pipelineFlags);
364 renderCamera.clearDepthStencil = { cc.clearDepthValue, 0u };
365 renderCamera.clearColorValues = { cc.clearColorValue.x, cc.clearColorValue.y, cc.clearColorValue.z,
366 cc.clearColorValue.w };
367 renderCamera.cullType = GetRenderCameraCullTypeFromComponent(cc.culling);
368 renderCamera.renderPipelineType = GetRenderCameraRenderPipelineTypeFromComponent(cc.renderingPipeline);
369 renderCamera.msaaSampleCountFlags = static_cast<SampleCountFlags>(cc.msaaSampleCount);
370 if (cc.customRenderNodeGraph) {
371 renderCamera.customRenderNodeGraph = renderHandleMgr.GetRenderHandleReference(cc.customRenderNodeGraph);
372 }
373 renderCamera.customRenderNodeGraphFile = cc.customRenderNodeGraphFile;
374 const uint32_t maxCount = BASE_NS::Math::min(static_cast<uint32_t>(cc.colorTargetCustomization.size()),
375 RenderSceneDataConstants::MAX_CAMERA_COLOR_TARGET_COUNT);
376 for (uint32_t idx = 0; idx < maxCount; ++idx) {
377 renderCamera.colorTargetCustomization[idx].format = cc.colorTargetCustomization[idx].format;
378 renderCamera.colorTargetCustomization[idx].usageFlags = cc.colorTargetCustomization[idx].usageFlags;
379 }
380 renderCamera.depthTargetCustomization.format = cc.depthTargetCustomization.format;
381 renderCamera.depthTargetCustomization.usageFlags = cc.depthTargetCustomization.usageFlags;
382
383 if (checkCustomTargets && (!cc.customColorTargets.empty() || cc.customDepthTarget)) {
384 renderCamera.flags |= RenderCamera::CAMERA_FLAG_CUSTOM_TARGETS_BIT;
385 RenderHandleReference customColorTarget;
386 if (cc.customColorTargets.size() > 0) {
387 customColorTarget = renderHandleMgr.GetRenderHandleReference(cc.customColorTargets[0]);
388 }
389 RenderHandleReference customDepthTarget = renderHandleMgr.GetRenderHandleReference(cc.customDepthTarget);
390 if (customColorTarget.GetHandleType() != RenderHandleType::GPU_IMAGE) {
391 CORE_LOG_E("invalid custom render target(s) for camera (%s)", renderCamera.name.c_str());
392 }
393 renderCamera.depthTarget = move(customDepthTarget);
394 renderCamera.colorTargets[0u] = move(customColorTarget);
395 }
396
397 const uint32_t maxMvCount = Math::min(
398 RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT, static_cast<uint32_t>(cc.multiViewCameras.size()));
399 renderCamera.multiViewCameraHash = 0U;
400 for (uint32_t idx = 0; idx < maxMvCount; ++idx) {
401 const auto& mvRef = cc.multiViewCameras[idx];
402 if (auto otherCamera = cameraMgr.Read(mvRef)) {
403 if ((otherCamera->sceneFlags & (CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT |
404 CameraComponent::SceneFlagBits::MAIN_CAMERA_BIT)) &&
405 (otherCamera->pipelineFlags & CameraComponent::PipelineFlagBits::MULTI_VIEW_ONLY_BIT)) {
406 renderCamera.multiViewCameraIds[renderCamera.multiViewCameraCount++] = mvRef.id;
407 HashCombine(renderCamera.multiViewCameraHash, mvRef.id);
408 }
409 }
410 }
411 if ((renderCamera.multiViewCameraCount > 0U) ||
412 (renderCamera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_MULTI_VIEW_ONLY_BIT)) {
413 if (renderCamera.renderPipelineType == RenderCamera::RenderPipelineType::LIGHT_FORWARD) {
414 #if (CORE3D_VALIDATION_ENABLED == 1)
415 CORE_LOG_ONCE_I(to_string(renderCamera.id) + "camera_pipeline_mv",
416 "Camera rendering pipeline cannot be LIGHT_FORWARD for multi-view (changing to FORWARD internally).");
417 #endif
418 renderCamera.renderPipelineType = RenderCamera::RenderPipelineType::FORWARD;
419 }
420 }
421
422 ValidateRenderCamera(renderCamera);
423 }
424
CreateColorPrePassRenderCamera(const IRenderHandleComponentManager & renderHandleMgr,const ICameraComponentManager & cameraMgr,const IGpuResourceManager & gpuResourceMgr,const RenderCamera & baseCamera,const Entity & prePassEntity,const uint64_t uniqueId)425 RenderCamera CreateColorPrePassRenderCamera(const IRenderHandleComponentManager& renderHandleMgr,
426 const ICameraComponentManager& cameraMgr, const IGpuResourceManager& gpuResourceMgr, const RenderCamera& baseCamera,
427 const Entity& prePassEntity, const uint64_t uniqueId)
428 {
429 RenderCamera rc = baseCamera;
430 rc.mainCameraId = baseCamera.id; // main camera for pre-pass
431 // reset targets, pre-pass does not support custom targets nor uses main camera targets
432 rc.depthTarget = {};
433 for (uint32_t idx = 0; idx < countof(rc.colorTargets); ++idx) {
434 rc.colorTargets[idx] = {};
435 }
436 // NOTE: LIGHT_FORWARD prevents additional HDR target creation
437 rc.renderPipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
438 // by default these cannot be resolved for the pre-pass camera
439 // FillRenderCameraBaseFromCameraComponent handles these for actual pre-pass cameras
440 rc.customRenderNodeGraphFile.clear();
441 rc.customRenderNodeGraph = {};
442 if (const auto prePassCameraHandle = cameraMgr.Read(prePassEntity); prePassCameraHandle) {
443 FillRenderCameraBaseFromCameraComponent(
444 renderHandleMgr, cameraMgr, gpuResourceMgr, *prePassCameraHandle, rc, false);
445 rc.flags |= RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT | RenderCamera::CAMERA_FLAG_OPAQUE_BIT |
446 RenderCamera::CAMERA_FLAG_CLEAR_DEPTH_BIT | RenderCamera::CAMERA_FLAG_CLEAR_COLOR_BIT;
447 // NOTE: does not evaluate custom targets for pre-pass camera
448 } else {
449 // automatic reduction to half res.
450 rc.renderResolution = { static_cast<uint32_t>(static_cast<float>(rc.renderResolution[0]) * 0.5f),
451 static_cast<uint32_t>(static_cast<float>(rc.renderResolution[1]) * 0.5f) };
452 // NOTE: should better evaluate all the flags from the main camera
453 rc.flags = RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT | RenderCamera::CAMERA_FLAG_OPAQUE_BIT |
454 RenderCamera::CAMERA_FLAG_CLEAR_DEPTH_BIT | RenderCamera::CAMERA_FLAG_CLEAR_COLOR_BIT;
455 }
456 rc.name = to_string(uniqueId);
457 rc.id = uniqueId; // unique id for main pre-pass
458 rc.prePassColorTargetName = {};
459 rc.postProcessName = DefaultMaterialCameraConstants::CAMERA_PRE_PASS_POST_PROCESS_PREFIX_NAME;
460 return rc;
461 }
462
WeightedPercentualBlend(BASE_NS::Math::Vec4 & origin,const BASE_NS::Math::Vec4 & switches)463 void WeightedPercentualBlend(BASE_NS::Math::Vec4& origin, const BASE_NS::Math::Vec4& switches)
464 {
465 float sumSwitches = switches.x + switches.y + switches.z + switches.w;
466
467 if (std::fabs(sumSwitches - 1.0f) < Math::EPSILON) {
468 origin = switches;
469 } else {
470 float sumOrigin = 0.0f;
471
472 for (uint32_t i = 0; i < 4U; ++i) {
473 if (switches[i] == 0.0f) {
474 sumOrigin += origin[i];
475 }
476 }
477 if (sumOrigin == 0.0f) { // !0div
478 for (uint32_t i = 0; i < 4U; ++i) {
479 if (switches[i] == 0.0f) {
480 origin[i] = 0.0f;
481 }
482 }
483 } else {
484 float scalingFactor = (1.0f - sumSwitches) / sumOrigin;
485
486 for (uint32_t i = 0; i < 4U; ++i) {
487 if (switches[i] > 0.0f) {
488 origin[i] = switches[i];
489 } else {
490 origin[i] *= scalingFactor;
491 }
492 }
493 }
494 }
495 }
496
FillRenderEnvironment(const IRenderHandleComponentManager & renderHandleMgr,const uint64_t & nodeLayerMask,const Entity & entity,const EnvironmentComponent & component,const Entity & probeTarget,RenderCamera::Environment & renderEnv,const IDynamicEnvironmentBlenderComponentManager & debcMgr)497 void FillRenderEnvironment(const IRenderHandleComponentManager& renderHandleMgr, const uint64_t& nodeLayerMask,
498 const Entity& entity, const EnvironmentComponent& component, const Entity& probeTarget,
499 RenderCamera::Environment& renderEnv, const IDynamicEnvironmentBlenderComponentManager& debcMgr)
500 {
501 renderEnv.id = entity.id;
502 renderEnv.layerMask = nodeLayerMask;
503 renderEnv.shader = renderHandleMgr.GetRenderHandleReference(component.shader);
504 if (component.background == EnvironmentComponent::Background::NONE) {
505 renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_NONE;
506 } else if (component.background == EnvironmentComponent::Background::IMAGE) {
507 renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_IMAGE;
508 } else if (component.background == EnvironmentComponent::Background::CUBEMAP) {
509 renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_CUBEMAP;
510 } else if (component.background == EnvironmentComponent::Background::EQUIRECTANGULAR) {
511 renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_EQUIRECTANGULAR;
512 } else if (component.background == EnvironmentComponent::Background::SKY) {
513 renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_SKY;
514 }
515 // force blender cubemap
516 if (EntityUtil::IsValid(component.blendEnvironments)) {
517 if (auto blendEnv = debcMgr.Read(component.blendEnvironments); blendEnv) {
518 if (!blendEnv->environments.empty()) {
519 renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_CUBEMAP;
520 }
521 }
522 }
523 // check for weather effects
524 if (EntityUtil::IsValid(component.weather)) {
525 renderEnv.flags |= RenderCamera::Environment::EnvironmentFlagBits::ENVIRONMENT_FLAG_CAMERA_WEATHER_BIT;
526 }
527
528 if (EntityUtil::IsValid(probeTarget)) {
529 renderEnv.radianceCubemap = renderHandleMgr.GetRenderHandleReference(probeTarget);
530 renderEnv.envMap = renderHandleMgr.GetRenderHandleReference(probeTarget);
531 } else {
532 renderEnv.radianceCubemap = renderHandleMgr.GetRenderHandleReference(component.radianceCubemap);
533 renderEnv.envMap = renderHandleMgr.GetRenderHandleReference(component.envMap);
534 }
535 renderEnv.radianceCubemapMipCount = component.radianceCubemapMipCount;
536 renderEnv.envMapLodLevel = component.envMapLodLevel;
537 const size_t shCount =
538 std::min(countof(component.irradianceCoefficients), countof(renderEnv.shIndirectCoefficients));
539 for (size_t idx = 0; idx < shCount; ++idx) {
540 renderEnv.shIndirectCoefficients[idx] = Math::Vec4(component.irradianceCoefficients[idx], 1.0f);
541 }
542 renderEnv.indirectDiffuseFactor = component.indirectDiffuseFactor;
543 renderEnv.indirectSpecularFactor = component.indirectSpecularFactor;
544 renderEnv.envMapFactor = component.envMapFactor;
545 if (EntityUtil::IsValid(component.blendEnvironments)) {
546 if (auto blendEnv = debcMgr.Read(component.blendEnvironments); blendEnv) {
547 auto entry = blendEnv->entryFactor;
548 auto swtch = blendEnv->switchFactor;
549 WeightedPercentualBlend(entry, swtch);
550 renderEnv.blendFactor = entry;
551 }
552 } else {
553 renderEnv.blendFactor = { 1.0f, 0.0f, 0.0f, 0.0f };
554 }
555
556 renderEnv.rotation = component.environmentRotation;
557 }
558
LerpVec4(const Math::Vec4 & vec0,const Math::Vec4 & vec1,const Math::Vec4 & blend)559 inline constexpr Math::Vec4 LerpVec4(const Math::Vec4& vec0, const Math::Vec4& vec1, const Math::Vec4& blend)
560 {
561 return Math::Vec4(Math::lerp(vec0.x, vec1.x, blend.x), Math::lerp(vec0.y, vec1.y, blend.y),
562 Math::lerp(vec0.z, vec1.z, blend.z), Math::lerp(vec0.w, vec1.w, blend.w));
563 }
564
LerpVec4(const Math::Vec4 & vec0,const Math::Vec4 & vec1,const float blend)565 inline constexpr Math::Vec4 LerpVec4(const Math::Vec4& vec0, const Math::Vec4& vec1, const float blend)
566 {
567 return Math::Vec4(Math::lerp(vec0.x, vec1.x, blend), Math::lerp(vec0.y, vec1.y, blend),
568 Math::lerp(vec0.z, vec1.z, blend), Math::lerp(vec0.w, vec1.w, blend));
569 }
570
FillCameraRenderEnvironment(IRenderDataStoreDefaultCamera & dsCamera,const CameraComponent & component,RenderCamera & camera)571 void FillCameraRenderEnvironment(
572 IRenderDataStoreDefaultCamera& dsCamera, const CameraComponent& component, RenderCamera& camera)
573 {
574 camera.environment = EntityUtil::IsValid(component.environment)
575 ? dsCamera.GetEnvironment(component.environment.id)
576 : dsCamera.GetEnvironment(RenderSceneDataConstants::INVALID_ID);
577 // if dynamic cubemap is used, we create a new environment for camera id with default coefficients
578 if (camera.environment.multiEnvCount != 0U) {
579 camera.environment.backgroundType = RenderCamera::Environment::BG_TYPE_CUBEMAP;
580 }
581 }
582
FillMultiEnvironments(const IEnvironmentComponentManager & envMgr,RenderCamera::Environment & renderEnv)583 void FillMultiEnvironments(const IEnvironmentComponentManager& envMgr, RenderCamera::Environment& renderEnv)
584 {
585 // only supported background type
586 CORE_ASSERT(renderEnv.multiEnvCount != 0U);
587 CORE_ASSERT(renderEnv.backgroundType == RenderCamera::Environment::BG_TYPE_CUBEMAP);
588 // replace base environment values -> combine indirect diffuse values
589 renderEnv.indirectDiffuseFactor = Math::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
590 renderEnv.indirectSpecularFactor = Math::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
591 renderEnv.envMapFactor = Math::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
592 for (size_t idx = 0; idx < countof(renderEnv.shIndirectCoefficients); ++idx) {
593 renderEnv.shIndirectCoefficients[idx] = Math::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
594 }
595 float blendVal = 1.0f;
596 for (uint32_t envIdx = 0U; envIdx < renderEnv.multiEnvCount; ++envIdx) {
597 if (const auto multiEnv = envMgr.Read(Entity { renderEnv.multiEnvIds[envIdx] }); multiEnv) {
598 const auto& currEnv = *multiEnv;
599 renderEnv.indirectDiffuseFactor =
600 LerpVec4(renderEnv.indirectDiffuseFactor, currEnv.indirectDiffuseFactor, blendVal);
601 renderEnv.indirectSpecularFactor =
602 LerpVec4(renderEnv.indirectSpecularFactor, currEnv.indirectSpecularFactor, blendVal);
603 renderEnv.envMapFactor = LerpVec4(renderEnv.envMapFactor, currEnv.envMapFactor, blendVal);
604 for (size_t idx = 0; idx < countof(renderEnv.shIndirectCoefficients); ++idx) {
605 renderEnv.shIndirectCoefficients[idx] = LerpVec4(renderEnv.shIndirectCoefficients[idx],
606 Math::Vec4(currEnv.irradianceCoefficients[idx], 1.0f), blendVal);
607 }
608 blendVal = renderEnv.blendFactor[envIdx];
609 }
610 }
611 }
612
GetRenderCameraFogFromComponent(const ILayerComponentManager * layerMgr,const IFogComponentManager * fogMgr,const RenderConfigurationComponent & renderConfigurationComponent,const CameraComponent & cameraComponent)613 RenderCamera::Fog GetRenderCameraFogFromComponent(const ILayerComponentManager* layerMgr,
614 const IFogComponentManager* fogMgr, const RenderConfigurationComponent& renderConfigurationComponent,
615 const CameraComponent& cameraComponent)
616 {
617 RenderCamera::Fog renderFog;
618 if (!(layerMgr && fogMgr)) {
619 return renderFog;
620 }
621
622 auto fillRenderFog = [](const uint64_t& nodeLayerMask, const Entity& entity, const FogComponent& component,
623 RenderCamera::Fog& renderFog) {
624 renderFog.id = entity.id;
625 renderFog.layerMask = nodeLayerMask;
626
627 renderFog.firstLayer = { component.density, component.heightFalloff, component.heightFogOffset, 0.0f };
628 renderFog.secondLayer = { component.layerDensity, component.layerHeightFalloff, component.layerHeightFogOffset,
629 0.0f };
630 renderFog.baseFactors = { component.startDistance, component.cuttoffDistance, component.maxOpacity, 0.0f };
631 renderFog.inscatteringColor = component.inscatteringColor;
632 renderFog.envMapFactor = component.envMapFactor;
633 renderFog.additionalFactor = component.additionalFactor;
634 };
635
636 const Entity cameraFogEntity = cameraComponent.fog;
637 // Check if camera has a valid fog
638 Entity fogEntity = cameraFogEntity;
639 auto fogId = fogMgr->GetComponentId(fogEntity);
640 if (fogId == IComponentManager::INVALID_COMPONENT_ID) {
641 // Next try if the scene has a valid fog
642 fogEntity = renderConfigurationComponent.fog;
643 fogId = fogMgr->GetComponentId(fogEntity);
644 }
645 if (fogId != IComponentManager::INVALID_COMPONENT_ID) {
646 if (auto fogDataHandle = fogMgr->Read(fogId); fogDataHandle) {
647 const FogComponent& fogComponent = *fogDataHandle;
648 uint64_t layerMask = LayerConstants::DEFAULT_LAYER_MASK;
649 if (auto layerHandle = layerMgr->Read(fogEntity); layerHandle) {
650 layerMask = layerHandle->layerMask;
651 }
652
653 fillRenderFog(layerMask, fogEntity, fogComponent, renderFog);
654 }
655 }
656
657 return renderFog;
658 }
659
GetRenderShadowTypes(const RenderConfigurationComponent & renderConfigurationComponent)660 constexpr IRenderDataStoreDefaultLight::ShadowTypes GetRenderShadowTypes(
661 const RenderConfigurationComponent& renderConfigurationComponent)
662 {
663 IRenderDataStoreDefaultLight::ShadowTypes st { IRenderDataStoreDefaultLight::ShadowType::PCF,
664 IRenderDataStoreDefaultLight::ShadowQuality::NORMAL, IRenderDataStoreDefaultLight::ShadowSmoothness::NORMAL };
665 st.shadowType = (renderConfigurationComponent.shadowType == RenderConfigurationComponent::SceneShadowType::VSM)
666 ? IRenderDataStoreDefaultLight::ShadowType::VSM
667 : IRenderDataStoreDefaultLight::ShadowType::PCF;
668 if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::LOW) {
669 st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::LOW;
670 } else if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::HIGH) {
671 st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::HIGH;
672 } else if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::ULTRA) {
673 st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::ULTRA;
674 }
675 if (renderConfigurationComponent.shadowSmoothness == RenderConfigurationComponent::SceneShadowSmoothness::HARD) {
676 st.shadowSmoothness = IRenderDataStoreDefaultLight::ShadowSmoothness::HARD;
677 } else if (renderConfigurationComponent.shadowSmoothness ==
678 RenderConfigurationComponent::SceneShadowSmoothness::SOFT) {
679 st.shadowSmoothness = IRenderDataStoreDefaultLight::ShadowSmoothness::SOFT;
680 }
681 return st;
682 }
683
FillPostProcessConfigurationVars(const PostProcessConfigurationComponent::PostProcessEffect & pp)684 IRenderDataStorePostProcess::PostProcess::Variables FillPostProcessConfigurationVars(
685 const PostProcessConfigurationComponent::PostProcessEffect& pp)
686 {
687 IRenderDataStorePostProcess::PostProcess::Variables vars;
688 vars.userFactorIndex = pp.globalUserFactorIndex;
689 // NOTE: shader cannot be changed here
690 vars.factor = pp.factor;
691 vars.enabled = pp.enabled;
692 vars.flags = pp.flags;
693 if (pp.customProperties) {
694 array_view<const uint8_t> customData =
695 array_view(static_cast<const uint8_t*>(pp.customProperties->RLock()), pp.customProperties->Size());
696 const size_t copyByteSize = Math::min(countof(vars.customPropertyData), customData.size_bytes());
697 CloneData(vars.customPropertyData, countof(vars.customPropertyData), customData.data(), copyByteSize);
698 pp.customProperties->RUnlock();
699 }
700 return vars;
701 }
702
703 PROPERTY_LIST(IRenderSystem::Properties, ComponentMetadata, MEMBER_PROPERTY(dataStoreMaterial, "dataStoreMaterial", 0),
704 MEMBER_PROPERTY(dataStoreCamera, "dataStoreCamera", 0), MEMBER_PROPERTY(dataStoreLight, "dataStoreLight", 0),
705 MEMBER_PROPERTY(dataStoreScene, "dataStoreScene", 0), MEMBER_PROPERTY(dataStoreMorph, "dataStoreMorph", 0),
706 MEMBER_PROPERTY(dataStorePrefix, "", 0))
707
708 // Extended sign: returns -1, 0 or 1 based on sign of a
Sgn(float a)709 float Sgn(float a)
710 {
711 if (a > 0.0f) {
712 return 1.0f;
713 }
714
715 if (a < 0.0f) {
716 return -1.0f;
717 }
718
719 return 0.0f;
720 }
721
722 struct ReflectionPlaneTargetUpdate {
723 bool recreated { false };
724 uint32_t mipCount { 1u };
725 uint32_t renderTargetResolution[2U] {};
726 EntityReference colorRenderTarget;
727 EntityReference depthRenderTarget;
728 };
729
UpdateReflectionPlaneMaterial(IRenderMeshComponentManager & renderMeshMgr,IMeshComponentManager & meshMgr,IMaterialComponentManager & materialMgr,const Entity & entity,const float screenPercentage,const ReflectionPlaneTargetUpdate & rptu)730 void UpdateReflectionPlaneMaterial(IRenderMeshComponentManager& renderMeshMgr, IMeshComponentManager& meshMgr,
731 IMaterialComponentManager& materialMgr, const Entity& entity, const float screenPercentage,
732 const ReflectionPlaneTargetUpdate& rptu)
733 {
734 // update material
735 const auto rmcHandle = renderMeshMgr.Read(entity);
736 if (!rmcHandle) {
737 return;
738 }
739 const auto meshHandle = meshMgr.Read(rmcHandle->mesh);
740 if (!meshHandle) {
741 return;
742 }
743 if (meshHandle->submeshes.empty()) {
744 return;
745 }
746 if (auto matHandle = materialMgr.Write(meshHandle->submeshes[0].material)) {
747 // NOTE: CLEARCOAT_ROUGHNESS cannot be used due to material flags bit is enabled for lighting
748 matHandle->textures[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].factor = {
749 static_cast<float>(rptu.mipCount),
750 screenPercentage,
751 static_cast<float>(rptu.renderTargetResolution[0u]),
752 static_cast<float>(rptu.renderTargetResolution[1u]),
753 };
754 }
755 }
756
ProcessReflectionTargetSize(const PlanarReflectionComponent & rc,const RenderCamera & cam,Math::UVec2 & targetRes)757 void ProcessReflectionTargetSize(const PlanarReflectionComponent& rc, const RenderCamera& cam, Math::UVec2& targetRes)
758 {
759 targetRes.x = Math::max(
760 targetRes.x, static_cast<uint32_t>(static_cast<float>(cam.renderResolution[0U]) * rc.screenPercentage));
761 targetRes.y = Math::max(
762 targetRes.y, static_cast<uint32_t>(static_cast<float>(cam.renderResolution[1U]) * rc.screenPercentage));
763 }
764
UpdatePlaneReflectionTargetResolution(IGpuResourceManager & gpuResourceMgr,IRenderHandleComponentManager & gpuHandleMgr,const RenderCamera & sceneCamera,const Entity & entity,const Math::UVec2 targetRes,const uint32_t reflectionMaxMipBlur,const PlanarReflectionComponent & reflComp)765 ReflectionPlaneTargetUpdate UpdatePlaneReflectionTargetResolution(IGpuResourceManager& gpuResourceMgr,
766 IRenderHandleComponentManager& gpuHandleMgr, const RenderCamera& sceneCamera, const Entity& entity,
767 const Math::UVec2 targetRes, const uint32_t reflectionMaxMipBlur, const PlanarReflectionComponent& reflComp)
768 {
769 ReflectionPlaneTargetUpdate rptu { false, 1U,
770 { reflComp.renderTargetResolution[0], reflComp.renderTargetResolution[1] }, reflComp.colorRenderTarget,
771 reflComp.depthRenderTarget };
772
773 const RenderHandle colorRenderTarget = gpuHandleMgr.GetRenderHandle(rptu.colorRenderTarget);
774 const RenderHandle depthRenderTarget = gpuHandleMgr.GetRenderHandle(rptu.depthRenderTarget);
775 // get current mip count
776 rptu.mipCount = RenderHandleUtil::IsValid(colorRenderTarget)
777 ? gpuResourceMgr.GetImageDescriptor(gpuResourceMgr.Get(colorRenderTarget)).mipCount
778 : 1U;
779 // will resize based on frame max size
780 if ((!RenderHandleUtil::IsValid(colorRenderTarget)) || (!RenderHandleUtil::IsValid(depthRenderTarget)) ||
781 (targetRes.x != rptu.renderTargetResolution[0]) || (targetRes.y != rptu.renderTargetResolution[1])) {
782 auto reCreateGpuImage = [](IGpuResourceManager& gpuResourceMgr, uint64_t id, RenderHandle handle,
783 uint32_t newWidth, uint32_t newHeight, uint baseMipCount, bool depthImage) {
784 GpuImageDesc desc = RenderHandleUtil::IsValid(handle)
785 ? gpuResourceMgr.GetImageDescriptor(gpuResourceMgr.Get(handle))
786 : CreateReflectionPlaneGpuImageDesc(depthImage);
787 desc.mipCount = baseMipCount;
788 desc.width = newWidth;
789 desc.height = newHeight;
790 if (RenderHandleUtil::IsValid(handle)) {
791 return gpuResourceMgr.Create(gpuResourceMgr.Get(handle), desc);
792 } else {
793 return gpuResourceMgr.Create(desc);
794 }
795 };
796 if (!EntityUtil::IsValid(rptu.colorRenderTarget)) {
797 rptu.colorRenderTarget = gpuHandleMgr.GetEcs().GetEntityManager().CreateReferenceCounted();
798 gpuHandleMgr.Create(rptu.colorRenderTarget);
799 }
800 rptu.mipCount = Math::min(reflectionMaxMipBlur,
801 static_cast<uint32_t>(std::log2f(static_cast<float>(std::max(targetRes.x, targetRes.y)))) + 1u);
802 gpuHandleMgr.Write(rptu.colorRenderTarget)->reference = reCreateGpuImage(
803 gpuResourceMgr, entity.id, colorRenderTarget, targetRes.x, targetRes.y, rptu.mipCount, false);
804
805 if (!EntityUtil::IsValid(rptu.depthRenderTarget)) {
806 rptu.depthRenderTarget = gpuHandleMgr.GetEcs().GetEntityManager().CreateReferenceCounted();
807 gpuHandleMgr.Create(rptu.depthRenderTarget);
808 }
809 gpuHandleMgr.Write(rptu.depthRenderTarget)->reference =
810 reCreateGpuImage(gpuResourceMgr, entity.id, depthRenderTarget, targetRes.x, targetRes.y, 1u, true);
811
812 rptu.renderTargetResolution[0] = targetRes.x;
813 rptu.renderTargetResolution[1] = targetRes.y;
814 rptu.recreated = true;
815 }
816
817 return rptu;
818 }
819
820 // Given position and normal of the plane, calculates plane in camera space.
CalculateCameraSpaceClipPlane(const Math::Mat4X4 & view,Math::Vec3 pos,Math::Vec3 normal,float sideSign)821 inline Math::Vec4 CalculateCameraSpaceClipPlane(
822 const Math::Mat4X4& view, Math::Vec3 pos, Math::Vec3 normal, float sideSign)
823 {
824 const Math::Vec3 offsetPos = pos;
825 const Math::Vec3 cpos = Math::MultiplyPoint3X4(view, offsetPos);
826 const Math::Vec3 cnormal = Math::Normalize(Math::MultiplyVector(view, normal)) * sideSign;
827 return Math::Vec4(cnormal.x, cnormal.y, cnormal.z, -Math::Dot(cpos, cnormal));
828 }
829
830 // See http://aras-p.info/texts/obliqueortho.html
CalculateObliqueProjectionMatrix(Math::Mat4X4 & projection,const Math::Vec4 & plane)831 inline void CalculateObliqueProjectionMatrix(Math::Mat4X4& projection, const Math::Vec4& plane)
832 {
833 const Math::Mat4X4 inverseProjection = Inverse(projection);
834
835 const Math::Vec4 q = inverseProjection * Math::Vec4(Sgn(plane.x), Sgn(plane.y), 1.0f, 1.0f);
836 const Math::Vec4 c = plane * (2.0f / Math::Dot(plane, q));
837
838 projection.data[2u] = c.x;
839 projection.data[6u] = c.y;
840 projection.data[10u] = c.z;
841 projection.data[14u] = c.w;
842 }
843
844 // Calculate reflection matrix from given matrix.
CalculateReflectionMatrix(const Math::Vec4 & plane)845 Math::Mat4X4 CalculateReflectionMatrix(const Math::Vec4& plane)
846 {
847 Math::Mat4X4 result(1.0f);
848
849 result.data[0u] = (1.0f - 2.0f * plane[0u] * plane[0u]);
850 result.data[4u] = (-2.0f * plane[0u] * plane[1u]);
851 result.data[8u] = (-2.0f * plane[0u] * plane[2u]);
852 result.data[12u] = (-2.0f * plane[3u] * plane[0u]);
853
854 result.data[1u] = (-2.0f * plane[1u] * plane[0u]);
855 result.data[5u] = (1.0f - 2.0f * plane[1u] * plane[1u]);
856 result.data[9u] = (-2.0f * plane[1u] * plane[2u]);
857 result.data[13u] = (-2.0f * plane[3u] * plane[1u]);
858
859 result.data[2u] = (-2.0f * plane[2u] * plane[0u]);
860 result.data[6u] = (-2.0f * plane[2u] * plane[1u]);
861 result.data[10u] = (1.0f - 2.0f * plane[2u] * plane[2u]);
862 result.data[14u] = (-2.0f * plane[3u] * plane[2u]);
863
864 result.data[3u] = 0.0f;
865 result.data[7u] = 0.0f;
866 result.data[11u] = 0.0f;
867 result.data[15u] = 1.0f;
868
869 return result;
870 }
871
LogBatchValidation(const MeshComponent & mesh)872 inline void LogBatchValidation(const MeshComponent& mesh)
873 {
874 #if (CORE3D_VALIDATION_ENABLED == 1)
875 if (mesh.submeshes.size() > MAX_BATCH_SUBMESH_COUNT) {
876 CORE_LOG_ONCE_E("submesh_counts_batch",
877 "CORE3D_VALIDATION: GPU instancing batches not supported for submeshes with count %u > %u ",
878 static_cast<uint32_t>(mesh.submeshes.size()), MAX_BATCH_SUBMESH_COUNT);
879 }
880 #endif
881 }
882
DestroyBatchData(BASE_NS::unordered_map<CORE_NS::Entity,RenderSystem::BatchDataVector> & batches)883 inline void DestroyBatchData(BASE_NS::unordered_map<CORE_NS::Entity, RenderSystem::BatchDataVector>& batches)
884 {
885 // NOTE: we destroy batch entity if its elements were not used in this frame
886 for (auto iter = batches.begin(); iter != batches.end();) {
887 if (iter->second.empty()) {
888 iter = batches.erase(iter);
889 } else {
890 iter->second.clear();
891 ++iter;
892 }
893 }
894 }
895
GetMeshMinAndMax(const IRenderPreprocessorSystem & renderPreprocessorSystem,const Entity renderMeshEntity,array_view<const Entity> nextRenderMeshEntities)896 MinAndMax GetMeshMinAndMax(const IRenderPreprocessorSystem& renderPreprocessorSystem, const Entity renderMeshEntity,
897 array_view<const Entity> nextRenderMeshEntities)
898 {
899 const auto meshAabb =
900 static_cast<const RenderPreprocessorSystem&>(renderPreprocessorSystem).GetRenderMeshAabb(renderMeshEntity);
901 MinAndMax mam { meshAabb.min, meshAabb.max };
902 for (const auto& nextRenderMeshEntity : nextRenderMeshEntities) {
903 const auto nextMeshAabb = static_cast<const RenderPreprocessorSystem&>(renderPreprocessorSystem)
904 .GetRenderMeshAabb(nextRenderMeshEntity);
905 mam.minAABB = Math::min(mam.minAABB, nextMeshAabb.min);
906 mam.maxAABB = Math::max(mam.maxAABB, nextMeshAabb.max);
907 }
908 return mam;
909 }
910
ProcessCameraAddMultiViewHash(const RenderCamera & cam,unordered_map<uint64_t,uint64_t> & childToParent)911 inline void ProcessCameraAddMultiViewHash(const RenderCamera& cam, unordered_map<uint64_t, uint64_t>& childToParent)
912 {
913 for (uint32_t idx = 0; idx < cam.multiViewCameraCount; ++idx) {
914 childToParent.insert_or_assign(cam.multiViewCameraIds[idx], cam.id);
915 }
916 }
917 } // namespace
918
RenderSystem(IEcs & ecs)919 RenderSystem::RenderSystem(IEcs& ecs)
920 : ecs_(ecs), nodeMgr_(GetManager<INodeComponentManager>(ecs)),
921 renderMeshMgr_(GetManager<IRenderMeshComponentManager>(ecs)),
922 worldMatrixMgr_(GetManager<IWorldMatrixComponentManager>(ecs)),
923 renderConfigMgr_(GetManager<IRenderConfigurationComponentManager>(ecs)),
924 cameraMgr_(GetManager<ICameraComponentManager>(ecs)), lightMgr_(GetManager<ILightComponentManager>(ecs)),
925 planarReflectionMgr_(GetManager<IPlanarReflectionComponentManager>(ecs)),
926 materialMgr_(GetManager<IMaterialComponentManager>(ecs)), meshMgr_(GetManager<IMeshComponentManager>(ecs)),
927 uriMgr_(GetManager<IUriComponentManager>(ecs)), nameMgr_(GetManager<INameComponentManager>(ecs)),
928 environmentMgr_(GetManager<IEnvironmentComponentManager>(ecs)), fogMgr_(GetManager<IFogComponentManager>(ecs)),
929 gpuHandleMgr_(GetManager<IRenderHandleComponentManager>(ecs)), layerMgr_(GetManager<ILayerComponentManager>(ecs)),
930 dynamicEnvBlendMgr_(GetManager<IDynamicEnvironmentBlenderComponentManager>(ecs)),
931 jointMatricesMgr_(GetManager<IJointMatricesComponentManager>(ecs)),
932 prevJointMatricesMgr_(GetManager<IPreviousJointMatricesComponentManager>(ecs)),
933 postProcessMgr_(GetManager<IPostProcessComponentManager>(ecs)),
934 postProcessConfigMgr_(GetManager<IPostProcessConfigurationComponentManager>(ecs)),
935 RENDER_SYSTEM_PROPERTIES(&properties_, array_view(ComponentMetadata))
936 {
937 if (IEngine* engine = ecs_.GetClassFactory().GetInterface<IEngine>(); engine) {
938 frustumUtil_ = GetInstance<IFrustumUtil>(UID_FRUSTUM_UTIL);
939 renderContext_ = GetInstance<IRenderContext>(*engine->GetInterface<IClassRegister>(), UID_RENDER_CONTEXT);
940 if (renderContext_) {
941 picking_ = GetInstance<IPicking>(*renderContext_->GetInterface<IClassRegister>(), UID_PICKING);
942 graphicsContext_ =
943 GetInstance<IGraphicsContext>(*renderContext_->GetInterface<IClassRegister>(), UID_GRAPHICS_CONTEXT);
944 if (graphicsContext_) {
945 renderUtil_ = &graphicsContext_->GetRenderUtil();
946 }
947 shaderMgr_ = &renderContext_->GetDevice().GetShaderManager();
948 gpuResourceMgr_ = &renderContext_->GetDevice().GetGpuResourceManager();
949 }
950 }
951 }
952
~RenderSystem()953 RenderSystem::~RenderSystem()
954 {
955 DestroyRenderDataStores();
956 }
957
SetActive(bool state)958 void RenderSystem::SetActive(bool state)
959 {
960 active_ = state;
961 }
962
IsActive() const963 bool RenderSystem::IsActive() const
964 {
965 return active_;
966 }
967
GetName() const968 string_view RenderSystem::GetName() const
969 {
970 return CORE3D_NS::GetName(this);
971 }
972
GetUid() const973 Uid RenderSystem::GetUid() const
974 {
975 return UID;
976 }
977
GetProperties()978 IPropertyHandle* RenderSystem::GetProperties()
979 {
980 return RENDER_SYSTEM_PROPERTIES.GetData();
981 }
982
GetProperties() const983 const IPropertyHandle* RenderSystem::GetProperties() const
984 {
985 return RENDER_SYSTEM_PROPERTIES.GetData();
986 }
987
SetProperties(const IPropertyHandle & data)988 void RenderSystem::SetProperties(const IPropertyHandle& data)
989 {
990 if (data.Owner() != &RENDER_SYSTEM_PROPERTIES) {
991 return;
992 }
993 if (const auto in = ScopedHandle<const IRenderSystem::Properties>(&data); in) {
994 properties_.dataStoreScene = in->dataStoreScene;
995 properties_.dataStoreCamera = in->dataStoreCamera;
996 properties_.dataStoreLight = in->dataStoreLight;
997 properties_.dataStoreMaterial = in->dataStoreMaterial;
998 properties_.dataStoreMorph = in->dataStoreMorph;
999 properties_.dataStorePrefix = in->dataStorePrefix;
1000 if (renderContext_) {
1001 SetDataStorePointers(renderContext_->GetRenderDataStoreManager());
1002 }
1003 }
1004 }
1005
SetDataStorePointers(IRenderDataStoreManager & manager)1006 void RenderSystem::SetDataStorePointers(IRenderDataStoreManager& manager)
1007 {
1008 // get data stores
1009 dsScene_ = refcnt_ptr<IRenderDataStoreDefaultScene>(manager.GetRenderDataStore(properties_.dataStoreScene));
1010 dsCamera_ = refcnt_ptr<IRenderDataStoreDefaultCamera>(manager.GetRenderDataStore(properties_.dataStoreCamera));
1011 dsLight_ = refcnt_ptr<IRenderDataStoreDefaultLight>(manager.GetRenderDataStore(properties_.dataStoreLight));
1012 dsMaterial_ =
1013 refcnt_ptr<IRenderDataStoreDefaultMaterial>(manager.GetRenderDataStore(properties_.dataStoreMaterial));
1014 }
1015
GetECS() const1016 const IEcs& RenderSystem::GetECS() const
1017 {
1018 return ecs_;
1019 }
1020
Initialize()1021 void RenderSystem::Initialize()
1022 {
1023 if (graphicsContext_ && renderContext_) {
1024 renderPreprocessorSystem_ = GetSystem<IRenderPreprocessorSystem>(ecs_);
1025 if (renderPreprocessorSystem_) {
1026 const auto in =
1027 ScopedHandle<IRenderPreprocessorSystem::Properties>(renderPreprocessorSystem_->GetProperties());
1028 properties_.dataStoreScene = in->dataStoreScene;
1029 properties_.dataStoreCamera = in->dataStoreCamera;
1030 properties_.dataStoreLight = in->dataStoreLight;
1031 properties_.dataStoreMaterial = in->dataStoreMaterial;
1032 properties_.dataStoreMorph = in->dataStoreMorph;
1033 properties_.dataStorePrefix = in->dataStorePrefix;
1034 } else {
1035 CORE_LOG_E("DEPRECATED USAGE: RenderPreprocessorSystem not found. Add system to system graph.");
1036 }
1037
1038 SetDataStorePointers(renderContext_->GetRenderDataStoreManager());
1039 }
1040 if (renderContext_ && uriMgr_ && gpuHandleMgr_) {
1041 // fetch default shaders and graphics states
1042 const IShaderManager& shaderMgr = renderContext_->GetDevice().GetShaderManager();
1043 auto& entityMgr = ecs_.GetEntityManager();
1044 FillShaderData(entityMgr, *uriMgr_, *gpuHandleMgr_, shaderMgr,
1045 DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE, dmShaderData_.opaque);
1046 FillShaderData(entityMgr, *uriMgr_, *gpuHandleMgr_, shaderMgr,
1047 DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT, dmShaderData_.blend);
1048 FillShaderData(entityMgr, *uriMgr_, *gpuHandleMgr_, shaderMgr,
1049 DefaultMaterialShaderConstants::RENDER_SLOT_DEPTH, dmShaderData_.depth);
1050 }
1051
1052 {
1053 const ComponentQuery::Operation operations[] = {
1054 { *nodeMgr_, ComponentQuery::Operation::REQUIRE },
1055 { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1056 { *layerMgr_, ComponentQuery::Operation::OPTIONAL },
1057 };
1058 lightQuery_.SetEcsListenersEnabled(true);
1059 lightQuery_.SetupQuery(*lightMgr_, operations);
1060 }
1061 {
1062 const ComponentQuery::Operation operations[] = {
1063 { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1064 { *layerMgr_, ComponentQuery::Operation::OPTIONAL },
1065 { *jointMatricesMgr_, ComponentQuery::Operation::OPTIONAL },
1066 { *prevJointMatricesMgr_, ComponentQuery::Operation::OPTIONAL },
1067 };
1068 renderableQuery_.SetEcsListenersEnabled(true);
1069 renderableQuery_.SetupQuery(*renderMeshMgr_, operations, true);
1070 }
1071 {
1072 const ComponentQuery::Operation operations[] = {
1073 { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1074 { *nodeMgr_, ComponentQuery::Operation::REQUIRE },
1075 { *renderMeshMgr_, ComponentQuery::Operation::REQUIRE },
1076 };
1077 reflectionsQuery_.SetEcsListenersEnabled(true);
1078 reflectionsQuery_.SetupQuery(*planarReflectionMgr_, operations);
1079 }
1080 if (renderContext_) {
1081 IRenderDataStoreManager& rdsMgr = renderContext_->GetRenderDataStoreManager();
1082 if (auto dsPod = refcnt_ptr<IRenderDataStorePod>(rdsMgr.GetRenderDataStore(POD_DATA_STORE_NAME))) {
1083 auto podData = dsPod->Get(DefaultMaterialCameraConstants::CAMERA_REFLECTION_POST_PROCESS_PREFIX_NAME);
1084 if (!podData.empty()) {
1085 const auto& config = reinterpret_cast<const PostProcessConfiguration&>(podData[0U]);
1086 reflectionMaxMipBlur_ = Math::min(
1087 config.blurConfiguration.maxMipLevel, DefaultMaterialCameraConstants::REFLECTION_PLANE_MIP_COUNT);
1088 }
1089 }
1090 }
1091 }
1092
Update(bool frameRenderingQueued,uint64_t totalTime,uint64_t deltaTime)1093 bool RenderSystem::Update(bool frameRenderingQueued, uint64_t totalTime, uint64_t deltaTime)
1094 {
1095 renderProcessing_.frameProcessed = false;
1096 if (!active_) {
1097 return false;
1098 }
1099
1100 const auto renderConfigurationGen = renderConfigMgr_->GetGenerationCounter();
1101 const auto cameraGen = cameraMgr_->GetGenerationCounter();
1102 const auto lightGen = lightMgr_->GetGenerationCounter();
1103 const auto planarReflectionGen = planarReflectionMgr_->GetGenerationCounter();
1104 const auto environmentGen = environmentMgr_->GetGenerationCounter();
1105 const auto fogGen = fogMgr_->GetGenerationCounter();
1106 const auto postprocessGen = postProcessMgr_->GetGenerationCounter();
1107 const auto postprocessConfigurationGen = postProcessConfigMgr_->GetGenerationCounter();
1108 if (!frameRenderingQueued && (renderConfigurationGeneration_ == renderConfigurationGen) &&
1109 (cameraGeneration_ == cameraGen) && (lightGeneration_ == lightGen) &&
1110 (planarReflectionGeneration_ == planarReflectionGen) && (environmentGeneration_ == environmentGen) &&
1111 (fogGeneration_ == fogGen) && (postprocessGeneration_ == postprocessGen) &&
1112 (postprocessConfigurationGeneration_ == postprocessConfigurationGen)) {
1113 return false;
1114 }
1115
1116 renderConfigurationGeneration_ = renderConfigurationGen;
1117 cameraGeneration_ = cameraGen;
1118 lightGeneration_ = lightGen;
1119 planarReflectionGeneration_ = planarReflectionGen;
1120 environmentGeneration_ = environmentGen;
1121 fogGeneration_ = fogGen;
1122 postprocessGeneration_ = postprocessGen;
1123 postprocessConfigurationGeneration_ = postprocessConfigurationGen;
1124
1125 totalTime_ = totalTime;
1126 deltaTime_ = deltaTime;
1127
1128 if (dsMaterial_ && dsCamera_ && dsLight_ && dsScene_) {
1129 dsMaterial_->Clear();
1130 dsCamera_->Clear();
1131 dsLight_->Clear();
1132 dsScene_->Clear();
1133 FetchFullScene();
1134 } else {
1135 #if (CORE3D_VALIDATION_ENABLED == 1)
1136 CORE_LOG_ONCE_W("rs_data_stores_not_found", "CORE3D_VALIDATION: render system render data stores not found");
1137 #endif
1138 }
1139 frameIndex_++;
1140
1141 renderProcessing_.frameProcessed = true;
1142 return true;
1143 }
1144
Uninitialize()1145 void RenderSystem::Uninitialize()
1146 {
1147 lightQuery_.SetEcsListenersEnabled(false);
1148 renderableQuery_.SetEcsListenersEnabled(false);
1149 reflectionsQuery_.SetEcsListenersEnabled(false);
1150 }
1151
GetRenderConfigurationComponent()1152 RenderConfigurationComponent RenderSystem::GetRenderConfigurationComponent()
1153 {
1154 for (IComponentManager::ComponentId i = 0; i < renderConfigMgr_->GetComponentCount(); i++) {
1155 const Entity id = renderConfigMgr_->GetEntity(i);
1156 if (nodeMgr_->Get(id).effectivelyEnabled) {
1157 return renderConfigMgr_->Get(i);
1158 }
1159 }
1160 return {};
1161 }
1162
ProcessScene(const RenderConfigurationComponent & sc)1163 Entity RenderSystem::ProcessScene(const RenderConfigurationComponent& sc)
1164 {
1165 Entity cameraEntity { INVALID_ENTITY };
1166 // Grab active camera.
1167 const auto cameraCount = cameraMgr_->GetComponentCount();
1168 for (IComponentManager::ComponentId id = 0; id < cameraCount; ++id) {
1169 if (auto handle = cameraMgr_->Read(id); handle) {
1170 if (handle->sceneFlags & CameraComponent::SceneFlagBits::MAIN_CAMERA_BIT) {
1171 cameraEntity = cameraMgr_->GetEntity(id);
1172 break;
1173 }
1174 }
1175 }
1176 dsLight_->SetShadowTypes(GetRenderShadowTypes(sc), 0u);
1177
1178 // NOTE: removed code for "No main camera set, grab 1st one (if any)."
1179
1180 return cameraEntity;
1181 }
1182
EvaluateFrameObjectFlags()1183 void RenderSystem::EvaluateFrameObjectFlags()
1184 {
1185 const auto info = dsMaterial_->GetRenderFrameObjectInfo();
1186 // update built-in pipeline modifications for default materials
1187 if (info.renderMaterialFlags & RenderMaterialFlagBits::RENDER_MATERIAL_TRANSMISSION_BIT) {
1188 // NOTE: should be alpha blend and not double sided, should be set by material author
1189 // automatically done by e.g. gltf2 importer
1190 renderProcessing_.frameFlags |= NEEDS_COLOR_PRE_PASS; // when allowing prepass on demand
1191 }
1192 }
1193
ProcessMesh(const RenderMeshData rmd,const SkinProcessData & spd)1194 void RenderSystem::ProcessMesh(const RenderMeshData rmd, const SkinProcessData& spd)
1195 {
1196 CORE_STATIC_ASSERT(sizeof(RenderMeshComponent::customData) == sizeof(RenderMeshData::customData));
1197 // NOTE: When object is skinned we use the mesh bounding box for all the submeshes because currently
1198 // there is no way to know here which joints affect one specific renderSubmesh.
1199 const bool useJoints = spd.jointMatricesComponent && (spd.jointMatricesComponent->count > 0);
1200 RenderMeshSkinData rmsd;
1201 if (useJoints) {
1202 CORE_ASSERT(spd.prevJointMatricesComponent);
1203 rmsd.skinJointMatrices = array_view<Math::Mat4X4 const>(
1204 spd.jointMatricesComponent->jointMatrices, spd.jointMatricesComponent->count);
1205 rmsd.prevSkinJointMatrices = array_view<Math::Mat4X4 const>(
1206 spd.prevJointMatricesComponent->jointMatrices, spd.prevJointMatricesComponent->count);
1207 rmsd.aabb.minAabb = spd.jointMatricesComponent->jointsAabbMin;
1208 rmsd.aabb.maxAabb = spd.jointMatricesComponent->jointsAabbMax;
1209 }
1210 const auto aabbs =
1211 static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderMeshAabbs(Entity { rmd.id });
1212
1213 RenderMeshAabbData renderMeshAabb;
1214 const bool hasMeshAabb = (!aabbs.empty());
1215 if (hasMeshAabb) {
1216 renderMeshAabb.aabb.minAabb = aabbs[0].min;
1217 renderMeshAabb.aabb.maxAabb = aabbs[0].max;
1218 }
1219 renderMeshAabb.submeshAabb = { reinterpret_cast<const RenderMinAndMax*>(aabbs.data()), aabbs.size() };
1220
1221 dsMaterial_->AddFrameRenderMeshData(rmd, renderMeshAabb, rmsd);
1222 }
1223
ProcessMesh(BASE_NS::array_view<const RenderMeshData> rmd,const RenderMeshBatchData rmbd,const SkinProcessData & spd)1224 void RenderSystem::ProcessMesh(
1225 BASE_NS::array_view<const RenderMeshData> rmd, const RenderMeshBatchData rmbd, const SkinProcessData& spd)
1226 {
1227 CORE_STATIC_ASSERT(sizeof(RenderMeshComponent::customData) == sizeof(RenderMeshData::customData));
1228 if (rmd.empty()) {
1229 return;
1230 }
1231 const auto& baseRmd = rmd[0];
1232
1233 // NOTE: When object is skinned we use the mesh bounding box for all the submeshes because currently
1234 // there is no way to know here which joints affect one specific renderSubmesh.
1235 const bool useJoints = spd.jointMatricesComponent && (spd.jointMatricesComponent->count > 0);
1236 RenderMeshSkinData rmsd;
1237 if (useJoints) {
1238 CORE_ASSERT(spd.prevJointMatricesComponent);
1239 rmsd.skinJointMatrices = array_view<Math::Mat4X4 const>(
1240 spd.jointMatricesComponent->jointMatrices, spd.jointMatricesComponent->count);
1241 rmsd.prevSkinJointMatrices = array_view<Math::Mat4X4 const>(
1242 spd.prevJointMatricesComponent->jointMatrices, spd.prevJointMatricesComponent->count);
1243 rmsd.aabb.minAabb = spd.jointMatricesComponent->jointsAabbMin;
1244 rmsd.aabb.maxAabb = spd.jointMatricesComponent->jointsAabbMax;
1245 }
1246 const auto aabbs =
1247 static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderMeshAabbs(Entity { baseRmd.id });
1248
1249 RenderMeshAabbData renderMeshAabb;
1250 const bool hasMeshAabb = (!aabbs.empty());
1251 if (hasMeshAabb) {
1252 renderMeshAabb.aabb.minAabb = aabbs[0].min;
1253 renderMeshAabb.aabb.maxAabb = aabbs[0].max;
1254 }
1255 renderMeshAabb.submeshAabb = { reinterpret_cast<const RenderMinAndMax*>(aabbs.data()), aabbs.size() };
1256
1257 dsMaterial_->AddFrameRenderMeshData(rmd, renderMeshAabb, rmsd, rmbd);
1258 }
1259
ProcessRenderMeshComponentBatch(const uint32_t sceneId,const Entity renderMeshBatch,const ComponentQuery::ResultRow * row)1260 void RenderSystem::ProcessRenderMeshComponentBatch(
1261 const uint32_t sceneId, const Entity renderMeshBatch, const ComponentQuery::ResultRow* row)
1262 {
1263 const RenderMeshComponent renderMeshComponent = renderMeshMgr_->Get(row->components[RQ_RMC]);
1264 const auto worldMatrix = worldMatrixMgr_->Read(row->components[RQ_WM]);
1265 const uint64_t layerMask = !row->IsValidComponentId(RQ_L) ? LayerConstants::DEFAULT_LAYER_MASK
1266 : layerMgr_->Get(row->components[RQ_L]).layerMask;
1267 // NOTE: direct component id for skins added to batch processing
1268 batches_[renderMeshBatch].push_back({ row->entity, renderMeshComponent.mesh, layerMask, sceneId,
1269 row->components[RQ_JM], row->components[RQ_PJM], worldMatrix->matrix, worldMatrix->prevMatrix });
1270 }
1271
ProcessRenderMeshAutomaticBatch(const uint32_t sceneId,array_view<const Entity> renderMeshComponents)1272 void RenderSystem::ProcessRenderMeshAutomaticBatch(
1273 const uint32_t sceneId, array_view<const Entity> renderMeshComponents)
1274 {
1275 auto SubmitBatch = [&](const vector<RenderMeshData>& rmd, const uint32_t jointId, const uint32_t prevJointId,
1276 const RenderMeshBatchData& rmbd) {
1277 if ((jointId != IComponentManager::INVALID_COMPONENT_ID) &&
1278 (prevJointId != IComponentManager::INVALID_COMPONENT_ID)) {
1279 auto const jointMatricesData = jointMatricesMgr_->Read(jointId);
1280 auto const prevJointMatricesData = prevJointMatricesMgr_->Read(prevJointId);
1281 const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1282 ProcessMesh(rmd, rmbd, spd);
1283 } else {
1284 ProcessMesh(rmd, rmbd, {});
1285 }
1286 };
1287
1288 uint32_t batchIndex = 0;
1289 uint32_t batchedCount = 0;
1290 ScopedHandle<const MeshComponent> meshHandle;
1291 const uint32_t batchInstCount = static_cast<uint32_t>(renderMeshComponents.size());
1292 MinAndMax mam;
1293 bool openBatch = false;
1294 IComponentManager::ComponentId jointId = IComponentManager::INVALID_COMPONENT_ID;
1295 IComponentManager::ComponentId prevJointId = IComponentManager::INVALID_COMPONENT_ID;
1296 for (const auto& entity : renderMeshComponents) {
1297 const auto row = renderableQuery_.FindResultRow(entity);
1298 if (!row) {
1299 continue;
1300 }
1301 const RenderMeshComponent rmc = renderMeshMgr_->Get(row->components[RQ_RMC]);
1302 if (!meshHandle) {
1303 meshHandle = meshMgr_->Read(rmc.mesh);
1304 if (!meshHandle) {
1305 continue;
1306 }
1307 }
1308
1309 const WorldMatrixComponent& world = worldMatrixMgr_->Get(row->components[RQ_WM]);
1310 const uint64_t layerMask = !row->IsValidComponentId(RQ_L) ? LayerConstants::DEFAULT_LAYER_MASK
1311 : layerMgr_->Read(row->components[RQ_L])->layerMask;
1312 // this is a batch of the same material
1313 // duplicates the mesh uniform data for all instances
1314 if (batchIndex == 0) {
1315 LogBatchValidation(*meshHandle);
1316
1317 openBatch = true;
1318 renderMeshData_.clear();
1319 renderMeshData_.reserve(meshHandle->submeshes.size());
1320
1321 const uint32_t currBatchCount = Math::min(batchInstCount - batchedCount, MAX_BATCH_OBJECT_COUNT);
1322 // process AABBs for all instances, the same mesh is used for all instances with their own
1323 // transform
1324 mam = GetMeshMinAndMax(*renderPreprocessorSystem_, entity,
1325 array_view(renderMeshComponents.data() + batchedCount, currBatchCount));
1326
1327 batchedCount += currBatchCount;
1328 // this is a batch of same material, so the material uniform data is duplicated
1329 RenderMeshData rmd { world.matrix, world.matrix, world.prevMatrix, entity.id, rmc.mesh.id, layerMask,
1330 sceneId };
1331 std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1332 renderMeshData_.push_back(move(rmd));
1333 // Optional skin, cannot change based on submesh)
1334 if (row->IsValidComponentId(RQ_JM) && row->IsValidComponentId(RQ_PJM)) {
1335 jointId = row->components[RQ_JM];
1336 prevJointId = row->components[RQ_PJM];
1337 }
1338 } else {
1339 // NOTE: normal matrix is missing
1340 RenderMeshData rmd { world.matrix, world.matrix, world.prevMatrix, entity.id, rmc.mesh.id, layerMask,
1341 sceneId };
1342 std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1343 renderMeshData_.push_back(move(rmd));
1344 // NOTE: materials have been automatically duplicated for all instance
1345 }
1346 if (++batchIndex == MAX_BATCH_OBJECT_COUNT) {
1347 SubmitBatch(renderMeshData_, jointId, prevJointId, { { mam.minAABB, mam.maxAABB }, 0U });
1348 // reset
1349 batchIndex = 0;
1350 openBatch = false;
1351 jointId = IComponentManager::INVALID_COMPONENT_ID;
1352 prevJointId = IComponentManager::INVALID_COMPONENT_ID;
1353 }
1354 }
1355 // submit final batch
1356 if (openBatch) {
1357 SubmitBatch(renderMeshData_, jointId, prevJointId, { { mam.minAABB, mam.maxAABB }, 0U });
1358 }
1359 }
1360
ProcessSingleRenderMesh(const uint32_t sceneId,Entity renderMeshComponent)1361 void RenderSystem::ProcessSingleRenderMesh(const uint32_t sceneId, Entity renderMeshComponent)
1362 {
1363 // add a single mesh
1364 if (const auto row = renderableQuery_.FindResultRow(renderMeshComponent); row) {
1365 const RenderMeshComponent rmc = renderMeshMgr_->Get(row->components[RQ_RMC]);
1366 if (const auto meshData = meshMgr_->Read(rmc.mesh); meshData) {
1367 const WorldMatrixComponent world = worldMatrixMgr_->Get(row->components[RQ_WM]);
1368 const uint64_t layerMask = !row->IsValidComponentId(RQ_L) ? LayerConstants::DEFAULT_LAYER_MASK
1369 : layerMgr_->Get(row->components[RQ_L]).layerMask;
1370 RenderMeshData rmd { world.matrix, world.matrix, world.prevMatrix, row->entity.id, rmc.mesh.id, layerMask,
1371 sceneId };
1372 std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1373 // (4, 5) JointMatrixComponents are optional.
1374 if (row->IsValidComponentId(RQ_JM) && row->IsValidComponentId(RQ_PJM)) {
1375 auto const jointMatricesData = jointMatricesMgr_->Read(row->components[RQ_JM]);
1376 auto const prevJointMatricesData = prevJointMatricesMgr_->Read(row->components[RQ_PJM]);
1377 CORE_ASSERT(jointMatricesData);
1378 CORE_ASSERT(prevJointMatricesData);
1379 const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1380 ProcessMesh(rmd, spd);
1381 } else {
1382 ProcessMesh(rmd, {});
1383 }
1384 }
1385 }
1386 }
1387
ProcessRenderables()1388 void RenderSystem::ProcessRenderables()
1389 {
1390 renderableQuery_.Execute();
1391 const auto levelData = static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetSceneData();
1392 for (const auto& level : levelData) {
1393 for (const auto& rmc : level.renderBatchComponents) {
1394 if (const auto row = renderableQuery_.FindResultRow(rmc); row) {
1395 const RenderMeshComponent renderMeshComponent = renderMeshMgr_->Get(row->components[RQ_RMC]);
1396 // batched render mesh components not processed linearly
1397 ProcessRenderMeshComponentBatch(level.sceneId, renderMeshComponent.renderMeshBatch, row);
1398 }
1399 }
1400
1401 {
1402 auto currentIndex = 0U;
1403 auto batchStartIndex = 0U;
1404 Entity currentMesh;
1405 for (const auto& rmc : level.instancingAllowed) {
1406 if (const auto row = renderableQuery_.FindResultRow(rmc); row) {
1407 const RenderMeshComponent renderMeshComponent = renderMeshMgr_->Get(row->components[RQ_RMC]);
1408 if (currentMesh != renderMeshComponent.mesh) {
1409 // create batch when the mesh changes [batchStartIndex..currentIndex)
1410 if (const auto batchSize = currentIndex - batchStartIndex; batchSize) {
1411 ProcessRenderMeshAutomaticBatch(
1412 level.sceneId, { level.instancingAllowed.data() + batchStartIndex, batchSize });
1413 }
1414
1415 batchStartIndex = currentIndex;
1416 currentMesh = renderMeshComponent.mesh;
1417 }
1418 }
1419 ++currentIndex;
1420 }
1421
1422 // handle the tail
1423 if (const auto batchSize = currentIndex - batchStartIndex; batchSize) {
1424 ProcessRenderMeshAutomaticBatch(
1425 level.sceneId, { level.instancingAllowed.data() + batchStartIndex, batchSize });
1426 }
1427 }
1428
1429 for (const auto& rmc : level.rest) {
1430 ProcessSingleRenderMesh(level.sceneId, rmc);
1431 }
1432 }
1433
1434 // process render mesh batch component related meshes
1435 ProcessRenderMeshBatchComponentRenderables();
1436 }
1437
ProcessRenderMeshBatchComponentRenderables()1438 void RenderSystem::ProcessRenderMeshBatchComponentRenderables()
1439 {
1440 auto SubmitBatch = [&](const vector<RenderMeshData>& rmd, const uint32_t jointId, const uint32_t prevJointId,
1441 const RenderMeshBatchData& rmbd) {
1442 if ((jointId != IComponentManager::INVALID_COMPONENT_ID) &&
1443 (prevJointId != IComponentManager::INVALID_COMPONENT_ID)) {
1444 auto const jointMatricesData = jointMatricesMgr_->Read(jointId);
1445 auto const prevJointMatricesData = prevJointMatricesMgr_->Read(prevJointId);
1446 const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1447 ProcessMesh(rmd, rmbd, spd);
1448 } else {
1449 ProcessMesh(rmd, rmbd, {});
1450 }
1451 };
1452
1453 // process render mesh batch component related meshes
1454 RenderMeshBatchData rmbd { {}, RENDER_MATERIAL_GPU_INSTANCING_MATERIAL_BIT };
1455 for (const auto& batchRef : batches_) {
1456 uint32_t batchIndex = 0U;
1457 uint32_t batchedCount = 0U;
1458 IComponentManager::ComponentId jointId = IComponentManager::INVALID_COMPONENT_ID;
1459 IComponentManager::ComponentId prevJointId = IComponentManager::INVALID_COMPONENT_ID;
1460 const uint32_t batchInstCount = static_cast<uint32_t>(batchRef.second.size());
1461 MinAndMax mam;
1462 bool batchOpen = false;
1463 for (uint32_t entIdx = 0U; entIdx < batchInstCount; ++entIdx) {
1464 const auto& inst = batchRef.second[entIdx];
1465 const Entity& entRef = inst.entity;
1466 const Entity& meshEntRef = inst.mesh;
1467 if (const auto meshData = meshMgr_->Read(meshEntRef); meshData) {
1468 const auto& mesh = *meshData;
1469 const RenderMeshComponent rmc = renderMeshMgr_->Get(entRef);
1470 // process the first fully
1471 if (batchIndex == 0U) {
1472 LogBatchValidation(mesh);
1473
1474 batchOpen = true;
1475 renderMeshData_.clear();
1476 renderMeshData_.reserve(meshData->submeshes.size());
1477
1478 const uint32_t currPatchCount = Math::min(batchInstCount - batchedCount, MAX_BATCH_OBJECT_COUNT);
1479 // process AABBs for all instances, the same mesh is used for all instances with their own
1480 // transform
1481 const BatchIndices batchIndices { ~0u, entIdx + 1U, entIdx + currPatchCount };
1482 CombineBatchWorldMinAndMax(batchRef.second, batchIndices, mesh, mam);
1483 batchedCount += currPatchCount;
1484 RenderMeshData rmd { inst.mtx, inst.mtx, inst.prevWorld, entRef.id, meshEntRef.id, inst.layerMask };
1485 std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1486 renderMeshData_.push_back(move(rmd));
1487 // Optional skin, cannot change based on submesh)
1488 if (inst.jointId != IComponentManager::INVALID_COMPONENT_ID) {
1489 jointId = inst.jointId;
1490 prevJointId = inst.prevJointId;
1491 }
1492 } else {
1493 // NOTE: normal matrix is missing
1494 RenderMeshData rmd { inst.mtx, inst.mtx, inst.prevWorld, entRef.id, meshEntRef.id, inst.layerMask };
1495 std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1496 renderMeshData_.push_back(move(rmd));
1497 }
1498 if (++batchIndex == MAX_BATCH_OBJECT_COUNT) {
1499 rmbd.aabb = { mam.minAABB, mam.maxAABB };
1500 SubmitBatch(renderMeshData_, jointId, prevJointId, rmbd);
1501 // reset
1502 batchIndex = 0;
1503 batchOpen = false;
1504 jointId = IComponentManager::INVALID_COMPONENT_ID;
1505 prevJointId = IComponentManager::INVALID_COMPONENT_ID;
1506 }
1507 }
1508 }
1509 if (batchOpen) {
1510 rmbd.aabb = { mam.minAABB, mam.maxAABB };
1511 SubmitBatch(renderMeshData_, jointId, prevJointId, rmbd);
1512 }
1513 }
1514 // NOTE: we destroy batch entity if its elements were not used in this frame
1515 DestroyBatchData(batches_);
1516 }
1517
CombineBatchWorldMinAndMax(const BatchDataVector & batchVec,const BatchIndices & batchIndices,const MeshComponent & mesh,MinAndMax & mam) const1518 void RenderSystem::CombineBatchWorldMinAndMax(
1519 const BatchDataVector& batchVec, const BatchIndices& batchIndices, const MeshComponent& mesh, MinAndMax& mam) const
1520 {
1521 CORE_ASSERT(picking_);
1522 CORE_ASSERT(batchIndices.batchEndIndex <= static_cast<uint32_t>(batchVec.size()));
1523 if (batchIndices.submeshIndex == ~0u) {
1524 for (uint32_t bIdx = batchIndices.batchStartIndex; bIdx < batchIndices.batchEndIndex; ++bIdx) {
1525 const BatchData& bData = batchVec[bIdx];
1526 const auto& meshAabb =
1527 static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderMeshAabb(bData.entity);
1528 mam.minAABB = Math::min(mam.minAABB, meshAabb.min);
1529 mam.maxAABB = Math::max(mam.maxAABB, meshAabb.max);
1530 }
1531 } else if (batchIndices.submeshIndex < mesh.submeshes.size()) {
1532 for (uint32_t bIdx = batchIndices.batchStartIndex; bIdx < batchIndices.batchEndIndex; ++bIdx) {
1533 const BatchData& bData = batchVec[bIdx];
1534 const auto& submeshAabbs =
1535 static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetRenderMeshAabbs(bData.entity);
1536 if (batchIndices.submeshIndex < submeshAabbs.size()) {
1537 mam.minAABB = Math::min(mam.minAABB, submeshAabbs[batchIndices.submeshIndex].min);
1538 mam.maxAABB = Math::max(mam.maxAABB, submeshAabbs[batchIndices.submeshIndex].max);
1539 }
1540 }
1541 }
1542 }
1543
ProcessEnvironments(const RenderConfigurationComponent & renderConfig)1544 void RenderSystem::ProcessEnvironments(const RenderConfigurationComponent& renderConfig)
1545 {
1546 if (!(environmentMgr_ && layerMgr_ && gpuHandleMgr_)) {
1547 return;
1548 }
1549
1550 const auto envCount = environmentMgr_->GetComponentCount();
1551 for (IComponentManager::ComponentId id = 0; id < envCount; ++id) {
1552 if (ScopedHandle<const EnvironmentComponent> handle = environmentMgr_->Read(id); handle) {
1553 const EnvironmentComponent& component = *handle;
1554
1555 const Entity envEntity = environmentMgr_->GetEntity(id);
1556 uint64_t layerMask = LayerConstants::DEFAULT_LAYER_MASK;
1557 if (auto layerHandle = layerMgr_->Read(envEntity); layerHandle) {
1558 layerMask = layerHandle->layerMask;
1559 }
1560
1561 Entity probeTarget;
1562 if (EntityUtil::IsValid(component.reflectionProbe)) {
1563 auto rcm = GetManager<IReflectionProbeComponentManager>(ecs_);
1564 if (auto probe = rcm->Read(component.reflectionProbe); probe) {
1565 if (auto probeCamera = cameraMgr_->Read(probe->probeCamera); probeCamera) {
1566 if (!probeCamera->customColorTargets.empty() &&
1567 EntityUtil::IsValid(probeCamera->customColorTargets[0U])) {
1568 probeTarget = probeCamera->customColorTargets[0U];
1569 }
1570 }
1571 }
1572 }
1573
1574 RenderCamera::Environment renderEnv;
1575 FillRenderEnvironment(
1576 *gpuHandleMgr_, layerMask, envEntity, component, probeTarget, renderEnv, *dynamicEnvBlendMgr_);
1577 // material custom resources (first check preferred custom resources)
1578 if (!component.customResources.empty()) {
1579 const size_t maxCustomCount = Math::min(component.customResources.size(),
1580 static_cast<size_t>(RenderSceneDataConstants::MAX_ENV_CUSTOM_RESOURCE_COUNT));
1581 for (size_t idx = 0; idx < maxCustomCount; ++idx) {
1582 renderEnv.customResourceHandles[idx] =
1583 gpuHandleMgr_->GetRenderHandleReference(component.customResources[idx]);
1584 }
1585 }
1586
1587 uint32_t blendEnvCount = 0;
1588 if (auto debc = dynamicEnvBlendMgr_->Read(component.blendEnvironments); debc) {
1589 blendEnvCount = Math::min(static_cast<uint32_t>(debc->environments.size()),
1590 DefaultMaterialCameraConstants::MAX_CAMERA_MULTI_ENVIRONMENT_COUNT);
1591 for (uint32_t idx = 0U; idx < blendEnvCount; ++idx) {
1592 if (EntityUtil::IsValid(debc->environments[idx])) {
1593 renderEnv.multiEnvIds[renderEnv.multiEnvCount++] = debc->environments[idx].id;
1594 }
1595 }
1596 }
1597 if (renderEnv.multiEnvCount > 0U) {
1598 FillMultiEnvironments(*environmentMgr_, renderEnv);
1599 }
1600 // check for main environment
1601 if (renderEnv.id == renderConfig.environment.id) {
1602 renderEnv.flags |= RenderCamera::Environment::EnvironmentFlagBits::ENVIRONMENT_FLAG_MAIN_BIT;
1603 }
1604 dsCamera_->AddEnvironment(renderEnv);
1605 }
1606 }
1607 }
1608
ProcessCameras(const RenderConfigurationComponent & renderConfig,const Entity & mainCameraEntity,RenderScene & renderScene)1609 void RenderSystem::ProcessCameras(
1610 const RenderConfigurationComponent& renderConfig, const Entity& mainCameraEntity, RenderScene& renderScene)
1611 {
1612 // The scene camera and active render cameras are added here. ProcessReflections reflection cameras.
1613 // This is temporary when moving towards camera based rendering in 3D context.
1614 const uint32_t mainCameraId = cameraMgr_->GetComponentId(mainCameraEntity);
1615 const auto cameraCount = cameraMgr_->GetComponentCount();
1616 vector<RenderCamera> tmpCameras;
1617 tmpCameras.reserve(cameraCount);
1618 unordered_map<uint64_t, uint64_t> mvChildToParent; // multi-view child to parent
1619 for (IComponentManager::ComponentId id = 0; id < cameraCount; ++id) {
1620 ScopedHandle<const CameraComponent> handle = cameraMgr_->Read(id);
1621 const CameraComponent& component = *handle;
1622 if ((mainCameraId != id) && ((component.sceneFlags & CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT) == 0)) {
1623 continue;
1624 }
1625 const Entity cameraEntity = cameraMgr_->GetEntity(id);
1626 uint32_t level = 0U;
1627 if (auto nodeHandle = nodeMgr_->Read(cameraEntity)) {
1628 level = nodeHandle->sceneId;
1629 }
1630 const auto worldMatrixComponentId = worldMatrixMgr_->GetComponentId(cameraEntity);
1631 // Make sure we have render matrix.
1632 if (worldMatrixComponentId != IComponentManager::INVALID_COMPONENT_ID) {
1633 const WorldMatrixComponent renderMatrixComponent = worldMatrixMgr_->Get(worldMatrixComponentId);
1634
1635 float determinant = 0.0f;
1636 const Math::Mat4X4 view = Math::Inverse(Math::Mat4X4(renderMatrixComponent.matrix.data), determinant);
1637
1638 RenderCamera::Flags rcFlags = 0;
1639 if (mainCameraId == id) {
1640 renderScene.cameraIndex = static_cast<uint32_t>(tmpCameras.size());
1641 rcFlags = RenderCamera::CAMERA_FLAG_MAIN_BIT;
1642 }
1643 const bool createPrePassCam = (component.pipelineFlags & CameraComponent::FORCE_COLOR_PRE_PASS_BIT) ||
1644 (component.pipelineFlags & CameraComponent::ALLOW_COLOR_PRE_PASS_BIT);
1645 renderProcessing_.frameFlags |=
1646 (component.pipelineFlags & CameraComponent::FORCE_COLOR_PRE_PASS_BIT) ? NEEDS_COLOR_PRE_PASS : 0;
1647
1648 bool isCameraNegative = determinant < 0.0f;
1649 const auto proj = CameraMatrixUtil::CalculateProjectionMatrix(component, isCameraNegative);
1650
1651 RenderCamera camera;
1652 FillRenderCameraBaseFromCameraComponent(
1653 *gpuHandleMgr_, *cameraMgr_, *gpuResourceMgr_, component, camera, true);
1654 // we add entity id as camera name if there isn't name (we need this for render node graphs)
1655 camera.id = cameraEntity.id;
1656 camera.name = GetCameraName(*nameMgr_, cameraEntity);
1657 if (camera.flags & RenderCamera::CAMERA_FLAG_CUBEMAP_BIT) {
1658 camera.flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_INVERSE_WINDING_BIT;
1659 }
1660
1661 camera.sceneId = level;
1662
1663 camera.matrices.view = view;
1664 camera.matrices.proj = proj;
1665 const CameraData prevFrameCamData = UpdateAndGetPreviousFrameCameraData(cameraEntity, view, proj);
1666 camera.matrices.viewPrevFrame = prevFrameCamData.view;
1667 camera.matrices.projPrevFrame = prevFrameCamData.proj;
1668 camera.flags |= (rcFlags | ((isCameraNegative) ? RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT : 0));
1669 FillCameraRenderEnvironment(*dsCamera_, component, camera);
1670 camera.fog = GetRenderCameraFogFromComponent(layerMgr_, fogMgr_, renderConfig, component);
1671 camera.shaderFlags |=
1672 (camera.fog.id != RenderSceneDataConstants::INVALID_ID) ? RenderCamera::CAMERA_SHADER_FOG_BIT : 0U;
1673 camera.postProcessName = GetPostProcessName(
1674 postProcessMgr_, postProcessConfigMgr_, nameMgr_, properties_.dataStoreScene, component.postProcess);
1675 camera.customPostProcessRenderNodeGraphFile =
1676 GetPostProcessRenderNodeGraph(postProcessConfigMgr_, component.postProcess);
1677
1678 // NOTE: setting up the color pre pass with a target name is a temporary solution
1679 uint64_t prePassCameraHash = 0U;
1680 if (createPrePassCam) {
1681 prePassCameraHash = Hash(camera.id, camera.id);
1682 camera.prePassColorTargetName = renderScene.name +
1683 DefaultMaterialCameraConstants::CAMERA_COLOR_PREFIX_NAME +
1684 to_string(prePassCameraHash);
1685 }
1686 tmpCameras.push_back(camera);
1687 ProcessCameraAddMultiViewHash(camera, mvChildToParent);
1688 // The order of setting cameras matter (main camera index is set already)
1689 if (createPrePassCam) {
1690 tmpCameras.push_back(CreateColorPrePassRenderCamera(
1691 *gpuHandleMgr_, *cameraMgr_, *gpuResourceMgr_, camera, component.prePassCamera, prePassCameraHash));
1692 }
1693 }
1694 }
1695 // add cameras to data store
1696 for (auto& cam : tmpCameras) {
1697 // fill multi-view info
1698 if (cam.flags & RenderCamera::CAMERA_FLAG_MULTI_VIEW_ONLY_BIT) {
1699 if (const auto iter = mvChildToParent.find(cam.id); iter != mvChildToParent.cend()) {
1700 cam.multiViewParentCameraId = iter->second;
1701 }
1702 }
1703 dsCamera_->AddCamera(cam);
1704 }
1705 }
1706
ProcessReflection(const ComponentQuery::ResultRow & row,const PlanarReflectionComponent & reflComponent,const RenderCamera & camera,const Math::UVec2 targetRes)1707 void RenderSystem::ProcessReflection(const ComponentQuery::ResultRow& row,
1708 const PlanarReflectionComponent& reflComponent, const RenderCamera& camera, const Math::UVec2 targetRes)
1709 {
1710 // ReflectionsQuery has four required components:
1711 // (0) PlanarReflectionComponent
1712 // (1) WorldMatrixComponent
1713 // (2) NodeComponent
1714 // (3) RenderMeshComponent
1715 const WorldMatrixComponent reflectionPlaneMatrix = worldMatrixMgr_->Get(row.components[1u]);
1716
1717 // cull plane (sphere) from camera
1718 bool insideFrustum = true;
1719 if (frustumUtil_ && picking_) {
1720 const RenderMeshComponent rmc = renderMeshMgr_->Get(row.components[3U]);
1721 if (const auto meshHandle = meshMgr_->Read(rmc.mesh); meshHandle) {
1722 // frustum planes created without jitter
1723 const Frustum frustum = frustumUtil_->CreateFrustum(camera.matrices.proj * camera.matrices.view);
1724 const auto mam =
1725 picking_->GetWorldAABB(reflectionPlaneMatrix.matrix, meshHandle->aabbMin, meshHandle->aabbMax);
1726 const float radius = Math::Magnitude(mam.maxAABB - mam.minAABB) * 0.5f;
1727 const Math::Vec3 pos = Math::Vec3(reflectionPlaneMatrix.matrix[3U]);
1728 insideFrustum = frustumUtil_->SphereFrustumCollision(frustum, pos, radius);
1729 // NOTE: add normal check for camera (cull based on normal and camera view)
1730 }
1731 }
1732 if (!insideFrustum) {
1733 return; // early out
1734 }
1735
1736 // Calculate reflected view matrix from camera matrix.
1737 // Reflection plane.
1738 const Math::Vec3 translation = reflectionPlaneMatrix.matrix.w;
1739 const Math::Vec3 normal = Math::Normalize(Math::GetColumn(reflectionPlaneMatrix.matrix, 1));
1740 const float distance = -Math::Dot(normal, translation) - reflComponent.clipOffset;
1741 const Math::Vec4 plane { normal.x, normal.y, normal.z, distance };
1742
1743 // Calculate mirror matrix from plane.
1744 const Math::Mat4X4 reflection = CalculateReflectionMatrix(plane);
1745 const Math::Mat4X4 reflectedView = camera.matrices.view * reflection;
1746
1747 Math::Mat4X4 reflectedProjection = camera.matrices.proj;
1748
1749 // NOTE: Should modify near plane of projection matrix to clip in to reflection plane.
1750 // This effectively optimizes away the un-wanted objects that are behind the plane
1751 // and otherwise would be visible in the reflection.
1752 // e.g.
1753 // CalculateCameraSpaceClipPlane()
1754 // calculate camera-space projection matrix that has clip plane as near plane.
1755 // CalculateObliqueProjectionMatrix()
1756
1757 const Math::Vec4 cameraSpaceClipPlane = CalculateCameraSpaceClipPlane(reflectedView, translation, normal, -1.0f);
1758 CalculateObliqueProjectionMatrix(reflectedProjection, cameraSpaceClipPlane);
1759
1760 const ReflectionPlaneTargetUpdate rptu = UpdatePlaneReflectionTargetResolution(
1761 *gpuResourceMgr_, *gpuHandleMgr_, camera, row.entity, targetRes, reflectionMaxMipBlur_, reflComponent);
1762 if (rptu.recreated) {
1763 if (auto handle = planarReflectionMgr_->Write(row.components[0u])) {
1764 handle->renderTargetResolution[0] = rptu.renderTargetResolution[0];
1765 handle->renderTargetResolution[1] = rptu.renderTargetResolution[1];
1766 handle->colorRenderTarget = rptu.colorRenderTarget;
1767 handle->depthRenderTarget = rptu.depthRenderTarget;
1768 }
1769 UpdateReflectionPlaneMaterial(
1770 *renderMeshMgr_, *meshMgr_, *materialMgr_, row.entity, reflComponent.screenPercentage, rptu);
1771 }
1772
1773 RenderCamera reflCam;
1774 const uint64_t reflCamId = Hash(row.entity.id, camera.id);
1775 reflCam.id = reflCamId;
1776 reflCam.mainCameraId = camera.id; // link to main camera
1777 reflCam.sceneId = camera.sceneId;
1778 reflCam.layerMask = reflComponent.layerMask;
1779 reflCam.matrices.view = reflectedView;
1780 reflCam.matrices.proj = reflectedProjection;
1781 const CameraData prevFrameCamData =
1782 UpdateAndGetPreviousFrameCameraData({ reflCamId }, reflCam.matrices.view, reflCam.matrices.proj);
1783 reflCam.matrices.viewPrevFrame = prevFrameCamData.view;
1784 reflCam.matrices.projPrevFrame = prevFrameCamData.proj;
1785 const auto xFactor = (static_cast<float>(camera.renderResolution[0]) * reflComponent.screenPercentage) /
1786 static_cast<float>(rptu.renderTargetResolution[0]);
1787 const auto yFactor = (static_cast<float>(camera.renderResolution[1]) * reflComponent.screenPercentage) /
1788 static_cast<float>(rptu.renderTargetResolution[1]);
1789 reflCam.viewport = { camera.viewport[0u] * xFactor, camera.viewport[1u] * yFactor, camera.viewport[2u] * xFactor,
1790 camera.viewport[3u] * yFactor };
1791 reflCam.depthTarget = gpuHandleMgr_->GetRenderHandleReference(rptu.depthRenderTarget);
1792 reflCam.colorTargets[0u] = gpuHandleMgr_->GetRenderHandleReference(rptu.colorRenderTarget);
1793
1794 reflCam.renderResolution = { rptu.renderTargetResolution[0], rptu.renderTargetResolution[1] };
1795 reflCam.zNear = camera.zNear;
1796 reflCam.zFar = camera.zFar;
1797 reflCam.flags = (reflComponent.additionalFlags & PlanarReflectionComponent::FlagBits::MSAA_BIT)
1798 ? RenderCamera::CAMERA_FLAG_MSAA_BIT
1799 : 0U;
1800 reflCam.flags |= (RenderCamera::CAMERA_FLAG_REFLECTION_BIT | RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT);
1801 reflCam.flags |= (RenderCamera::CAMERA_FLAG_CUSTOM_TARGETS_BIT);
1802 reflCam.renderPipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
1803 reflCam.clearDepthStencil = camera.clearDepthStencil;
1804 reflCam.clearColorValues = camera.clearColorValues;
1805 reflCam.cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
1806 reflCam.environment = camera.environment;
1807 reflCam.postProcessName = DefaultMaterialCameraConstants::CAMERA_REFLECTION_POST_PROCESS_PREFIX_NAME;
1808 dsCamera_->AddCamera(reflCam);
1809 }
1810
ProcessReflections(const RenderScene & renderScene)1811 void RenderSystem::ProcessReflections(const RenderScene& renderScene)
1812 {
1813 const auto& cameras = dsCamera_->GetCameras();
1814 if (cameras.empty()) {
1815 return; // early out
1816 }
1817
1818 reflectionsQuery_.Execute();
1819 const auto queryResults = reflectionsQuery_.GetResults();
1820 if (queryResults.empty()) {
1821 return; // early out
1822 }
1823
1824 constexpr RenderCamera::Flags disableFlags { RenderCamera::CAMERA_FLAG_REFLECTION_BIT |
1825 RenderCamera::CAMERA_FLAG_SHADOW_BIT |
1826 RenderCamera::CAMERA_FLAG_OPAQUE_BIT };
1827 constexpr RenderCamera::Flags enableFlags { RenderCamera::CAMERA_FLAG_ALLOW_REFLECTION_BIT };
1828 for (const auto& row : queryResults) {
1829 // first loop all cameras to get the maximum size for this frame
1830 // might be visible with multiple cameras with different camera sizes
1831 // ReflectionsQuery has four required components:
1832 // (0) PlanarReflectionComponent
1833 // (1) WorldMatrixComponent
1834 // (2) NodeComponent
1835 // (3) RenderMeshComponent
1836 // Skip if this node is disabled.
1837 const NodeComponent nodeComponent = nodeMgr_->Get(row.components[2u]);
1838 if (!nodeComponent.effectivelyEnabled) {
1839 continue;
1840 }
1841 const PlanarReflectionComponent rc = planarReflectionMgr_->Get(row.components[0u]);
1842 if ((rc.additionalFlags & PlanarReflectionComponent::FlagBits::ACTIVE_RENDER_BIT) == 0) {
1843 continue;
1844 }
1845 Math::UVec2 targetRes = { 0U, 0U };
1846 for (const auto& cam : cameras) {
1847 if (((cam.flags & disableFlags) == 0) && ((cam.flags & enableFlags) != 0) &&
1848 (cam.sceneId == nodeComponent.sceneId)) {
1849 ProcessReflectionTargetSize(rc, cam, targetRes);
1850 }
1851 }
1852 // then process with correct frame target resolution
1853 for (const auto& cam : cameras) {
1854 if (((cam.flags & disableFlags) == 0) && ((cam.flags & enableFlags) != 0) &&
1855 (cam.sceneId == nodeComponent.sceneId)) {
1856 ProcessReflection(row, rc, cam, targetRes);
1857 }
1858 }
1859 }
1860 }
1861
ProcessLight(const LightProcessData & lpd)1862 void RenderSystem::ProcessLight(const LightProcessData& lpd)
1863 {
1864 const auto& lightComponent = lpd.lightComponent;
1865 RenderLight light { lpd.entity.id, lightComponent.lightLayerMask,
1866 { lpd.world[3u], 1.0f }, // the last column (3) of the world matrix contains the world position.
1867 { Math::Normalize(lpd.world * Math::Vec4(0.0f, 0.0f, -1.0f, 0.0f)), 0.0f },
1868 { lightComponent.color, lightComponent.intensity } };
1869
1870 // See:
1871 // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
1872 const float outer = Math::clamp(lightComponent.spotOuterAngle, lightComponent.spotInnerAngle, Math::PI / 2.0f);
1873 const float inner = Math::clamp(lightComponent.spotInnerAngle, 0.0f, outer);
1874
1875 if (lightComponent.type == LightComponent::Type::DIRECTIONAL) {
1876 light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT;
1877 } else if (lightComponent.type == LightComponent::Type::POINT) {
1878 light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_POINT_LIGHT_BIT;
1879 } else if (lightComponent.type == LightComponent::Type::SPOT) {
1880 light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_SPOT_LIGHT_BIT;
1881
1882 const float cosInnerConeAngle = cosf(inner);
1883 const float cosOuterConeAngle = cosf(outer);
1884
1885 const float lightAngleScale = 1.0f / Math::max(0.001f, cosInnerConeAngle - cosOuterConeAngle);
1886 const float lightAngleOffset = -cosOuterConeAngle * lightAngleScale;
1887
1888 light.spotLightParams = { lightAngleScale, lightAngleOffset, inner, outer };
1889 }
1890 light.range = ComponentUtilFunctions::CalculateSafeLightRange(lightComponent.range, lightComponent.intensity);
1891
1892 light.sceneId = lpd.sceneId;
1893
1894 if (lightComponent.shadowEnabled) {
1895 light.shadowFactors = { Math::clamp01(lightComponent.shadowStrength), lightComponent.shadowDepthBias,
1896 lightComponent.shadowNormalBias, 0.0f };
1897 ProcessShadowCamera(lpd, light);
1898 }
1899
1900 dsLight_->AddLight(light);
1901 }
1902
ProcessShadowCamera(const LightProcessData lpd,RenderLight & light)1903 void RenderSystem::ProcessShadowCamera(const LightProcessData lpd, RenderLight& light)
1904 {
1905 if ((light.lightUsageFlags &
1906 (RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT | RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT)) == 0) {
1907 return;
1908 }
1909 light.shadowCameraIndex = static_cast<uint32_t>(dsCamera_->GetCameraCount());
1910 if (light.shadowCameraIndex >= DefaultMaterialCameraConstants::MAX_CAMERA_COUNT) {
1911 light.shadowCameraIndex = ~0u;
1912 light.lightUsageFlags &= (~RenderLight::LightUsageFlagBits::LIGHT_USAGE_SHADOW_LIGHT_BIT);
1913 #if (CORE3D_VALIDATION_ENABLED == 1)
1914 const string onceName = string(to_string(light.id) + "_too_many_cam");
1915 CORE_LOG_ONCE_W(onceName, "CORE3D_VALIDATION: shadow camera dropped, too many cameras in scene");
1916 #endif
1917 return; // early out
1918 }
1919 light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_SHADOW_LIGHT_BIT;
1920
1921 float zNear = 0.0f;
1922 float zFar = 0.0f;
1923 RenderCamera camera;
1924 camera.id = SHADOW_CAMERA_START_UNIQUE_ID + light.shadowCameraIndex; // id used for easier uniqueness
1925 camera.sceneId = lpd.sceneId;
1926 camera.shadowId = lpd.entity.id;
1927 camera.layerMask = lpd.lightComponent.shadowLayerMask; // we respect light shadow rendering mask
1928 if (light.lightUsageFlags & RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT) {
1929 // NOTE: modifies the light camera to follow center of scene
1930 // Add slight bias offset to radius.
1931 #if (CORE3D_VALIDATION_ENABLED == 1)
1932 if (std::isinf(lpd.renderScene.worldSceneBoundingSphereRadius)) {
1933 CORE_LOG_ONCE_W("inf_scene", "Infinite world bounding sphere, shadows won't be visible.");
1934 }
1935 #endif
1936 const float nonZeroRadius = Math::max(lpd.renderScene.worldSceneBoundingSphereRadius, Math::EPSILON);
1937 const float radius = nonZeroRadius + nonZeroRadius * 0.05f;
1938 const Math::Vec3 lightPos =
1939 lpd.renderScene.worldSceneCenter - Math::Vec3(light.dir.x, light.dir.y, light.dir.z) * radius;
1940 camera.matrices.view = Math::LookAtRh(lightPos, lpd.renderScene.worldSceneCenter, { 0.0f, 1.0f, 0.0f });
1941 camera.matrices.proj = Math::OrthoRhZo(-radius, radius, -radius, radius, 0.001f, radius * 2.0f);
1942 zNear = 0.0f;
1943 zFar = 6.0f;
1944 } else if (light.lightUsageFlags & RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT) {
1945 float determinant = 0.0f;
1946 camera.matrices.view = Math::Inverse(lpd.world, determinant);
1947 const float yFov = Math::clamp(light.spotLightParams.w * 2.0f, 0.0f, Math::PI);
1948 zFar = light.range; // use light range for z far
1949 zNear = Math::max(0.1f, lpd.lightComponent.nearPlane);
1950 camera.matrices.proj = Math::PerspectiveRhZo(yFov, 1.0f, zNear, zFar);
1951 }
1952
1953 camera.matrices.proj[1][1] *= -1.0f; // left-hand NDC while Vulkan right-handed -> flip y
1954
1955 const CameraData prevFrameCamData =
1956 UpdateAndGetPreviousFrameCameraData(lpd.entity, camera.matrices.viewPrevFrame, camera.matrices.projPrevFrame);
1957 camera.matrices.viewPrevFrame = prevFrameCamData.view;
1958 camera.matrices.projPrevFrame = prevFrameCamData.proj;
1959 camera.viewport = { 0.0f, 0.0f, 1.0f, 1.0f };
1960 // get current default resolution
1961 camera.renderResolution = dsLight_->GetShadowQualityResolution();
1962 // NOTE: custom shadow camera targets not yet supported
1963 camera.zNear = zNear;
1964 camera.zFar = zFar;
1965 camera.flags = RenderCamera::CAMERA_FLAG_SHADOW_BIT;
1966 camera.cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
1967
1968 dsCamera_->AddCamera(camera);
1969 }
1970
ProcessLights(RenderScene & renderScene)1971 void RenderSystem::ProcessLights(RenderScene& renderScene)
1972 {
1973 lightQuery_.Execute();
1974
1975 uint32_t spotLightIndex = 0;
1976 for (const auto& row : lightQuery_.GetResults()) {
1977 // In addition to the base our lightQuery has two required components and two optional components:
1978 // (0) LightComponent
1979 // (1) NodeComponent
1980 // (2) WorldMatrixComponent
1981 const NodeComponent nodeComponent = nodeMgr_->Get(row.components[1u]);
1982 if (nodeComponent.effectivelyEnabled) {
1983 const LightComponent lightComponent = lightMgr_->Get(row.components[0u]);
1984 const WorldMatrixComponent renderMatrixComponent = worldMatrixMgr_->Get(row.components[2u]);
1985 const uint64_t layerMask = !row.IsValidComponentId(3u) ? LayerConstants::DEFAULT_LAYER_MASK
1986 : layerMgr_->Get(row.components[3u]).layerMask;
1987 const Math::Mat4X4 world(renderMatrixComponent.matrix.data);
1988 const LightProcessData lpd { layerMask, nodeComponent.sceneId, row.entity, lightComponent, world,
1989 renderScene, spotLightIndex };
1990 ProcessLight(lpd);
1991 }
1992 }
1993 }
1994
ProcessPostProcesses()1995 void RenderSystem::ProcessPostProcesses()
1996 {
1997 if (!renderContext_ || !postProcessMgr_ || !postProcessConfigMgr_) {
1998 return;
1999 }
2000 IRenderDataStoreManager& rdsMgr = renderContext_->GetRenderDataStoreManager();
2001 auto dsPod = refcnt_ptr<IRenderDataStorePod>(rdsMgr.GetRenderDataStore(POD_DATA_STORE_NAME));
2002 auto dsPp = refcnt_ptr<IRenderDataStorePostProcess>(rdsMgr.GetRenderDataStore(PP_DATA_STORE_NAME));
2003 if ((!dsPod) || (!dsPp)) {
2004 return;
2005 }
2006
2007 const auto postProcessCount = postProcessMgr_->GetComponentCount();
2008 for (IComponentManager::ComponentId id = 0; id < postProcessCount; ++id) {
2009 const auto handle = postProcessMgr_->Read(id);
2010 // in reality it shouldn't be possible to get an invalid handle.
2011 if (!handle) {
2012 continue;
2013 }
2014 const auto& pp = *handle;
2015
2016 // just copy values (no support for fog control)
2017 PostProcessConfiguration ppConfig;
2018 ppConfig.enableFlags = pp.enableFlags;
2019 ppConfig.bloomConfiguration = pp.bloomConfiguration;
2020 ppConfig.vignetteConfiguration = pp.vignetteConfiguration;
2021 ppConfig.colorFringeConfiguration = pp.colorFringeConfiguration;
2022 ppConfig.ditherConfiguration = pp.ditherConfiguration;
2023 ppConfig.blurConfiguration = pp.blurConfiguration;
2024 ppConfig.colorConversionConfiguration = pp.colorConversionConfiguration;
2025 ppConfig.tonemapConfiguration = pp.tonemapConfiguration;
2026 ppConfig.fxaaConfiguration = pp.fxaaConfiguration;
2027 ppConfig.taaConfiguration = pp.taaConfiguration;
2028 ppConfig.dofConfiguration = pp.dofConfiguration;
2029 ppConfig.motionBlurConfiguration = pp.motionBlurConfiguration;
2030 ppConfig.lensFlareConfiguration = pp.lensFlareConfiguration;
2031
2032 const Entity ppEntity = postProcessMgr_->GetEntity(id);
2033 const auto ppName =
2034 GetPostProcessName(postProcessMgr_, postProcessConfigMgr_, nameMgr_, properties_.dataStoreScene, ppEntity);
2035 // NOTE: camera based new post process interface integration
2036 RecalculatePostProcesses(ppName, ppConfig);
2037 auto const dataView = dsPod->Get(ppName);
2038 if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
2039 dsPod->Set(ppName, arrayviewU8(ppConfig));
2040 } else {
2041 renderProcessing_.postProcessPods.emplace_back(ppName);
2042 dsPod->CreatePod(POST_PROCESS_NAME, ppName, arrayviewU8(ppConfig));
2043 }
2044 }
2045 const auto postProcessConfigCount = postProcessConfigMgr_->GetComponentCount();
2046 for (IComponentManager::ComponentId id = 0; id < postProcessConfigCount; ++id) {
2047 // NOTE: should check if nothing has changed and not copy data if it has not changed
2048 const auto handle = postProcessConfigMgr_->Read(id);
2049 // in reality it shouldn't be possible to get an invalid handle.
2050 if (!handle) {
2051 continue;
2052 }
2053 const Entity ppEntity = postProcessConfigMgr_->GetEntity(id);
2054 const auto ppName =
2055 GetPostProcessName(postProcessMgr_, postProcessConfigMgr_, nameMgr_, properties_.dataStoreScene, ppEntity);
2056 if (!dsPp->Contains(ppName)) {
2057 renderProcessing_.postProcessConfigs.emplace_back(ppName);
2058 dsPp->Create(ppName);
2059 }
2060 for (const auto& ref : handle->postProcesses) {
2061 const IRenderDataStorePostProcess::PostProcess::Variables vars = FillPostProcessConfigurationVars(ref);
2062 if (dsPp->Contains(ppName, ref.name)) {
2063 dsPp->Set(ppName, ref.name, vars);
2064 } else {
2065 RenderHandleReference shader = gpuHandleMgr_->GetRenderHandleReference(ref.shader);
2066 dsPp->Create(ppName, ref.name, move(shader));
2067 dsPp->Set(ppName, ref.name, vars);
2068 }
2069 }
2070 }
2071 }
2072
RecalculatePostProcesses(BASE_NS::string_view name,RENDER_NS::PostProcessConfiguration & ppConfig)2073 void RenderSystem::RecalculatePostProcesses(BASE_NS::string_view name, RENDER_NS::PostProcessConfiguration& ppConfig)
2074 {
2075 // process only new post process interfaces for cameras
2076 if (ppConfig.enableFlags & PostProcessConfiguration::ENABLE_LENS_FLARE_BIT) {
2077 // fetch cameras if camera post process (should be)
2078 const auto& cameras = dsCamera_->GetCameras();
2079 for (const auto& camRef : cameras) {
2080 if (camRef.postProcessName == name) {
2081 const Math::Vec3 p = -ppConfig.lensFlareConfiguration.flarePosition;
2082 const Math::Vec3 flareDir = BASE_NS::Math::Normalize(p);
2083 // NOTE: the camera view processing should be per camera in RenderNodeDefaultCameraPostProcessController
2084 // there the inverse is already calculated
2085 const Math::Vec3 camPos = Math::Inverse(camRef.matrices.view)[3U];
2086 const float camFar = camRef.zFar;
2087
2088 const Math::Mat4X4 viewProj = camRef.matrices.proj * camRef.matrices.view;
2089
2090 Math::Vec4 viewPos = Math::Vec4(camPos + flareDir * camFar, 1.0f);
2091 Math::Vec4 clipSpacePos = viewProj * viewPos;
2092
2093 const float rW = clipSpacePos.w == 0.0f ? 0.0f : (1.0f / clipSpacePos.w);
2094 Math::Vec3 flarePosProj = Math::Vec3(clipSpacePos.x * rW, clipSpacePos.y * rW, clipSpacePos.z * rW);
2095 flarePosProj.x = 0.5f + (flarePosProj.x * 0.5f);
2096 flarePosProj.y = 0.5f + (flarePosProj.y * 0.5f);
2097 // bake the sign in for culling
2098 const float zSign = (clipSpacePos.z < 0.0f) ? 1.0f : -1.0f;
2099 flarePosProj.z = (0.5f + (flarePosProj.z * 0.5f)) * zSign;
2100
2101 // calculate flare pos for render post process
2102 ppConfig.lensFlareConfiguration.flarePosition = flarePosProj;
2103
2104 break;
2105 }
2106 }
2107 }
2108 }
2109
DestroyRenderDataStores()2110 void RenderSystem::DestroyRenderDataStores()
2111 {
2112 if (IEngine* engine = ecs_.GetClassFactory().GetInterface<IEngine>(); engine) {
2113 // check that render context is still alive
2114 if (auto renderContext =
2115 GetInstance<IRenderContext>(*engine->GetInterface<IClassRegister>(), UID_RENDER_CONTEXT);
2116 renderContext) {
2117 IRenderDataStoreManager& rdsMgr = renderContext_->GetRenderDataStoreManager();
2118 if (auto dataStore = refcnt_ptr<IRenderDataStorePod>(rdsMgr.GetRenderDataStore(POD_DATA_STORE_NAME))) {
2119 for (const auto& ref : renderProcessing_.postProcessPods) {
2120 dataStore->DestroyPod(POST_PROCESS_NAME, ref.c_str());
2121 }
2122 }
2123 if (auto dataStore =
2124 refcnt_ptr<IRenderDataStorePostProcess>(rdsMgr.GetRenderDataStore(PP_DATA_STORE_NAME))) {
2125 for (const auto& ref : renderProcessing_.postProcessConfigs) {
2126 dataStore->Destroy(ref.c_str());
2127 }
2128 }
2129 }
2130 }
2131 }
2132
FetchFullScene()2133 void RenderSystem::FetchFullScene()
2134 {
2135 if (!active_) {
2136 return;
2137 }
2138
2139 #if (CORE3D_DEV_ENABLED == 1)
2140 CORE_CPU_PERF_SCOPE("CORE3D", "RenderSystem", "FetchFullScene", CORE3D_PROFILER_DEFAULT_COLOR);
2141 #endif
2142
2143 // Process scene settings (if present), look up first active scene.
2144 const RenderConfigurationComponent renderConfig = GetRenderConfigurationComponent();
2145 const Entity cameraEntity = ProcessScene(renderConfig);
2146
2147 RenderScene renderDataScene;
2148 renderDataScene.customRenderNodeGraphFile = renderConfig.customRenderNodeGraphFile;
2149 renderDataScene.customPostSceneRenderNodeGraphFile = renderConfig.customPostSceneRenderNodeGraphFile;
2150 renderDataScene.name = properties_.dataStoreScene;
2151 renderDataScene.dataStoreNamePrefix = properties_.dataStorePrefix;
2152 renderDataScene.dataStoreNameCamera = properties_.dataStoreCamera;
2153 renderDataScene.dataStoreNameLight = properties_.dataStoreLight;
2154 renderDataScene.dataStoreNameMaterial = properties_.dataStoreMaterial;
2155 renderDataScene.dataStoreNameMorph = properties_.dataStoreMorph;
2156 constexpr double uToMsDiv = 1000.0;
2157 constexpr double uToSDiv = 1000000.0;
2158 renderDataScene.sceneDeltaTime =
2159 static_cast<float>(static_cast<double>(deltaTime_) / uToMsDiv); // real delta time used for scene as well
2160 renderDataScene.totalTime = static_cast<float>(static_cast<double>(totalTime_) / uToSDiv);
2161 renderDataScene.deltaTime = renderDataScene.sceneDeltaTime;
2162 renderDataScene.frameIndex = static_cast<uint32_t>((frameIndex_ % std::numeric_limits<uint32_t>::max()));
2163 renderProcessing_.frameFlags = 0; // zero frame flags for camera processing
2164
2165 ProcessEnvironments(renderConfig);
2166 ProcessCameras(renderConfig, cameraEntity, renderDataScene);
2167 ProcessReflections(renderDataScene);
2168 ProcessPostProcesses();
2169
2170 // Process all render components.
2171 ProcessRenderables();
2172
2173 // fill frame flags after renderable processing
2174 EvaluateFrameObjectFlags();
2175
2176 // Process render node graphs automatically based on camera if needed bits set for properties
2177 // Some materials might request color pre-pass etc. (needs to be done after renderables are processed)
2178 ProcessRenderNodeGraphs(renderConfig, renderDataScene);
2179
2180 // NOTE: move world sphere calculation to own system
2181 const auto boundingSphere = static_cast<RenderPreprocessorSystem*>(renderPreprocessorSystem_)->GetBoundingSphere();
2182 sceneBoundingSpherePosition_ = boundingSphere.center;
2183 sceneBoundingSphereRadius_ = boundingSphere.radius;
2184
2185 renderDataScene.worldSceneCenter = sceneBoundingSpherePosition_;
2186 renderDataScene.worldSceneBoundingSphereRadius = sceneBoundingSphereRadius_;
2187
2188 // Process lights.
2189 ProcessLights(renderDataScene);
2190
2191 dsScene_->SetScene(renderDataScene);
2192
2193 // Remove prev frame data from not used cameras
2194 for (auto iter = cameraData_.begin(); iter != cameraData_.end();) {
2195 if (iter->second.lastFrameIndex != frameIndex_) {
2196 iter = cameraData_.erase(iter);
2197 } else {
2198 ++iter;
2199 }
2200 }
2201 }
2202
ProcessRenderNodeGraphs(const RenderConfigurationComponent & renderConfig,const RenderScene & renderScene)2203 void RenderSystem::ProcessRenderNodeGraphs(
2204 const RenderConfigurationComponent& renderConfig, const RenderScene& renderScene)
2205 {
2206 auto& orderedRngs = renderProcessing_.orderedRenderNodeGraphs;
2207 orderedRngs.clear();
2208 const bool createRngs =
2209 (renderConfig.renderingFlags & RenderConfigurationComponent::SceneRenderingFlagBits::CREATE_RNGS_BIT);
2210 if (createRngs && graphicsContext_ && renderUtil_) {
2211 struct CameraOrdering {
2212 uint64_t id { RenderSceneDataConstants::INVALID_ID };
2213 uint64_t mainId { RenderSceneDataConstants::INVALID_ID };
2214 size_t renderCameraIdx { 0 };
2215 };
2216 const auto& renderCameras = dsCamera_->GetCameras();
2217 vector<CameraOrdering> baseCameras;
2218 vector<CameraOrdering> depCameras;
2219 baseCameras.reserve(renderCameras.size());
2220 depCameras.reserve(renderCameras.size());
2221 size_t mainCamIdx = size_t(~0);
2222 // ignore shadow and multi-view only cameras
2223 constexpr uint32_t ignoreFlags { RenderCamera::CAMERA_FLAG_SHADOW_BIT |
2224 RenderCamera::CAMERA_FLAG_MULTI_VIEW_ONLY_BIT };
2225 for (size_t camIdx = 0; camIdx < renderCameras.size(); ++camIdx) {
2226 const auto& cam = renderCameras[camIdx];
2227 if ((cam.flags & ignoreFlags) == 0) {
2228 if (cam.flags & RenderCamera::CAMERA_FLAG_MAIN_BIT) {
2229 mainCamIdx = camIdx;
2230 } else {
2231 if (cam.mainCameraId == RenderSceneDataConstants::INVALID_ID) {
2232 baseCameras.push_back({ cam.id, cam.mainCameraId, camIdx });
2233 } else {
2234 // do not add pre-pass camera if render processing does not need it
2235 if (cam.flags & RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT) {
2236 if (renderProcessing_.frameFlags & NEEDS_COLOR_PRE_PASS) {
2237 depCameras.push_back({ cam.id, cam.mainCameraId, camIdx });
2238 }
2239 } else {
2240 depCameras.push_back({ cam.id, cam.mainCameraId, camIdx });
2241 }
2242 }
2243 }
2244 }
2245 }
2246 // main camera needs to be the last
2247 if (mainCamIdx < renderCameras.size()) {
2248 const auto& cam = renderCameras[mainCamIdx];
2249 baseCameras.push_back({ cam.id, cam.mainCameraId, mainCamIdx });
2250 }
2251 // insert dependency cameras to correct positions
2252 for (const auto& depCam : depCameras) {
2253 for (size_t idx = 0; idx < baseCameras.size(); ++idx) {
2254 if (depCam.mainId == baseCameras[idx].id) {
2255 baseCameras.insert(baseCameras.begin() + int64_t(idx), depCam);
2256 break;
2257 }
2258 }
2259 }
2260 // now cameras are in correct order if the dependencied were correct in RenderCameras
2261
2262 // first create scene render node graph if needed
2263 // we need to have scene render node graph as a separate
2264 orderedRngs.push_back(GetSceneRenderNodeGraph(renderScene));
2265
2266 // then, add valid camera render node graphs
2267 for (const auto& cam : baseCameras) {
2268 CORE_ASSERT(cam.renderCameraIdx < renderCameras.size());
2269 const auto& camRef = renderCameras[cam.renderCameraIdx];
2270 CORE_ASSERT(camRef.id != 0xFFFFFFFFffffffff); // there must be an id for uniqueness
2271 CameraRngsOutput camRngs = GetCameraRenderNodeGraphs(renderScene, camRef);
2272 if (camRngs.rngs.rngHandle) {
2273 orderedRngs.push_back(move(camRngs.rngs.rngHandle));
2274 if (camRngs.rngs.ppRngHandle) {
2275 orderedRngs.push_back(move(camRngs.rngs.ppRngHandle));
2276 }
2277 for (uint32_t mvIdx = 0U; mvIdx < RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT;
2278 ++mvIdx) {
2279 if (camRngs.multiviewPpHandles[mvIdx]) {
2280 orderedRngs.push_back(move(camRngs.multiviewPpHandles[mvIdx]));
2281 }
2282 }
2283 }
2284 }
2285 // then possible post scene custom render node graph
2286 if (renderProcessing_.sceneRngs.customPostRng) {
2287 orderedRngs.push_back(renderProcessing_.sceneRngs.customPostRng);
2288 }
2289 // destroy unused after two frames
2290 const uint64_t ageLimit = (frameIndex_ < 2) ? 0 : (frameIndex_ - 2);
2291 for (auto iter = renderProcessing_.camIdToRng.begin(); iter != renderProcessing_.camIdToRng.end();) {
2292 if (iter->second.lastFrameIndex < ageLimit) {
2293 iter = renderProcessing_.camIdToRng.erase(iter);
2294 } else {
2295 ++iter;
2296 }
2297 }
2298 }
2299 }
2300
GetCameraRenderNodeGraphs(const RenderScene & renderScene,const RenderCamera & renderCamera)2301 RenderSystem::CameraRngsOutput RenderSystem::GetCameraRenderNodeGraphs(
2302 const RenderScene& renderScene, const RenderCamera& renderCamera)
2303 {
2304 constexpr uint32_t rngChangeFlags =
2305 RenderCamera::CAMERA_FLAG_MSAA_BIT | RenderCamera::CAMERA_FLAG_CUSTOM_TARGETS_BIT;
2306 auto createNewRngs = [](auto& rngm, const auto& rnUtil, const auto& scene, const auto& obj, const auto& mvCams) {
2307 const auto descs = rnUtil->GetRenderNodeGraphDescs(scene, obj, 0, mvCams);
2308 CameraRngsOutput rngs;
2309 rngs.rngs.rngHandle = rngm.Create(
2310 IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, descs.camera, {}, scene.name);
2311 if (!descs.postProcess.nodes.empty()) {
2312 rngs.rngs.ppRngHandle =
2313 rngm.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC,
2314 descs.postProcess, {}, scene.name);
2315 }
2316 for (size_t mvIdx = 0; mvIdx < mvCams.size(); ++mvIdx) {
2317 rngs.multiviewPpHandles[mvIdx] =
2318 rngm.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC,
2319 descs.multiViewCameraPostProcesses[mvIdx], {}, scene.name);
2320 }
2321 return rngs;
2322 };
2323
2324 IRenderNodeGraphManager& rngm = renderContext_->GetRenderNodeGraphManager();
2325 CameraRngsOutput rngs;
2326 rngs.rngs.rngHandle = renderCamera.customRenderNodeGraph;
2327 if (!rngs.rngs.rngHandle) {
2328 if (auto iter = renderProcessing_.camIdToRng.find(renderCamera.id);
2329 iter != renderProcessing_.camIdToRng.cend()) {
2330 // NOTE: not optimal, currently re-creates a render node graph if:
2331 // * msaa flags have changed
2332 // * post process name / component has changed
2333 // * pipeline has changed
2334 // * rng files have changed
2335 // * multi-view count has changed
2336 const bool reCreate =
2337 ((iter->second.flags & rngChangeFlags) != (renderCamera.flags & rngChangeFlags)) ||
2338 (iter->second.postProcessName != renderCamera.postProcessName) ||
2339 (iter->second.renderPipelineType != renderCamera.renderPipelineType) ||
2340 (iter->second.customRngFile != renderCamera.customRenderNodeGraphFile) ||
2341 (iter->second.customPostProcessRngFile != renderCamera.customPostProcessRenderNodeGraphFile) ||
2342 (iter->second.multiViewCameraCount != renderCamera.multiViewCameraCount) ||
2343 (iter->second.multiViewCameraHash != renderCamera.multiViewCameraHash);
2344 if (reCreate) {
2345 iter->second.rngs = {};
2346 const vector<RenderCamera> multiviewCameras = GetMultiviewCameras(renderCamera);
2347 auto newRngs = createNewRngs(rngm, renderUtil_, renderScene, renderCamera, multiviewCameras);
2348 // copy
2349 rngs = newRngs;
2350 iter->second.rngs = move(newRngs.rngs);
2351 // update multiview post process
2352 for (size_t mvIdx = 0; mvIdx < multiviewCameras.size(); ++mvIdx) {
2353 const auto& mvCamera = multiviewCameras[mvIdx];
2354 auto& mvData = renderProcessing_.camIdToRng[mvCamera.id];
2355 mvData.rngs.ppRngHandle = move(newRngs.multiviewPpHandles[mvIdx]);
2356 mvData.lastFrameIndex = frameIndex_;
2357 }
2358 } else {
2359 // found and copy the handles
2360 rngs.rngs = iter->second.rngs;
2361 // multiview post processes
2362 for (uint32_t mvIdx = 0; mvIdx < renderCamera.multiViewCameraCount; ++mvIdx) {
2363 auto& mvData = renderProcessing_.camIdToRng[renderCamera.multiViewCameraIds[mvIdx]];
2364 rngs.multiviewPpHandles[mvIdx] = mvData.rngs.ppRngHandle;
2365 mvData.lastFrameIndex = frameIndex_;
2366 }
2367 }
2368 iter->second.flags = renderCamera.flags;
2369 iter->second.renderPipelineType = renderCamera.renderPipelineType;
2370 iter->second.lastFrameIndex = frameIndex_;
2371 iter->second.postProcessName = renderCamera.postProcessName;
2372 iter->second.customRngFile = renderCamera.customRenderNodeGraphFile;
2373 iter->second.customPostProcessRngFile = renderCamera.customPostProcessRenderNodeGraphFile;
2374 iter->second.multiViewCameraCount = renderCamera.multiViewCameraCount;
2375 iter->second.multiViewCameraHash = renderCamera.multiViewCameraHash;
2376 } else {
2377 const vector<RenderCamera> multiviewCameras = GetMultiviewCameras(renderCamera);
2378 auto newRngs = createNewRngs(rngm, renderUtil_, renderScene, renderCamera, multiviewCameras);
2379 rngs = newRngs;
2380 renderProcessing_.camIdToRng[renderCamera.id] = { move(newRngs.rngs), renderCamera.flags,
2381 renderCamera.renderPipelineType, frameIndex_, renderCamera.postProcessName,
2382 renderCamera.customRenderNodeGraphFile, renderCamera.customPostProcessRenderNodeGraphFile,
2383 renderCamera.multiViewCameraCount, renderCamera.multiViewCameraHash };
2384 // update multiview post process
2385 for (size_t mvIdx = 0; mvIdx < multiviewCameras.size(); ++mvIdx) {
2386 const auto& mvCamera = multiviewCameras[mvIdx];
2387 auto& mvData = renderProcessing_.camIdToRng[mvCamera.id];
2388 mvData.rngs.ppRngHandle = move(newRngs.multiviewPpHandles[mvIdx]);
2389 mvData.lastFrameIndex = frameIndex_;
2390 }
2391 }
2392 }
2393 return rngs;
2394 }
2395
GetSceneRenderNodeGraph(const RenderScene & renderScene)2396 RenderHandleReference RenderSystem::GetSceneRenderNodeGraph(const RenderScene& renderScene)
2397 {
2398 IRenderNodeGraphManager& rngm = renderContext_->GetRenderNodeGraphManager();
2399 auto createNewRng = [](auto& rngm, const auto& rnUtil, const auto& scene) {
2400 const RenderNodeGraphDesc desc = rnUtil->GetRenderNodeGraphDesc(scene, 0);
2401 return rngm.Create(
2402 IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, desc, {}, scene.name);
2403 };
2404 auto createNewCustomRng = [](auto& rngm, const auto& rnUtil, const auto& scene, const auto& rngFile) {
2405 const RenderNodeGraphDesc desc = rnUtil->GetRenderNodeGraphDesc(scene, rngFile, 0);
2406 return rngm.Create(
2407 IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, desc, {}, scene.name);
2408 };
2409
2410 // first check if there's custom render node graph file
2411 // if not, use the default
2412 RenderHandleReference handle;
2413 if (!renderScene.customRenderNodeGraphFile.empty()) {
2414 const bool reCreate = (renderProcessing_.sceneRngs.customRngFile != renderScene.customRenderNodeGraphFile);
2415 if (reCreate) {
2416 renderProcessing_.sceneRngs.customRng = createNewRng(rngm, renderUtil_, renderScene);
2417 }
2418 handle = renderProcessing_.sceneRngs.customRng;
2419 renderProcessing_.sceneRngs.customRngFile = renderScene.customRenderNodeGraphFile;
2420 } else {
2421 // clear
2422 renderProcessing_.sceneRngs.customRng = {};
2423 renderProcessing_.sceneRngs.customRngFile.clear();
2424 }
2425 if (!handle) {
2426 if ((!renderProcessing_.sceneRngs.rng)) {
2427 renderProcessing_.sceneRngs.rng = createNewRng(rngm, renderUtil_, renderScene);
2428 }
2429 handle = renderProcessing_.sceneRngs.rng;
2430 }
2431
2432 // process custom post scene render node graph
2433 // NOTE: it is not returned by the method
2434 if (!renderScene.customPostSceneRenderNodeGraphFile.empty()) {
2435 const bool reCreate =
2436 (renderProcessing_.sceneRngs.customPostSceneRngFile != renderScene.customPostSceneRenderNodeGraphFile);
2437 if (reCreate) {
2438 renderProcessing_.sceneRngs.customPostRng =
2439 createNewCustomRng(rngm, renderUtil_, renderScene, renderScene.customPostSceneRenderNodeGraphFile);
2440 }
2441 renderProcessing_.sceneRngs.customPostSceneRngFile = renderScene.customPostSceneRenderNodeGraphFile;
2442 } else {
2443 // clear
2444 renderProcessing_.sceneRngs.customPostRng = {};
2445 renderProcessing_.sceneRngs.customPostSceneRngFile.clear();
2446 }
2447
2448 return handle;
2449 }
2450
GetRenderNodeGraphs() const2451 array_view<const RenderHandleReference> RenderSystem::GetRenderNodeGraphs() const
2452 {
2453 if (renderProcessing_.frameProcessed) {
2454 return renderProcessing_.orderedRenderNodeGraphs;
2455 } else {
2456 return {};
2457 }
2458 }
2459
UpdateAndGetPreviousFrameCameraData(const Entity & entity,const Math::Mat4X4 & view,const Math::Mat4X4 & proj)2460 RenderSystem::CameraData RenderSystem::UpdateAndGetPreviousFrameCameraData(
2461 const Entity& entity, const Math::Mat4X4& view, const Math::Mat4X4& proj)
2462 {
2463 CameraData currData = { view, proj, frameIndex_ };
2464 if (auto iter = cameraData_.find(entity); iter != cameraData_.end()) {
2465 const CameraData prevData = iter->second;
2466 iter->second = currData;
2467 return prevData; // correct previous frame matrices
2468 } else {
2469 cameraData_.insert_or_assign(entity, currData);
2470 return currData; // current frame returned because of no prev frame matrices
2471 }
2472 }
2473
GetMultiviewCameras(const RenderCamera & renderCamera)2474 vector<RenderCamera> RenderSystem::GetMultiviewCameras(const RenderCamera& renderCamera)
2475 {
2476 vector<RenderCamera> mvCameras;
2477 if (renderCamera.multiViewCameraCount > 0U) {
2478 const auto& cameras = dsCamera_->GetCameras();
2479 for (uint32_t camIdx = 0; camIdx < renderCamera.multiViewCameraCount; ++camIdx) {
2480 const uint32_t ci = dsCamera_->GetCameraIndex(renderCamera.multiViewCameraIds[camIdx]);
2481 if (ci < cameras.size()) {
2482 mvCameras.push_back(cameras[ci]);
2483 }
2484 }
2485 }
2486 return mvCameras;
2487 }
2488
IRenderSystemInstance(IEcs & ecs)2489 ISystem* IRenderSystemInstance(IEcs& ecs)
2490 {
2491 return new RenderSystem(ecs);
2492 }
2493
IRenderSystemDestroy(ISystem * instance)2494 void IRenderSystemDestroy(ISystem* instance)
2495 {
2496 delete static_cast<RenderSystem*>(instance);
2497 }
2498 CORE3D_END_NAMESPACE()
2499