• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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