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