• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 <PropertyTools/property_api_impl.inl>
26 #include <PropertyTools/property_macros.h>
27 
28 #include <3d/ecs/components/camera_component.h>
29 #include <3d/ecs/components/environment_component.h>
30 #include <3d/ecs/components/fog_component.h>
31 #include <3d/ecs/components/joint_matrices_component.h>
32 #include <3d/ecs/components/layer_component.h>
33 #include <3d/ecs/components/light_component.h>
34 #include <3d/ecs/components/material_component.h>
35 #include <3d/ecs/components/material_extension_component.h>
36 #include <3d/ecs/components/mesh_component.h>
37 #include <3d/ecs/components/name_component.h>
38 #include <3d/ecs/components/node_component.h>
39 #include <3d/ecs/components/planar_reflection_component.h>
40 #include <3d/ecs/components/post_process_component.h>
41 #include <3d/ecs/components/render_configuration_component.h>
42 #include <3d/ecs/components/render_handle_component.h>
43 #include <3d/ecs/components/render_mesh_batch_component.h>
44 #include <3d/ecs/components/render_mesh_component.h>
45 #include <3d/ecs/components/skin_component.h>
46 #include <3d/ecs/components/skin_joints_component.h>
47 #include <3d/ecs/components/uri_component.h>
48 #include <3d/ecs/components/world_matrix_component.h>
49 #include <3d/ecs/systems/intf_node_system.h>
50 #include <3d/ecs/systems/intf_render_preprocessor_system.h>
51 #include <3d/ecs/systems/intf_skinning_system.h>
52 #include <3d/implementation_uids.h>
53 #include <3d/intf_graphics_context.h>
54 #include <3d/render/intf_render_data_store_default_camera.h>
55 #include <3d/render/intf_render_data_store_default_light.h>
56 #include <3d/render/intf_render_data_store_default_material.h>
57 #include <3d/render/intf_render_data_store_default_scene.h>
58 #include <3d/util/intf_mesh_util.h>
59 #include <3d/util/intf_picking.h>
60 #include <3d/util/intf_render_util.h>
61 #include <base/containers/string.h>
62 #include <base/math/float_packer.h>
63 #include <base/math/matrix_util.h>
64 #include <base/math/quaternion_util.h>
65 #include <base/math/vector.h>
66 #include <base/math/vector_util.h>
67 #include <core/ecs/intf_ecs.h>
68 #include <core/ecs/intf_entity_manager.h>
69 #include <core/implementation_uids.h>
70 #include <core/intf_engine.h>
71 #include <core/log.h>
72 #include <core/namespace.h>
73 #include <core/perf/cpu_perf_scope.h>
74 #include <core/perf/intf_performance_data_manager.h>
75 #include <core/plugin/intf_plugin_register.h>
76 #include <render/datastore/intf_render_data_store_manager.h>
77 #include <render/datastore/intf_render_data_store_pod.h>
78 #include <render/datastore/render_data_store_render_pods.h>
79 #include <render/device/intf_gpu_resource_manager.h>
80 #include <render/device/intf_shader_manager.h>
81 #include <render/device/pipeline_state_desc.h>
82 #include <render/implementation_uids.h>
83 #include <render/intf_render_context.h>
84 #include <render/nodecontext/intf_render_node_graph_manager.h>
85 #include <render/resource_handle.h>
86 
87 #include "ecs/components/previous_joint_matrices_component.h"
88 #include "ecs/components/previous_world_matrix_component.h"
89 #include "util/component_util_functions.h"
90 #include "util/mesh_util.h"
91 #include "util/uri_lookup.h"
92 
93 CORE_BEGIN_NAMESPACE()
94 DECLARE_PROPERTY_TYPE(RENDER_NS::IRenderDataStoreManager*);
95 CORE_END_NAMESPACE()
96 
97 CORE3D_BEGIN_NAMESPACE()
98 using namespace RENDER_NS;
99 using namespace BASE_NS;
100 using namespace CORE_NS;
101 
102 namespace {
103 static const RenderSubmesh INIT {};
104 static const MaterialComponent DEF_MATERIAL_COMPONENT {};
105 static constexpr uint32_t NEEDS_COLOR_PRE_PASS { 1u << 0u };
106 static constexpr uint64_t PREPASS_CAMERA_START_UNIQUE_ID { 1 };
107 static constexpr uint64_t SHADOW_CAMERA_START_UNIQUE_ID { 100 };
108 #if (CORE3D_VALIDATION_ENABLED == 1)
109 static constexpr uint32_t MAX_BATCH_SUBMESH_COUNT { 64u };
110 #endif
111 
112 static constexpr uint32_t MAX_BATCH_OBJECT_COUNT { PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE /
113                                                    PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
114 
115 // typename for POD data. (e.g. "PostProcess") (core/render/intf_render_data_store_pod.h)
116 static constexpr string_view POST_PROCESS_NAME { "PostProcess" };
117 static constexpr string_view POD_DATA_STORE_NAME { "RenderDataStorePod" };
118 
CreateReflectionPlaneGpuImageDesc(bool depthImage)119 constexpr GpuImageDesc CreateReflectionPlaneGpuImageDesc(bool depthImage)
120 {
121     GpuImageDesc desc;
122     desc.depth = 1;
123     desc.format = depthImage ? Format::BASE_FORMAT_D16_UNORM : Format::BASE_FORMAT_R8G8B8A8_SRGB;
124     desc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
125     desc.usageFlags = depthImage ? ImageUsageFlags(ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
126                                                    ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)
127                                  : ImageUsageFlags(ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
128                                                    ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT);
129     desc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
130     desc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
131     desc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
132     desc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
133     return desc;
134 }
135 
GetRenderCameraFlagsFromComponentFlags(const uint32_t pipelineFlags)136 constexpr uint32_t GetRenderCameraFlagsFromComponentFlags(const uint32_t pipelineFlags)
137 {
138     uint32_t flags = 0;
139     if (pipelineFlags & CameraComponent::PipelineFlagBits::MSAA_BIT) {
140         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT;
141     }
142     if (pipelineFlags & CameraComponent::PipelineFlagBits::CLEAR_DEPTH_BIT) {
143         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_CLEAR_DEPTH_BIT;
144     }
145     if (pipelineFlags & CameraComponent::PipelineFlagBits::CLEAR_COLOR_BIT) {
146         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_CLEAR_COLOR_BIT;
147     }
148     if (pipelineFlags & CameraComponent::PipelineFlagBits::HISTORY_BIT) {
149         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_HISTORY_BIT;
150     }
151     if (pipelineFlags & CameraComponent::PipelineFlagBits::JITTER_BIT) {
152         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_JITTER_BIT;
153     }
154     if (pipelineFlags & CameraComponent::PipelineFlagBits::VELOCITY_OUTPUT_BIT) {
155         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_VELOCITY_NORMAL_BIT;
156     }
157     if (pipelineFlags & CameraComponent::PipelineFlagBits::DEPTH_OUTPUT_BIT) {
158         flags |= RenderCamera::CameraFlagBits::CAMERA_FLAG_OUTPUT_DEPTH_BIT;
159     }
160     // NOTE: color pre pass bit is not currently enabled from here
161     return flags;
162 }
163 
GetRenderCameraCullTypeFromComponent(const CameraComponent::Culling cameraCullType)164 constexpr inline RenderCamera::CameraCullType GetRenderCameraCullTypeFromComponent(
165     const CameraComponent::Culling cameraCullType)
166 {
167     RenderCamera::CameraCullType cullType(RenderCamera::CameraCullType::CAMERA_CULL_NONE);
168     if (cameraCullType == CameraComponent::Culling::VIEW_FRUSTUM) {
169         cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
170     }
171     return cullType;
172 }
173 
GetRenderCameraRenderPipelineTypeFromComponent(const CameraComponent::RenderingPipeline cameraRenderPipelineType)174 constexpr inline RenderCamera::RenderPipelineType GetRenderCameraRenderPipelineTypeFromComponent(
175     const CameraComponent::RenderingPipeline cameraRenderPipelineType)
176 {
177     RenderCamera::RenderPipelineType pipelineType(RenderCamera::RenderPipelineType::FORWARD);
178     if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::LIGHT_FORWARD) {
179         pipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
180     } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::FORWARD) {
181         pipelineType = RenderCamera::RenderPipelineType::FORWARD;
182     } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::DEFERRED) {
183         pipelineType = RenderCamera::RenderPipelineType::DEFERRED;
184     } else if (cameraRenderPipelineType == CameraComponent::RenderingPipeline::CUSTOM) {
185         pipelineType = RenderCamera::RenderPipelineType::CUSTOM;
186     }
187     return pipelineType;
188 }
189 
ValidateRenderCamera(RenderCamera & camera)190 void ValidateRenderCamera(RenderCamera& camera)
191 {
192     if (camera.renderPipelineType == RenderCamera::RenderPipelineType::DEFERRED) {
193         if (camera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT) {
194             camera.flags = camera.flags & (~RenderCamera::CameraFlagBits::CAMERA_FLAG_MSAA_BIT);
195 #if (CORE3D_VALIDATION_ENABLED == 1)
196             CORE_LOG_ONCE_I("valid_r_c" + to_string(camera.id),
197                 "MSAA flag with deferred pipeline dropped (cam id %" PRIu64 ")", camera.id);
198 #endif
199         }
200     }
201 }
202 
GetPostProcessName(const IPostProcessComponentManager * postProcessMgr,const Entity & entity)203 inline fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> GetPostProcessName(
204     const IPostProcessComponentManager* postProcessMgr, const Entity& entity)
205 {
206     fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> ret =
207         DefaultMaterialCameraConstants::CAMERA_POST_PROCESS_PREFIX_NAME;
208     if (postProcessMgr && postProcessMgr->HasComponent(entity)) {
209         ret.append(to_string(entity.id));
210     }
211     return ret;
212 }
213 
GetCameraName(INameComponentManager & nameMgr,const Entity & entity)214 inline fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> GetCameraName(
215     INameComponentManager& nameMgr, const Entity& entity)
216 {
217     fixed_string<RenderDataConstants::MAX_DEFAULT_NAME_LENGTH> ret;
218     if (ScopedHandle<const NameComponent> nameHandle = nameMgr.Read(entity); nameHandle) {
219         ret.append(nameHandle->name);
220     } else {
221         ret.append(to_string(entity.id));
222     }
223     return ret;
224 }
225 
226 // does not update all the variables
FillRenderCameraBaseFromCameraComponent(const IRenderHandleComponentManager & renderHandleMgr,const CameraComponent & cameraComponent,RenderCamera & renderCamera,const bool checkCustomTargets)227 void FillRenderCameraBaseFromCameraComponent(const IRenderHandleComponentManager& renderHandleMgr,
228     const CameraComponent& cameraComponent, RenderCamera& renderCamera, const bool checkCustomTargets)
229 {
230     renderCamera.layerMask = cameraComponent.layerMask;
231     renderCamera.viewport = { cameraComponent.viewport[0u], cameraComponent.viewport[1u], cameraComponent.viewport[2u],
232         cameraComponent.viewport[3u] };
233     renderCamera.scissor = { cameraComponent.scissor[0u], cameraComponent.scissor[1u], cameraComponent.scissor[2u],
234         cameraComponent.scissor[3u] };
235     renderCamera.renderResolution = { cameraComponent.renderResolution[0u], cameraComponent.renderResolution[1u] };
236     renderCamera.zNear = cameraComponent.zNear;
237     renderCamera.zFar = cameraComponent.zFar;
238     renderCamera.flags = GetRenderCameraFlagsFromComponentFlags(cameraComponent.pipelineFlags);
239     renderCamera.clearDepthStencil = { cameraComponent.clearDepthValue, 0u };
240     renderCamera.clearColorValues = { cameraComponent.clearColorValue.x, cameraComponent.clearColorValue.y,
241         cameraComponent.clearColorValue.z, cameraComponent.clearColorValue.w };
242     renderCamera.cullType = GetRenderCameraCullTypeFromComponent(cameraComponent.culling);
243     renderCamera.renderPipelineType = GetRenderCameraRenderPipelineTypeFromComponent(cameraComponent.renderingPipeline);
244     if (cameraComponent.customRenderNodeGraph) {
245         renderCamera.customRenderNodeGraph =
246             renderHandleMgr.GetRenderHandleReference(cameraComponent.customRenderNodeGraph);
247     }
248     renderCamera.customRenderNodeGraphFile = cameraComponent.customRenderNodeGraphFile;
249     const uint32_t maxCount = BASE_NS::Math::min(static_cast<uint32_t>(cameraComponent.colorTargetCustomization.size()),
250         RenderSceneDataConstants::MAX_CAMERA_COLOR_TARGET_COUNT);
251     for (uint32_t idx = 0; idx < maxCount; ++idx) {
252         renderCamera.colorTargetCustomization[idx].format = cameraComponent.colorTargetCustomization[idx].format;
253         renderCamera.colorTargetCustomization[idx].usageFlags =
254             cameraComponent.colorTargetCustomization[idx].usageFlags;
255     }
256     renderCamera.depthTargetCustomization.format = cameraComponent.depthTargetCustomization.format;
257     renderCamera.depthTargetCustomization.usageFlags = cameraComponent.depthTargetCustomization.usageFlags;
258 
259     if (checkCustomTargets && (cameraComponent.customColorTargets.size() > 0 || cameraComponent.customDepthTarget)) {
260         renderCamera.targetType = RenderCamera::CameraTargetType::TARGET_TYPE_CUSTOM_TARGETS;
261         RenderHandleReference customColorTarget;
262         if (cameraComponent.customColorTargets.size() > 0) {
263             customColorTarget = renderHandleMgr.GetRenderHandleReference(cameraComponent.customColorTargets[0]);
264         }
265         RenderHandleReference customDepthTarget =
266             renderHandleMgr.GetRenderHandleReference(cameraComponent.customDepthTarget);
267         if (customColorTarget.GetHandleType() != RenderHandleType::GPU_IMAGE) {
268             CORE_LOG_E("invalid custom render target(s) for camera (%s)", renderCamera.name.c_str());
269         }
270         renderCamera.depthTarget = move(customDepthTarget);
271         renderCamera.colorTargets[0u] = move(customColorTarget);
272     }
273 
274     ValidateRenderCamera(renderCamera);
275 }
276 
CreateColorPrePassRenderCamera(const IRenderHandleComponentManager & renderHandleMgr,const ICameraComponentManager & cameraMgr,const RenderCamera & baseCamera,const Entity & prePassEntity,const uint64_t uniqueId)277 RenderCamera CreateColorPrePassRenderCamera(const IRenderHandleComponentManager& renderHandleMgr,
278     const ICameraComponentManager& cameraMgr, const RenderCamera& baseCamera, const Entity& prePassEntity,
279     const uint64_t uniqueId)
280 {
281     RenderCamera rc = baseCamera;
282     // reset targets, pre-pass does not support custom targets nor uses main camera targets
283     rc.depthTarget = {};
284     for (uint32_t idx = 0; idx < countof(rc.colorTargets); ++idx) {
285         rc.colorTargets[idx] = {};
286     }
287     // NOTE: LIGHT_FORWARD prevents additional HDR target creation
288     rc.renderPipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
289     if (const auto prePassCameraHandle = cameraMgr.Read(prePassEntity); prePassCameraHandle) {
290         FillRenderCameraBaseFromCameraComponent(renderHandleMgr, *prePassCameraHandle, rc, false);
291         rc.flags |= RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT | RenderCamera::CAMERA_FLAG_OPAQUE_BIT |
292                     RenderCamera::CAMERA_FLAG_CLEAR_DEPTH_BIT | RenderCamera::CAMERA_FLAG_CLEAR_COLOR_BIT;
293         // NOTE: does not evaluate custom targets for pre-pass camera
294     } else {
295         // automatic reduction to half res.
296         rc.renderResolution = { static_cast<uint32_t>(static_cast<float>(rc.renderResolution[0]) * 0.5f),
297             static_cast<uint32_t>(static_cast<float>(rc.renderResolution[1]) * 0.5f) };
298         // NOTE: should better evaluate all the flags from the main camera
299         rc.flags = RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT | RenderCamera::CAMERA_FLAG_OPAQUE_BIT |
300                    RenderCamera::CAMERA_FLAG_CLEAR_DEPTH_BIT | RenderCamera::CAMERA_FLAG_CLEAR_COLOR_BIT;
301     }
302     rc.name = to_string(uniqueId);
303     rc.id = uniqueId; // unique id for main pre-pass
304     rc.prePassColorTarget = {};
305     rc.prePassColorTargetName = {};
306     rc.postProcessName = DefaultMaterialCameraConstants::CAMERA_PRE_PASS_POST_PROCESS_PREFIX_NAME;
307     return rc;
308 }
309 
FillRenderEnvironment(const IRenderHandleComponentManager * renderHandleMgr,const uint64_t & nodeLayerMask,const Entity & entity,const EnvironmentComponent & component,RenderCamera::Environment & renderEnv)310 void FillRenderEnvironment(const IRenderHandleComponentManager* renderHandleMgr, const uint64_t& nodeLayerMask,
311     const Entity& entity, const EnvironmentComponent& component, RenderCamera::Environment& renderEnv)
312 {
313     renderEnv.id = entity.id;
314     renderEnv.layerMask = nodeLayerMask;
315     renderEnv.shader = renderHandleMgr->GetRenderHandleReference(component.shader);
316     if (component.background == EnvironmentComponent::Background::NONE) {
317         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_NONE;
318     } else if (component.background == EnvironmentComponent::Background::IMAGE) {
319         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_IMAGE;
320     } else if (component.background == EnvironmentComponent::Background::CUBEMAP) {
321         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_CUBEMAP;
322     } else if (component.background == EnvironmentComponent::Background::EQUIRECTANGULAR) {
323         renderEnv.backgroundType = RenderCamera::Environment::BG_TYPE_EQUIRECTANGULAR;
324     }
325     renderEnv.radianceCubemap = renderHandleMgr->GetRenderHandleReference(component.radianceCubemap);
326     renderEnv.radianceCubemapMipCount = component.radianceCubemapMipCount;
327     renderEnv.envMap = renderHandleMgr->GetRenderHandleReference(component.envMap);
328     renderEnv.envMapLodLevel = component.envMapLodLevel;
329     const size_t shCount =
330         std::min(countof(component.irradianceCoefficients), countof(renderEnv.shIndirectCoefficients));
331     for (size_t idx = 0; idx < shCount; ++idx) {
332         renderEnv.shIndirectCoefficients[idx] = Math::Vec4(component.irradianceCoefficients[idx], 1.0);
333     }
334     renderEnv.indirectDiffuseFactor = component.indirectDiffuseFactor;
335     renderEnv.indirectSpecularFactor = component.indirectSpecularFactor;
336     renderEnv.envMapFactor = component.envMapFactor;
337     renderEnv.rotation = component.environmentRotation;
338 }
339 
GetRenderCameraEnvironmentFromComponent(const ILayerComponentManager * layerMgr,const IRenderHandleComponentManager * gpuHandleMgr,const IEnvironmentComponentManager * envMgr,const IMaterialExtensionComponentManager * matExtMgr,const RenderConfigurationComponent & renderConfigurationComponent,const CameraComponent & cameraComponent)340 RenderCamera::Environment GetRenderCameraEnvironmentFromComponent(const ILayerComponentManager* layerMgr,
341     const IRenderHandleComponentManager* gpuHandleMgr, const IEnvironmentComponentManager* envMgr,
342     const IMaterialExtensionComponentManager* matExtMgr,
343     const RenderConfigurationComponent& renderConfigurationComponent, const CameraComponent& cameraComponent)
344 {
345     RenderCamera::Environment renderEnv;
346     if (!(envMgr && matExtMgr)) {
347         return renderEnv;
348     }
349 
350     auto fillExtensionResources = [](const IRenderHandleComponentManager* renderHandleMgr,
351                                       const MaterialExtensionComponent& component,
352                                       RenderCamera::Environment& renderEnv) {
353         constexpr uint32_t maxCount = Math::min(static_cast<uint32_t>(MaterialExtensionComponent::RESOURCE_COUNT),
354             RenderSceneDataConstants::MAX_ENV_CUSTOM_RESOURCE_COUNT);
355         for (uint32_t idx = 0; idx < maxCount; ++idx) {
356             renderEnv.customResourceHandles[idx] = renderHandleMgr->GetRenderHandleReference(component.resources[idx]);
357         }
358     };
359 
360     const Entity cameraEnvEntity = cameraComponent.environment;
361     // Check if camera has a valid environment
362     Entity envEntity = cameraEnvEntity;
363     auto envId = envMgr->GetComponentId(envEntity);
364     if (envId == IComponentManager::INVALID_COMPONENT_ID) {
365         // Next try if the scene has a valid environment
366         envEntity = renderConfigurationComponent.environment;
367         envId = envMgr->GetComponentId(envEntity);
368     }
369     if (envId != IComponentManager::INVALID_COMPONENT_ID) {
370         if (auto envDataHandle = envMgr->Read(envId); envDataHandle) {
371             const EnvironmentComponent& envComponent = *envDataHandle;
372             uint64_t layerMask = LayerConstants::DEFAULT_LAYER_MASK;
373             if (auto layerHandle = layerMgr->Read(envEntity); layerHandle) {
374                 layerMask = layerHandle->layerMask;
375             }
376 
377             FillRenderEnvironment(gpuHandleMgr, layerMask, cameraEnvEntity, envComponent, renderEnv);
378             if (const auto matExtHandle = matExtMgr->Read(envEntity); matExtHandle) {
379                 const MaterialExtensionComponent& matExtComp = *matExtHandle;
380                 fillExtensionResources(gpuHandleMgr, matExtComp, renderEnv);
381             }
382         }
383     }
384     return renderEnv;
385 }
386 
GetRenderCameraFogFromComponent(const ILayerComponentManager * layerMgr,const IFogComponentManager * fogMgr,const RenderConfigurationComponent & renderConfigurationComponent,const CameraComponent & cameraComponent)387 RenderCamera::Fog GetRenderCameraFogFromComponent(const ILayerComponentManager* layerMgr,
388     const IFogComponentManager* fogMgr, const RenderConfigurationComponent& renderConfigurationComponent,
389     const CameraComponent& cameraComponent)
390 {
391     RenderCamera::Fog renderFog;
392     if (!(layerMgr && fogMgr)) {
393         return renderFog;
394     }
395 
396     auto fillRenderFog = [](const uint64_t& nodeLayerMask, const Entity& entity, const FogComponent& component,
397                              RenderCamera::Fog& renderFog) {
398         renderFog.id = entity.id;
399         renderFog.layerMask = nodeLayerMask;
400 
401         renderFog.firstLayer = { component.density, component.heightFalloff, component.heightFogOffset, 0.0f };
402         renderFog.secondLayer = { component.layerDensity, component.layerHeightFalloff, component.layerHeightFogOffset,
403             0.0f };
404         renderFog.baseFactors = { component.startDistance, component.cuttoffDistance, component.maxOpacity, 0.0f };
405         renderFog.inscatteringColor = component.inscatteringColor;
406         renderFog.envMapFactor = component.envMapFactor;
407         renderFog.additionalFactor = component.additionalFactor;
408     };
409 
410     const Entity cameraFogEntity = cameraComponent.fog;
411     // Check if camera has a valid environment
412     Entity envEntity = cameraFogEntity;
413     auto envId = fogMgr->GetComponentId(envEntity);
414     if (envId == IComponentManager::INVALID_COMPONENT_ID) {
415         // Next try if the scene has a valid environment
416         envEntity = renderConfigurationComponent.environment;
417         envId = fogMgr->GetComponentId(envEntity);
418     }
419     if (envId != IComponentManager::INVALID_COMPONENT_ID) {
420         if (auto fogDataHandle = fogMgr->Read(envId); fogDataHandle) {
421             const FogComponent& fogComponent = *fogDataHandle;
422             uint64_t layerMask = LayerConstants::DEFAULT_LAYER_MASK;
423             if (auto layerHandle = layerMgr->Read(envEntity); layerHandle) {
424                 layerMask = layerHandle->layerMask;
425             }
426 
427             fillRenderFog(layerMask, cameraFogEntity, fogComponent, renderFog);
428         }
429     }
430     return renderFog;
431 }
432 
GetRenderShadowTypes(const RenderConfigurationComponent & renderConfigurationComponent)433 constexpr IRenderDataStoreDefaultLight::ShadowTypes GetRenderShadowTypes(
434     const RenderConfigurationComponent& renderConfigurationComponent)
435 {
436     IRenderDataStoreDefaultLight::ShadowTypes st { IRenderDataStoreDefaultLight::ShadowType::PCF,
437         IRenderDataStoreDefaultLight::ShadowQuality::NORMAL, IRenderDataStoreDefaultLight::ShadowSmoothness::NORMAL };
438     st.shadowType = (renderConfigurationComponent.shadowType == RenderConfigurationComponent::SceneShadowType::VSM)
439                         ? IRenderDataStoreDefaultLight::ShadowType::VSM
440                         : IRenderDataStoreDefaultLight::ShadowType::PCF;
441     if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::LOW) {
442         st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::LOW;
443     } else if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::HIGH) {
444         st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::HIGH;
445     } else if (renderConfigurationComponent.shadowQuality == RenderConfigurationComponent::SceneShadowQuality::ULTRA) {
446         st.shadowQuality = IRenderDataStoreDefaultLight::ShadowQuality::ULTRA;
447     }
448     if (renderConfigurationComponent.shadowSmoothness == RenderConfigurationComponent::SceneShadowSmoothness::HARD) {
449         st.shadowSmoothness = IRenderDataStoreDefaultLight::ShadowSmoothness::HARD;
450     } else if (renderConfigurationComponent.shadowSmoothness ==
451                RenderConfigurationComponent::SceneShadowSmoothness::SOFT) {
452         st.shadowSmoothness = IRenderDataStoreDefaultLight::ShadowSmoothness::SOFT;
453     }
454     return st;
455 }
456 
MaterialHandles(const MaterialComponent & materialDesc,const IRenderHandleComponentManager & gpuManager)457 RenderDataDefaultMaterial::MaterialHandles MaterialHandles(
458     const MaterialComponent& materialDesc, const IRenderHandleComponentManager& gpuManager)
459 {
460     RenderDataDefaultMaterial::MaterialHandles materialHandles;
461     auto imageIt = std::begin(materialHandles.images);
462     auto samplerIt = std::begin(materialHandles.samplers);
463     for (const MaterialComponent::TextureInfo& info : materialDesc.textures) {
464         *imageIt++ = gpuManager.GetRenderHandleReference(info.image);
465         *samplerIt++ = gpuManager.GetRenderHandleReference(info.sampler);
466     }
467     return materialHandles;
468 }
469 
RenderMaterialLightingFlagsFromMaterialFlags(const MaterialComponent::LightingFlags materialFlags)470 constexpr uint32_t RenderMaterialLightingFlagsFromMaterialFlags(const MaterialComponent::LightingFlags materialFlags)
471 {
472     uint32_t rmf = 0;
473     if (materialFlags & MaterialComponent::LightingFlagBits::SHADOW_RECEIVER_BIT) {
474         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_RECEIVER_BIT;
475     }
476     if (materialFlags & MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT) {
477         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_CASTER_BIT;
478     }
479     if (materialFlags & MaterialComponent::LightingFlagBits::PUNCTUAL_LIGHT_RECEIVER_BIT) {
480         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_PUNCTUAL_LIGHT_RECEIVER_BIT;
481     }
482     if (materialFlags & MaterialComponent::LightingFlagBits::INDIRECT_LIGHT_RECEIVER_BIT) {
483         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_INDIRECT_LIGHT_RECEIVER_BIT;
484     }
485     return rmf;
486 }
487 
RenderSubmeshFlagsFromMeshFlags(const MeshComponent::Submesh::Flags flags)488 constexpr uint32_t RenderSubmeshFlagsFromMeshFlags(const MeshComponent::Submesh::Flags flags)
489 {
490     uint32_t rmf = 0;
491     if (flags & MeshComponent::Submesh::FlagBits::TANGENTS_BIT) {
492         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_TANGENTS_BIT;
493     }
494     if (flags & MeshComponent::Submesh::FlagBits::VERTEX_COLORS_BIT) {
495         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_VERTEX_COLORS_BIT;
496     }
497     if (flags & MeshComponent::Submesh::FlagBits::SKIN_BIT) {
498         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT;
499     }
500     if (flags & MeshComponent::Submesh::FlagBits::SECOND_TEXCOORD_BIT) {
501         rmf |= RenderSubmeshFlagBits::RENDER_SUBMESH_SECOND_TEXCOORD_BIT;
502     }
503     return rmf;
504 }
505 
RenderMaterialFlagsFromMaterialValues(const MaterialComponent & matDesc,const RenderDataDefaultMaterial::MaterialHandles & handles,const uint32_t hasTransformBit)506 uint32_t RenderMaterialFlagsFromMaterialValues(const MaterialComponent& matDesc,
507     const RenderDataDefaultMaterial::MaterialHandles& handles, const uint32_t hasTransformBit)
508 {
509     uint32_t rmf = 0;
510     // enable built-in specialization for default materials
511     CORE_ASSERT(matDesc.type <= MaterialComponent::Type::CUSTOM_COMPLEX);
512     if (matDesc.type < MaterialComponent::Type::CUSTOM) {
513         if (handles.images[MaterialComponent::TextureIndex::NORMAL] ||
514             handles.images[MaterialComponent::TextureIndex::CLEARCOAT_NORMAL]) {
515             // need to check for tangents as well with submesh
516             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_NORMAL_MAP_BIT;
517         }
518         if (matDesc.textures[MaterialComponent::TextureIndex::CLEARCOAT].factor.x > 0.0f) {
519             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_CLEAR_COAT_BIT;
520         }
521         if ((matDesc.textures[MaterialComponent::TextureIndex::SHEEN].factor.x > 0.0f) ||
522             (matDesc.textures[MaterialComponent::TextureIndex::SHEEN].factor.y > 0.0f) ||
523             (matDesc.textures[MaterialComponent::TextureIndex::SHEEN].factor.z > 0.0f)) {
524             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SHEEN_BIT;
525         }
526         if (matDesc.textures[MaterialComponent::TextureIndex::SPECULAR].factor != Math::Vec4(1.f, 1.f, 1.f, 1.f) ||
527             handles.images[MaterialComponent::TextureIndex::SPECULAR]) {
528             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SPECULAR_BIT;
529         }
530         if (matDesc.textures[MaterialComponent::TextureIndex::TRANSMISSION].factor.x > 0.0f) {
531             rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_TRANSMISSION_BIT;
532         }
533     }
534     if (hasTransformBit) {
535         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_TEXTURE_TRANSFORM_BIT;
536     }
537     if (matDesc.alphaCutoff < 1.0f) {
538         rmf |= RenderMaterialFlagBits::RENDER_MATERIAL_SHADER_DISCARD_BIT;
539     }
540     // NOTE: earlier version had MASK here for opaque bit as well
541     return rmf;
542 }
543 
544 #if (CORE3D_VALIDATION_ENABLED == 1)
ValidateInputColor(const Entity material,const MaterialComponent & matComp)545 void ValidateInputColor(const Entity material, const MaterialComponent& matComp)
546 {
547     if (matComp.type < MaterialComponent::Type::CUSTOM) {
548         const auto& base = matComp.textures[MaterialComponent::TextureIndex::BASE_COLOR];
549         if ((base.factor.x > 1.0f) || (base.factor.y > 1.0f) || (base.factor.z > 1.0f) || (base.factor.w > 1.0f)) {
550             CORE_LOG_ONCE_W(to_string(material.id) + "_base_fac",
551                 "CORE3D_VALIDATION: Non custom material type expects base color factor to be <= 1.0f.");
552         }
553         const auto& mat = matComp.textures[MaterialComponent::TextureIndex::MATERIAL];
554         if ((mat.factor.y > 1.0f) || (mat.factor.z > 1.0f)) {
555             CORE_LOG_ONCE_W(to_string(material.id) + "_mat_fac",
556                 "CORE3D_VALIDATION: Non custom material type expects roughness and metallic to be <= 1.0f.");
557         }
558     }
559 }
560 #endif
561 
InputMaterialUniformsFromMaterialComponent(const Entity material,const MaterialComponent & matDesc)562 RenderDataDefaultMaterial::InputMaterialUniforms InputMaterialUniformsFromMaterialComponent(
563     const Entity material, const MaterialComponent& matDesc)
564 {
565     RenderDataDefaultMaterial::InputMaterialUniforms mu;
566     uint transformBits = 0u;
567     {
568         constexpr uint32_t index = 0u;
569         const auto& tex = matDesc.textures[MaterialComponent::TextureIndex::BASE_COLOR];
570         // NOTE: premultiplied alpha, applied here and therefore the baseColor factor is special
571         const float alpha = tex.factor.w;
572         const Math::Vec4 baseColor = {
573             tex.factor.x * alpha,
574             tex.factor.y * alpha,
575             tex.factor.z * alpha,
576             alpha,
577         };
578 #if (CORE3D_VALIDATION_ENABLED == 1)
579         ValidateInputColor(material, matDesc);
580 #endif
581 
582         auto& texRef = mu.textureData[index];
583         texRef.factor = baseColor;
584         texRef.translation = tex.transform.translation;
585         texRef.rotation = tex.transform.rotation;
586         texRef.scale = tex.transform.scale;
587         const bool hasTransform = (((texRef.translation.x != 0.0f) || (texRef.translation.y != 0.0f)) ||
588                                    (texRef.rotation != 0.0f) || ((texRef.scale.x != 1.0f) || (texRef.scale.y != 1.0f)));
589         transformBits |= static_cast<uint32_t>(hasTransform) << index;
590     }
591     constexpr uint32_t texCount = Math::min(static_cast<uint32_t>(MaterialComponent::TextureIndex::TEXTURE_COUNT),
592         RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT);
593     for (uint32_t idx = 1u; idx < texCount; ++idx) {
594         const auto& tex = matDesc.textures[idx];
595         auto& texRef = mu.textureData[idx];
596         texRef.factor = tex.factor;
597         texRef.translation = tex.transform.translation;
598         texRef.rotation = tex.transform.rotation;
599         texRef.scale = tex.transform.scale;
600         const bool hasTransform = (((texRef.translation.x != 0.0f) || (texRef.translation.y != 0.0f)) ||
601                                    (texRef.rotation != 0.0f) || ((texRef.scale.x != 1.0f) || (texRef.scale.y != 1.0f)));
602         transformBits |= static_cast<uint32_t>(hasTransform) << idx;
603     }
604     mu.alphaCutoff = matDesc.alphaCutoff;
605     mu.id = material.id;
606     mu.texCoordSetBits = matDesc.useTexcoordSetBit;
607     mu.texTransformSetBits = transformBits;
608     return mu;
609 }
610 
611 BEGIN_PROPERTY(IRenderSystem::Properties, ComponentMetadata)
612     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreManager, "IRenderDataStoreManager", PropertyFlags::IS_HIDDEN)
613     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreMaterial, "dataStoreMaterial", 0)
614     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreCamera, "dataStoreCamera", 0)
615     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreLight, "dataStoreLight", 0)
616     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreScene, "dataStoreScene", 0)
617     DECL_PROPERTY2(IRenderSystem::Properties, dataStoreMorph, "dataStoreMorph", 0)
618 END_PROPERTY();
619 
SetupSubmeshBuffers(const IRenderHandleComponentManager & renderHandleManager,const MeshComponent & desc,const MeshComponent::Submesh & submesh,RenderSubmesh & renderSubmesh)620 void SetupSubmeshBuffers(const IRenderHandleComponentManager& renderHandleManager, const MeshComponent& desc,
621     const MeshComponent::Submesh& submesh, RenderSubmesh& renderSubmesh)
622 {
623     CORE_STATIC_ASSERT(
624         MeshComponent::Submesh::BUFFER_COUNT <= RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT);
625     // calculate real vertex buffer count and fill "safety" handles for default material
626     // no default shader variants without joints etc.
627     std::transform(std::begin(submesh.bufferAccess), std::end(submesh.bufferAccess),
628         std::begin(renderSubmesh.vertexBuffers),
629         [&renderSubmesh, &renderHandleManager](const MeshComponent::Submesh::BufferAccess& acc) {
630             RenderVertexBuffer renderVb;
631             if (EntityUtil::IsValid(acc.buffer)) {
632                 renderVb.bufferHandle = renderHandleManager.GetRenderHandleReference(acc.buffer);
633             }
634             if (renderVb.bufferHandle) {
635                 renderVb.bufferOffset = acc.offset;
636                 renderVb.byteSize = acc.byteSize;
637             } else {
638                 renderVb.bufferHandle = renderSubmesh.vertexBuffers[0].bufferHandle; // expecting safety binding
639                 renderVb.bufferOffset = 0;
640                 renderVb.byteSize = 0;
641             }
642             // NOTE: we will get max amount of vertex buffers if there is at least one
643             // should calculate the real needed vertx input declaration specific count
644             if (renderVb.bufferHandle) {
645                 renderSubmesh.vertexBufferCount++;
646             }
647             return renderVb;
648         });
649 
650     if (submesh.indexBuffer.buffer) {
651         renderSubmesh.indexBuffer.bufferHandle =
652             renderHandleManager.GetRenderHandleReference(submesh.indexBuffer.buffer);
653         renderSubmesh.indexBuffer.bufferOffset = submesh.indexBuffer.offset;
654         renderSubmesh.indexBuffer.byteSize = submesh.indexBuffer.byteSize;
655         renderSubmesh.indexBuffer.indexType = submesh.indexBuffer.indexType;
656     }
657     if (submesh.indirectArgsBuffer.buffer) {
658         renderSubmesh.indirectArgsBuffer.bufferHandle =
659             renderHandleManager.GetRenderHandleReference(submesh.indirectArgsBuffer.buffer);
660         renderSubmesh.indirectArgsBuffer.bufferOffset = submesh.indirectArgsBuffer.offset;
661         renderSubmesh.indirectArgsBuffer.byteSize = submesh.indirectArgsBuffer.byteSize;
662     }
663 
664     // Set submesh flags.
665     renderSubmesh.submeshFlags = RenderSubmeshFlagsFromMeshFlags(submesh.flags);
666 }
667 
AddSingleMaterial(IMaterialComponentManager & materialMgr,IRenderHandleComponentManager & renderHandleMgr,IRenderDataStoreDefaultMaterial & dataStoreMaterial,const Entity & material,const bool useEntityId,const bool fetchMaterialHandles)668 uint32_t AddSingleMaterial(IMaterialComponentManager& materialMgr, IRenderHandleComponentManager& renderHandleMgr,
669     IRenderDataStoreDefaultMaterial& dataStoreMaterial, const Entity& material, const bool useEntityId,
670     const bool fetchMaterialHandles)
671 {
672     uint32_t materialIdx = RenderSceneDataConstants::INVALID_INDEX;
673     {
674         // scoped
675         auto matData = materialMgr.Read(material);
676         const MaterialComponent& materialComp = (matData) ? *matData : DEF_MATERIAL_COMPONENT;
677         // optimization for e.g. with batch GPU instancing (we do not care about material handles)
678         const RenderDataDefaultMaterial::MaterialHandles materialHandles =
679             fetchMaterialHandles ? MaterialHandles(materialComp, renderHandleMgr)
680                                  : RenderDataDefaultMaterial::MaterialHandles {};
681         const RenderDataDefaultMaterial::InputMaterialUniforms materialUniforms =
682             InputMaterialUniformsFromMaterialComponent(material, materialComp);
683         const uint32_t transformBits = materialUniforms.texTransformSetBits;
684 
685         const RenderMaterialFlags rmfFromBits =
686             RenderMaterialLightingFlagsFromMaterialFlags(materialComp.materialLightingFlags);
687         const RenderMaterialFlags rmfFromValues =
688             RenderMaterialFlagsFromMaterialValues(materialComp, materialHandles, transformBits);
689         const RenderMaterialFlags rmf = rmfFromBits | rmfFromValues;
690         RenderDataDefaultMaterial::MaterialData data {
691             RenderMaterialType(materialComp.type),
692             materialComp.extraRenderingFlags,
693             rmf,
694             materialComp.customRenderSlotId,
695             { renderHandleMgr.GetRenderHandleReference(materialComp.materialShader.shader),
696                 renderHandleMgr.GetRenderHandleReference(materialComp.materialShader.graphicsState) },
697             { renderHandleMgr.GetRenderHandleReference(materialComp.depthShader.shader),
698                 renderHandleMgr.GetRenderHandleReference(materialComp.depthShader.graphicsState) },
699         };
700         array_view<const uint8_t> customData;
701         if (materialComp.customProperties) {
702             const auto buffer = static_cast<const uint8_t*>(materialComp.customProperties->RLock());
703             constexpr auto setAndBinding = sizeof(uint32_t) * 2u;
704             customData = array_view(buffer + setAndBinding, materialComp.customProperties->Size() - setAndBinding);
705             materialComp.customProperties->RUnlock();
706         }
707         if (useEntityId) {
708             materialIdx =
709                 dataStoreMaterial.AddMaterialData(material.id, materialUniforms, materialHandles, data, customData);
710         } else {
711             materialIdx = dataStoreMaterial.AddMaterialData(materialUniforms, materialHandles, data, customData);
712         }
713     }
714     return materialIdx;
715 }
716 
717 struct RenderMaterialIndices {
718     uint32_t materialIndex { ~0u };
719     uint32_t materialCustomResourceIndex { ~0u };
720 };
AddRenderMaterial(IMaterialComponentManager & materialMgr,IMaterialExtensionComponentManager & materialExtMgr,IRenderHandleComponentManager & renderHandleMgr,IRenderDataStoreDefaultMaterial & dataStoreMaterial,const Entity & material)721 RenderMaterialIndices AddRenderMaterial(IMaterialComponentManager& materialMgr,
722     IMaterialExtensionComponentManager& materialExtMgr, IRenderHandleComponentManager& renderHandleMgr,
723     IRenderDataStoreDefaultMaterial& dataStoreMaterial, const Entity& material)
724 {
725     RenderMaterialIndices indices;
726     indices.materialIndex = dataStoreMaterial.GetMaterialIndex(material.id);
727     if ((indices.materialIndex == RenderSceneDataConstants::INVALID_INDEX) && EntityUtil::IsValid(material)) {
728         indices.materialIndex =
729             AddSingleMaterial(materialMgr, renderHandleMgr, dataStoreMaterial, material, true, true);
730         if (const auto matExtHandle = materialExtMgr.Read(material); matExtHandle) {
731             const MaterialExtensionComponent& matExtComp = *matExtHandle;
732             RenderHandleReference handleReferences[MaterialExtensionComponent::ResourceIndex::RESOURCE_COUNT];
733             std::transform(std::begin(matExtComp.resources), std::end(matExtComp.resources),
734                 std::begin(handleReferences), [&renderHandleMgr](const EntityReference& matEntity) {
735                     return renderHandleMgr.GetRenderHandleReference(matEntity);
736                 });
737             // bind all handles, invalid handles are just ignored
738             indices.materialCustomResourceIndex =
739                 dataStoreMaterial.AddMaterialCustomResources(material.id, handleReferences);
740         }
741     } else if ((indices.materialIndex != RenderSceneDataConstants::INVALID_INDEX) && EntityUtil::IsValid(material)) {
742         indices.materialCustomResourceIndex = dataStoreMaterial.GetMaterialCustomResourceIndex(material.id);
743     }
744 
745     // we add the default material component with default entity id (only added once)
746     if (indices.materialIndex == RenderSceneDataConstants::INVALID_INDEX) {
747         const Entity invalidEntity {};
748         indices.materialIndex =
749             AddSingleMaterial(materialMgr, renderHandleMgr, dataStoreMaterial, invalidEntity, true, true);
750     }
751     return indices;
752 }
753 
754 // Extended sign: returns -1, 0 or 1 based on sign of a
Sgn(float a)755 float Sgn(float a)
756 {
757     if (a > 0.0f) {
758         return 1.0f;
759     }
760 
761     if (a < 0.0f) {
762         return -1.0f;
763     }
764 
765     return 0.0f;
766 }
767 
768 struct ReflectionPlaneTargetUpdate {
769     bool recreated { false };
770     uint32_t mipCount { 1u };
771 };
772 
UpdateReflectionPlaneMaterial(IRenderMeshComponentManager & renderMeshMgr,IMeshComponentManager & meshMgr,IMaterialComponentManager & materialMgr,const Entity & entity,const PlanarReflectionComponent & reflComponent,const ReflectionPlaneTargetUpdate & rptu)773 void UpdateReflectionPlaneMaterial(IRenderMeshComponentManager& renderMeshMgr, IMeshComponentManager& meshMgr,
774     IMaterialComponentManager& materialMgr, const Entity& entity, const PlanarReflectionComponent& reflComponent,
775     const ReflectionPlaneTargetUpdate& rptu)
776 {
777     // update material
778     if (const auto rmcHandle = renderMeshMgr.Read(entity); rmcHandle) {
779         const RenderMeshComponent& rmc = *rmcHandle;
780         if (const auto meshHandle = meshMgr.Read(rmc.mesh); meshHandle) {
781             const MeshComponent& meshComponent = *meshHandle;
782             if (!meshComponent.submeshes.empty()) {
783                 if (auto matHandle = materialMgr.Write(meshComponent.submeshes[0].material); matHandle) {
784                     MaterialComponent& matComponent = *matHandle;
785                     // NOTE: CLEARCOAT_ROUGHNESS cannot be used due to material flags bit is enabled for lighting
786                     matComponent.textures[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].factor = {
787                         static_cast<float>(rptu.mipCount),
788                         reflComponent.screenPercentage,
789                         static_cast<float>(reflComponent.renderTargetResolution[0u]),
790                         static_cast<float>(reflComponent.renderTargetResolution[1u]),
791                     };
792                 }
793             }
794         }
795     }
796 }
797 
UpdatePlaneReflectionTargetResolution(IGpuResourceManager & gpuResourceMgr,IRenderHandleComponentManager & gpuHandleMgr,IPlanarReflectionComponentManager & planarReflMgr,const RenderCamera & sceneCamera,const Entity & entity,PlanarReflectionComponent & reflComp)798 ReflectionPlaneTargetUpdate UpdatePlaneReflectionTargetResolution(IGpuResourceManager& gpuResourceMgr,
799     IRenderHandleComponentManager& gpuHandleMgr, IPlanarReflectionComponentManager& planarReflMgr,
800     const RenderCamera& sceneCamera, const Entity& entity, PlanarReflectionComponent& reflComp)
801 {
802     // NOTE: if the resource is not yet created one should attach it to material as well
803     // these resources should be un-named
804     const uint32_t newWidth = static_cast<uint32_t>(sceneCamera.renderResolution.x * reflComp.screenPercentage);
805     const uint32_t newHeight = static_cast<uint32_t>(sceneCamera.renderResolution.y * reflComp.screenPercentage);
806 
807     ReflectionPlaneTargetUpdate rptu;
808 
809     const RenderHandle colorRenderTarget = gpuHandleMgr.GetRenderHandle(reflComp.colorRenderTarget);
810     const RenderHandle depthRenderTarget = gpuHandleMgr.GetRenderHandle(reflComp.depthRenderTarget);
811     // get current mip count
812     rptu.mipCount = RenderHandleUtil::IsValid(colorRenderTarget)
813                         ? gpuResourceMgr.GetImageDescriptor(gpuResourceMgr.Get(colorRenderTarget)).mipCount
814                         : 1u;
815     if ((!RenderHandleUtil::IsValid(colorRenderTarget)) || (!RenderHandleUtil::IsValid(depthRenderTarget)) ||
816         (newWidth != reflComp.renderTargetResolution[0]) || (newHeight != reflComp.renderTargetResolution[1])) {
817         auto reCreateGpuImage = [](IGpuResourceManager& gpuResourceMgr, uint64_t id, RenderHandle handle,
818                                     uint32_t newWidth, uint32_t newHeight, uint baseMipCount, bool depthImage) {
819             GpuImageDesc desc = RenderHandleUtil::IsValid(handle)
820                                     ? gpuResourceMgr.GetImageDescriptor(gpuResourceMgr.Get(handle))
821                                     : CreateReflectionPlaneGpuImageDesc(depthImage);
822             desc.mipCount = baseMipCount;
823             desc.width = newWidth;
824             desc.height = newHeight;
825             if (RenderHandleUtil::IsValid(handle)) {
826                 return gpuResourceMgr.Create(gpuResourceMgr.Get(handle), desc);
827             } else if (depthImage) {
828                 return gpuResourceMgr.Create(
829                     DefaultMaterialCameraConstants::CAMERA_DEPTH_PREFIX_NAME + to_string(id), desc);
830             } else {
831                 return gpuResourceMgr.Create(
832                     DefaultMaterialCameraConstants::CAMERA_COLOR_PREFIX_NAME + to_string(id), desc);
833             }
834         };
835         if (!EntityUtil::IsValid(reflComp.colorRenderTarget)) {
836             reflComp.colorRenderTarget = gpuHandleMgr.GetEcs().GetEntityManager().CreateReferenceCounted();
837             gpuHandleMgr.Create(reflComp.colorRenderTarget);
838         }
839         rptu.mipCount = Math::min(Math::max(DefaultMaterialCameraConstants::REFLECTION_PLANE_MIP_COUNT, rptu.mipCount),
840             static_cast<uint32_t>(std::log2f(static_cast<float>(std::max(newWidth, newHeight)))) + 1u);
841         gpuHandleMgr.Write(reflComp.colorRenderTarget)->reference =
842             reCreateGpuImage(gpuResourceMgr, entity.id, colorRenderTarget, newWidth, newHeight, rptu.mipCount, false);
843 
844         if (!EntityUtil::IsValid(reflComp.depthRenderTarget)) {
845             reflComp.depthRenderTarget = gpuHandleMgr.GetEcs().GetEntityManager().CreateReferenceCounted();
846             gpuHandleMgr.Create(reflComp.depthRenderTarget);
847         }
848         gpuHandleMgr.Write(reflComp.depthRenderTarget)->reference =
849             reCreateGpuImage(gpuResourceMgr, entity.id, depthRenderTarget, newWidth, newHeight, 1u, true);
850 
851         reflComp.renderTargetResolution[0] = newWidth;
852         reflComp.renderTargetResolution[1] = newHeight;
853         rptu.recreated = true;
854         planarReflMgr.Set(entity, reflComp);
855     }
856 
857     return rptu;
858 }
859 
860 // 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)861 inline Math::Vec4 CalculateCameraSpaceClipPlane(
862     const Math::Mat4X4& view, Math::Vec3 pos, Math::Vec3 normal, float sideSign, float clipPlaneOffset)
863 {
864     const Math::Vec3 offsetPos = pos + normal * clipPlaneOffset;
865     const Math::Vec3 cpos = Math::MultiplyPoint3X4(view, offsetPos);
866     const Math::Vec3 cnormal = Math::Normalize(Math::MultiplyVector(view, normal)) * sideSign;
867     return Math::Vec4(cnormal.x, cnormal.y, cnormal.z, -Math::Dot(cpos, cnormal));
868 }
869 
870 // See http://aras-p.info/texts/obliqueortho.html
CalculateObliqueProjectionMatrix(Math::Mat4X4 & projection,const Math::Vec4 & plane)871 inline void CalculateObliqueProjectionMatrix(Math::Mat4X4& projection, const Math::Vec4& plane)
872 {
873     const Math::Mat4X4 inverseProjection = Inverse(projection);
874 
875     const Math::Vec4 q = inverseProjection * Math::Vec4(Sgn(plane.x), Sgn(plane.y), 1.0f, 1.0f);
876     const Math::Vec4 c = plane * (2.0f / Math::Dot(plane, q));
877 
878     projection.data[2u] = c.x;
879     projection.data[6u] = c.y;
880     projection.data[10u] = c.z;
881     projection.data[14u] = c.w;
882 }
883 
884 // Calculate reflection matrix from given matrix.
CalculateReflectionMatrix(const Math::Vec4 & plane)885 Math::Mat4X4 CalculateReflectionMatrix(const Math::Vec4& plane)
886 {
887     Math::Mat4X4 result(1.0f);
888 
889     result.data[0u] = (1.0f - 2.0f * plane[0u] * plane[0u]);
890     result.data[4u] = (-2.0f * plane[0u] * plane[1u]);
891     result.data[8u] = (-2.0f * plane[0u] * plane[2u]);
892     result.data[12u] = (-2.0f * plane[3u] * plane[0u]);
893 
894     result.data[1u] = (-2.0f * plane[1u] * plane[0u]);
895     result.data[5u] = (1.0f - 2.0f * plane[1u] * plane[1u]);
896     result.data[9u] = (-2.0f * plane[1u] * plane[2u]);
897     result.data[13u] = (-2.0f * plane[3u] * plane[1u]);
898 
899     result.data[2u] = (-2.0f * plane[2u] * plane[0u]);
900     result.data[6u] = (-2.0f * plane[2u] * plane[1u]);
901     result.data[10u] = (1.0f - 2.0f * plane[2u] * plane[2u]);
902     result.data[14u] = (-2.0f * plane[3u] * plane[2u]);
903 
904     result.data[3u] = 0.0f;
905     result.data[7u] = 0.0f;
906     result.data[11u] = 0.0f;
907     result.data[15u] = 1.0f;
908 
909     return result;
910 }
911 
CalculateProjectionMatrix(CameraComponent const & cameraComponent,bool & isCameraNegative)912 Math::Mat4X4 CalculateProjectionMatrix(CameraComponent const& cameraComponent, bool& isCameraNegative)
913 {
914     switch (cameraComponent.projection) {
915         case CameraComponent::Projection::ORTHOGRAPHIC: {
916             auto orthoProj = Math::OrthoRhZo(cameraComponent.xMag * -0.5f, cameraComponent.xMag * 0.5f,
917                 cameraComponent.yMag * -0.5f, cameraComponent.yMag * 0.5f, cameraComponent.zNear, cameraComponent.zFar);
918             orthoProj[1][1] *= -1.f; // left-hand NDC while Vulkan right-handed -> flip y
919             return orthoProj;
920         }
921 
922         case CameraComponent::Projection::PERSPECTIVE: {
923             auto persProj = Math::PerspectiveRhZo(
924                 cameraComponent.yFov, cameraComponent.aspect, cameraComponent.zNear, cameraComponent.zFar);
925             persProj[1][1] *= -1.f; // left-hand NDC while Vulkan right-handed -> flip y
926             return persProj;
927         }
928 
929         case CameraComponent::Projection::CUSTOM: {
930             isCameraNegative = Math::Determinant(cameraComponent.customProjectionMatrix) < 0.0f;
931             return cameraComponent.customProjectionMatrix;
932         }
933 
934         default:
935             return Math::Mat4X4();
936     }
937 }
938 } // namespace
939 
RenderSystem(IEcs & ecs)940 RenderSystem::RenderSystem(IEcs& ecs)
941     : ecs_(ecs), nodeMgr_(GetManager<INodeComponentManager>(ecs)),
942       renderMeshBatchMgr_(GetManager<IRenderMeshBatchComponentManager>(ecs)),
943       renderMeshMgr_(GetManager<IRenderMeshComponentManager>(ecs)),
944       worldMatrixMgr_(GetManager<IWorldMatrixComponentManager>(ecs)),
945       prevWorldMatrixMgr_(GetManager<IPreviousWorldMatrixComponentManager>(ecs)),
946       renderConfigMgr_(GetManager<IRenderConfigurationComponentManager>(ecs)),
947       cameraMgr_(GetManager<ICameraComponentManager>(ecs)), lightMgr_(GetManager<ILightComponentManager>(ecs)),
948       planarReflectionMgr_(GetManager<IPlanarReflectionComponentManager>(ecs)),
949       materialExtensionMgr_(GetManager<IMaterialExtensionComponentManager>(ecs)),
950       materialMgr_(GetManager<IMaterialComponentManager>(ecs)), meshMgr_(GetManager<IMeshComponentManager>(ecs)),
951       uriMgr_(GetManager<IUriComponentManager>(ecs)), nameMgr_(GetManager<INameComponentManager>(ecs)),
952       environmentMgr_(GetManager<IEnvironmentComponentManager>(ecs)), fogMgr_(GetManager<IFogComponentManager>(ecs)),
953       gpuHandleMgr_(GetManager<IRenderHandleComponentManager>(ecs)), layerMgr_(GetManager<ILayerComponentManager>(ecs)),
954       jointMatricesMgr_(GetManager<IJointMatricesComponentManager>(ecs)),
955       prevJointMatricesMgr_(GetManager<IPreviousJointMatricesComponentManager>(ecs)),
956       postProcessMgr_(GetManager<IPostProcessComponentManager>(ecs)),
957       RENDER_SYSTEM_PROPERTIES(&properties_, array_view(ComponentMetadata))
958 {
959     if (IEngine* engine = ecs_.GetClassFactory().GetInterface<IEngine>(); engine) {
960         renderContext_ = GetInstance<IRenderContext>(*engine->GetInterface<IClassRegister>(), UID_RENDER_CONTEXT);
961         if (renderContext_) {
962             picking_ = GetInstance<IPicking>(*renderContext_->GetInterface<IClassRegister>(), UID_PICKING);
963             graphicsContext_ =
964                 GetInstance<IGraphicsContext>(*renderContext_->GetInterface<IClassRegister>(), UID_GRAPHICS_CONTEXT);
965             if (graphicsContext_) {
966                 renderUtil_ = &graphicsContext_->GetRenderUtil();
967             }
968             shaderMgr_ = &renderContext_->GetDevice().GetShaderManager();
969             gpuResourceMgr_ = &renderContext_->GetDevice().GetGpuResourceManager();
970         }
971     }
972 }
973 
~RenderSystem()974 RenderSystem::~RenderSystem()
975 {
976     DestroyRenderDataStores();
977 }
978 
SetActive(bool state)979 void RenderSystem::SetActive(bool state)
980 {
981     active_ = state;
982 }
983 
IsActive() const984 bool RenderSystem::IsActive() const
985 {
986     return active_;
987 }
988 
GetName() const989 string_view RenderSystem::GetName() const
990 {
991     return CORE3D_NS::GetName(this);
992 }
993 
GetUid() const994 Uid RenderSystem::GetUid() const
995 {
996     return UID;
997 }
998 
GetProperties()999 IPropertyHandle* RenderSystem::GetProperties()
1000 {
1001     return RENDER_SYSTEM_PROPERTIES.GetData();
1002 }
1003 
GetProperties() const1004 const IPropertyHandle* RenderSystem::GetProperties() const
1005 {
1006     return RENDER_SYSTEM_PROPERTIES.GetData();
1007 }
1008 
SetProperties(const IPropertyHandle & data)1009 void RenderSystem::SetProperties(const IPropertyHandle& data)
1010 {
1011     if (data.Owner() != &RENDER_SYSTEM_PROPERTIES) {
1012         return;
1013     }
1014     if (const auto in = ScopedHandle<const IRenderSystem::Properties>(&data); in) {
1015         properties_.dataStoreScene = in->dataStoreScene;
1016         properties_.dataStoreCamera = in->dataStoreCamera;
1017         properties_.dataStoreLight = in->dataStoreLight;
1018         properties_.dataStoreMaterial = in->dataStoreMaterial;
1019         properties_.dataStoreMorph = in->dataStoreMorph;
1020         if (properties_.dataStoreManager) {
1021             SetDataStorePointers(*properties_.dataStoreManager);
1022         }
1023     }
1024 }
1025 
SetDataStorePointers(IRenderDataStoreManager & manager)1026 void RenderSystem::SetDataStorePointers(IRenderDataStoreManager& manager)
1027 {
1028     properties_.dataStoreManager = &manager;
1029 
1030     // get data stores
1031     dsScene_ =
1032         static_cast<IRenderDataStoreDefaultScene*>(manager.GetRenderDataStore(properties_.dataStoreScene.data()));
1033     dsCamera_ =
1034         static_cast<IRenderDataStoreDefaultCamera*>(manager.GetRenderDataStore(properties_.dataStoreCamera.data()));
1035     dsLight_ =
1036         static_cast<IRenderDataStoreDefaultLight*>(manager.GetRenderDataStore(properties_.dataStoreLight.data()));
1037     dsMaterial_ =
1038         static_cast<IRenderDataStoreDefaultMaterial*>(manager.GetRenderDataStore(properties_.dataStoreMaterial.data()));
1039 }
1040 
GetECS() const1041 const IEcs& RenderSystem::GetECS() const
1042 {
1043     return ecs_;
1044 }
1045 
Initialize()1046 void RenderSystem::Initialize()
1047 {
1048     if (graphicsContext_ && renderContext_) {
1049         renderPreprocessorSystem_ = GetSystem<IRenderPreprocessorSystem>(ecs_);
1050         if (renderPreprocessorSystem_) {
1051             const auto in =
1052                 ScopedHandle<IRenderPreprocessorSystem::Properties>(renderPreprocessorSystem_->GetProperties());
1053             properties_.dataStoreScene = in->dataStoreScene;
1054             properties_.dataStoreCamera = in->dataStoreCamera;
1055             properties_.dataStoreLight = in->dataStoreLight;
1056             properties_.dataStoreMaterial = in->dataStoreMaterial;
1057             properties_.dataStoreMorph = in->dataStoreMorph;
1058         } else {
1059             CORE_LOG_E("DEPRECATED USAGE: RenderPreprocessorSystem not found. Add system to system graph.");
1060         }
1061 
1062         SetDataStorePointers(renderContext_->GetRenderDataStoreManager());
1063     }
1064 
1065     {
1066         const ComponentQuery::Operation operations[] = {
1067             { *nodeMgr_, ComponentQuery::Operation::REQUIRE },
1068             { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1069             { *layerMgr_, ComponentQuery::Operation::OPTIONAL },
1070         };
1071         lightQuery_.SetEcsListenersEnabled(true);
1072         lightQuery_.SetupQuery(*lightMgr_, operations);
1073     }
1074     {
1075         const ComponentQuery::Operation operations[] = {
1076             { *nodeMgr_, ComponentQuery::Operation::REQUIRE },
1077             { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1078             { *prevWorldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1079             { *layerMgr_, ComponentQuery::Operation::OPTIONAL },
1080             { *jointMatricesMgr_, ComponentQuery::Operation::OPTIONAL },
1081             { *prevJointMatricesMgr_, ComponentQuery::Operation::OPTIONAL },
1082         };
1083         renderableQuery_.SetEcsListenersEnabled(true);
1084         renderableQuery_.SetupQuery(*renderMeshMgr_, operations);
1085     }
1086     {
1087         const ComponentQuery::Operation operations[] = {
1088             { *worldMatrixMgr_, ComponentQuery::Operation::REQUIRE },
1089             { *nodeMgr_, ComponentQuery::Operation::REQUIRE },
1090         };
1091         reflectionsQuery_.SetEcsListenersEnabled(true);
1092         reflectionsQuery_.SetupQuery(*planarReflectionMgr_, operations);
1093     }
1094 }
1095 
Update(bool frameRenderingQueued,uint64_t totalTime,uint64_t deltaTime)1096 bool RenderSystem::Update(bool frameRenderingQueued, uint64_t totalTime, uint64_t deltaTime)
1097 {
1098     if (!frameRenderingQueued) {
1099         return false;
1100     }
1101     totalTime_ = totalTime;
1102     deltaTime_ = deltaTime;
1103 
1104     if (dsMaterial_ && dsCamera_ && dsLight_ && dsScene_) {
1105         dsMaterial_->Clear();
1106         dsCamera_->Clear();
1107         dsLight_->Clear();
1108         dsScene_->Clear();
1109         FetchFullScene();
1110     } else {
1111 #if (CORE3D_VALIDATION_ENABLED == 1)
1112         CORE_LOG_ONCE_W("rs_data_stores_not_found", "CORE3D_VALIDATION: render system render data stores not found");
1113 #endif
1114     }
1115     frameIndex_++;
1116 
1117     return true;
1118 }
1119 
Uninitialize()1120 void RenderSystem::Uninitialize()
1121 {
1122     lightQuery_.SetEcsListenersEnabled(false);
1123     renderableQuery_.SetEcsListenersEnabled(false);
1124     reflectionsQuery_.SetEcsListenersEnabled(false);
1125 }
1126 
GetRenderConfigurationComponent()1127 RenderConfigurationComponent RenderSystem::GetRenderConfigurationComponent()
1128 {
1129     for (IComponentManager::ComponentId i = 0; i < renderConfigMgr_->GetComponentCount(); i++) {
1130         const Entity id = renderConfigMgr_->GetEntity(i);
1131         if (nodeMgr_->Get(id).effectivelyEnabled) {
1132             return renderConfigMgr_->Get(i);
1133         }
1134     }
1135     return {};
1136 }
1137 
ProcessScene(const RenderConfigurationComponent & sc)1138 Entity RenderSystem::ProcessScene(const RenderConfigurationComponent& sc)
1139 {
1140     Entity cameraEntity { INVALID_ENTITY };
1141     // Grab active camera.
1142     const auto cameraCount = cameraMgr_->GetComponentCount();
1143     for (IComponentManager::ComponentId id = 0; id < cameraCount; ++id) {
1144         if (auto handle = cameraMgr_->Read(id); handle) {
1145             if (handle->sceneFlags & CameraComponent::SceneFlagBits::MAIN_CAMERA_BIT) {
1146                 cameraEntity = cameraMgr_->GetEntity(id);
1147                 break;
1148             }
1149         }
1150     }
1151     dsLight_->SetShadowTypes(GetRenderShadowTypes(sc), 0u);
1152 
1153     // NOTE: removed code for "No main camera set, grab 1st one (if any)."
1154 
1155     return cameraEntity;
1156 }
1157 
EvaluateMaterialModifications(const MaterialComponent & matComp)1158 void RenderSystem::EvaluateMaterialModifications(const MaterialComponent& matComp)
1159 {
1160     // update built-in pipeline modifications for default materials
1161     CORE_ASSERT(matComp.type <= MaterialComponent::Type::CUSTOM_COMPLEX);
1162     if (matComp.type < MaterialComponent::Type::CUSTOM) {
1163         if (matComp.textures[MaterialComponent::TextureIndex::TRANSMISSION].factor.x > 0.0f) {
1164             // NOTE: should be alpha blend and not double sided, should be set by material author
1165             // automatically done by e.g. gltf2 importer
1166             renderProcessing_.frameFlags |= NEEDS_COLOR_PRE_PASS; // when allowing prepass on demand
1167         }
1168     }
1169 }
1170 
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)1171 void RenderSystem::ProcessSubmesh(const MeshProcessData& mpd, const MeshComponent::Submesh& submesh,
1172     const uint32_t meshIndex, const uint32_t subMeshIndex, const uint32_t skinJointIndex, const MinAndMax& mam,
1173     const bool isNegative)
1174 {
1175     // The cost of constructing RenderSubmesh is suprisingly high. alternatives are copy-construction from a constant
1176     // or perhaps directly assinging the final values.
1177     RenderSubmesh renderSubmesh { INIT };
1178     renderSubmesh.id = mpd.renderMeshEntity.id;
1179     renderSubmesh.meshId = mpd.meshEntity.id;
1180     renderSubmesh.subMeshIndex = subMeshIndex;
1181     renderSubmesh.layerMask = mpd.layerMask; // pass node layer mask for render submesh
1182     renderSubmesh.renderSortLayer = submesh.renderSortLayer;
1183     renderSubmesh.renderSortLayerOrder = submesh.renderSortLayerOrder;
1184     renderSubmesh.meshIndex = meshIndex;
1185     renderSubmesh.skinJointIndex = skinJointIndex;
1186     renderSubmesh.worldCenter = (mam.minAABB + mam.maxAABB) * 0.5f;
1187     renderSubmesh.worldRadius = Math::max(Math::Magnitude(renderSubmesh.worldCenter - mam.minAABB),
1188         Math::Magnitude(mam.maxAABB - renderSubmesh.worldCenter));
1189 
1190     {
1191         mpd.sceneBoundingVolume.sumOfSubmeshPoints += renderSubmesh.worldCenter;
1192         mpd.sceneBoundingVolume.minAABB = Math::min(mpd.sceneBoundingVolume.minAABB, mam.minAABB);
1193         mpd.sceneBoundingVolume.maxAABB = Math::max(mpd.sceneBoundingVolume.maxAABB, mam.maxAABB);
1194         mpd.sceneBoundingVolume.submeshCount++;
1195     }
1196 
1197     SetupSubmeshBuffers(*gpuHandleMgr_, mpd.meshComponent, submesh, renderSubmesh);
1198 
1199     // Clear skinning bit if joint matrices were not given.
1200     if (skinJointIndex == RenderSceneDataConstants::INVALID_INDEX) {
1201         renderSubmesh.submeshFlags &= ~RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT;
1202     }
1203     if (isNegative) {
1204         renderSubmesh.submeshFlags |= RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT;
1205     }
1206 
1207     renderSubmesh.drawCommand.vertexCount = submesh.vertexCount;
1208     renderSubmesh.drawCommand.indexCount = submesh.indexCount;
1209     // NOTE: batch instance count
1210     renderSubmesh.drawCommand.instanceCount = submesh.instanceCount + mpd.batchInstanceCount;
1211 
1212     // overwrites the render submesh for every new material
1213     auto addMaterial = [&renderSubmesh, this](Entity materialEntity) {
1214         RenderMaterialIndices matIndices =
1215             AddRenderMaterial(*materialMgr_, *materialExtensionMgr_, *gpuHandleMgr_, *dsMaterial_, materialEntity);
1216         if (EntityUtil::IsValid(materialEntity)) {
1217             if (auto materialData = materialMgr_->Read(materialEntity); materialData) {
1218                 EvaluateMaterialModifications(*materialData);
1219             }
1220         }
1221         renderSubmesh.materialIndex = matIndices.materialIndex;
1222         renderSubmesh.customResourcesIndex = matIndices.materialCustomResourceIndex;
1223         dsMaterial_->AddSubmesh(renderSubmesh);
1224     };
1225     addMaterial(submesh.material);
1226     // updates only the material related indices in renderSubmesh for additional materials
1227     // NOTE: there will be as many RenderSubmeshes as materials
1228     for (const auto& matRef : submesh.additionalMaterials) {
1229         addMaterial(matRef);
1230     }
1231 }
1232 
ProcessMesh(const MeshProcessData & mpd,const MinAndMax & batchMam,const SkinProcessData & spd)1233 void RenderSystem::ProcessMesh(const MeshProcessData& mpd, const MinAndMax& batchMam, const SkinProcessData& spd)
1234 {
1235     CORE_STATIC_ASSERT(sizeof(RenderMeshComponent::customData) == sizeof(RenderMeshData::customData));
1236     RenderMeshData rmd { mpd.world, mpd.world, mpd.prevWorld, mpd.renderMeshEntity.id, mpd.meshEntity.id,
1237         mpd.layerMask };
1238     std::copy(std::begin(mpd.renderMeshComponent.customData), std::end(mpd.renderMeshComponent.customData),
1239         std::begin(rmd.customData));
1240     const uint32_t meshIndex = dsMaterial_->AddMeshData(rmd);
1241     uint32_t skinIndex = RenderSceneDataConstants::INVALID_INDEX;
1242     const bool useJoints = spd.jointMatricesComponent && (spd.jointMatricesComponent->count > 0);
1243     if (useJoints) {
1244         CORE_ASSERT(spd.prevJointMatricesComponent);
1245         const auto jm = array_view<Math::Mat4X4 const>(
1246             spd.jointMatricesComponent->jointMatrices, spd.jointMatricesComponent->count);
1247         const auto pjm = array_view<Math::Mat4X4 const>(
1248             spd.prevJointMatricesComponent->jointMatrices, spd.prevJointMatricesComponent->count);
1249         skinIndex = dsMaterial_->AddSkinJointMatrices(jm, pjm);
1250     }
1251 
1252     const bool isMeshNegative = Math::Determinant(mpd.world) < 0.0f;
1253     // NOTE: When object is skinned we use the mesh bounding box for all the submeshes because currently
1254     // there is no way to know here which joints affect one specific renderSubmesh.
1255     MinAndMax skinnedMeshBounds;
1256     if (useJoints) {
1257         skinnedMeshBounds.minAABB = spd.jointMatricesComponent->jointsAabbMin;
1258         skinnedMeshBounds.maxAABB = spd.jointMatricesComponent->jointsAabbMax;
1259     }
1260 
1261     CORE_ASSERT(picking_);
1262     for (uint32_t subMeshIdx = 0; subMeshIdx < mpd.meshComponent.submeshes.size(); ++subMeshIdx) {
1263         const auto& submesh = mpd.meshComponent.submeshes[subMeshIdx];
1264         MinAndMax mam =
1265             useJoints ? skinnedMeshBounds : picking_->GetWorldAABB(mpd.world, submesh.aabbMin, submesh.aabbMax);
1266         if (mpd.batchInstanceCount > 0) {
1267             mam.minAABB = Math::min(mam.minAABB, batchMam.minAABB);
1268             mam.maxAABB = Math::max(mam.maxAABB, batchMam.maxAABB);
1269         }
1270         ProcessSubmesh(mpd, submesh, meshIndex, subMeshIdx, skinIndex, mam, isMeshNegative);
1271     }
1272 }
1273 
ProcessRenderables(SceneBoundingVolumeHelper & sceneBoundingVolumeHelper)1274 void RenderSystem::ProcessRenderables(SceneBoundingVolumeHelper& sceneBoundingVolumeHelper)
1275 {
1276     renderableQuery_.Execute();
1277 
1278     for (const auto& row : renderableQuery_.GetResults()) {
1279         // In addition to the base our renderableQuery has two required components and one optional component:
1280         // (0) RenderMeshComponent
1281         // (1) NodeComponent
1282         // (2) WorldMatrixComponent
1283         // (3) PreviousWorldMatrixComponent
1284         // (4) LayerComponent (optional)
1285         // (5) JointMatrixComponent (optional)
1286         // (6) PreviousJointMatrixComponent (optional)
1287         const RenderMeshComponent renderMeshComponent = renderMeshMgr_->Get(row.components[0]);
1288         const NodeComponent nodeComponent = nodeMgr_->Get(row.components[1]);
1289         const WorldMatrixComponent renderMatrixComponent = worldMatrixMgr_->Get(row.components[2u]);
1290         const PreviousWorldMatrixComponent prevWorld = prevWorldMatrixMgr_->Get(row.components[3u]);
1291         const uint64_t layerMask = !row.IsValidComponentId(4u) ? LayerConstants::DEFAULT_LAYER_MASK
1292                                                                : layerMgr_->Get(row.components[4u]).layerMask;
1293         // batched render mesh components not processed linearly
1294         if (EntityUtil::IsValid(renderMeshComponent.renderMeshBatch)) {
1295             if (nodeComponent.effectivelyEnabled && (layerMask != LayerConstants::NONE_LAYER_MASK)) {
1296                 // NOTE: direct component id for skins added to batch processing
1297                 batches_[renderMeshComponent.renderMeshBatch].push_back(
1298                     { row.entity, renderMeshComponent.mesh, layerMask, row.components[5u], row.components[6u],
1299                         renderMatrixComponent.matrix, prevWorld.matrix });
1300             }
1301             continue;
1302         }
1303         // ignore disabled and nodes without layer mask
1304         if (nodeComponent.effectivelyEnabled && (layerMask != LayerConstants::NONE_LAYER_MASK)) {
1305             if (const auto meshData = meshMgr_->Read(renderMeshComponent.mesh); meshData) {
1306                 const auto& mesh = *meshData;
1307 
1308                 MeshProcessData mpd { layerMask, 0, row.entity, renderMeshComponent.mesh, mesh, renderMeshComponent,
1309                     renderMatrixComponent.matrix, prevWorld.matrix, sceneBoundingVolumeHelper };
1310                 // (5, 6) JointMatrixComponents are optional.
1311                 if (row.IsValidComponentId(5u) && row.IsValidComponentId(6u)) {
1312                     auto const jointMatricesData = jointMatricesMgr_->Read(row.components[5u]);
1313                     auto const prevJointMatricesData = prevJointMatricesMgr_->Read(row.components[6u]);
1314                     CORE_ASSERT(jointMatricesData);
1315                     CORE_ASSERT(prevJointMatricesData);
1316                     const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1317                     ProcessMesh(mpd, {}, spd);
1318                 } else {
1319                     ProcessMesh(mpd, {}, {});
1320                 }
1321             }
1322         }
1323     }
1324 
1325     ProcessBatchRenderables(sceneBoundingVolumeHelper);
1326 }
1327 
1328 namespace {
LogBatchValidation(const MeshComponent & mesh)1329 inline void LogBatchValidation(const MeshComponent& mesh)
1330 {
1331 #if (CORE3D_VALIDATION_ENABLED == 1)
1332     if (mesh.submeshes.size() > MAX_BATCH_SUBMESH_COUNT) {
1333         CORE_LOG_ONCE_E("submesh_counts_batch",
1334             "CORE3D_VALIDATION: GPU instancing batches not supported for submeshes with count %u > %u ",
1335             static_cast<uint32_t>(mesh.submeshes.size()), MAX_BATCH_SUBMESH_COUNT);
1336     }
1337 #endif
1338 }
1339 
DestroyBatchData(BASE_NS::unordered_map<CORE_NS::Entity,RenderSystem::BatchDataVector> & batches)1340 inline void DestroyBatchData(BASE_NS::unordered_map<CORE_NS::Entity, RenderSystem::BatchDataVector>& batches)
1341 {
1342     // NOTE: we destroy batch entity if its elements were not used in this frame
1343     for (auto iter = batches.begin(); iter != batches.end();) {
1344         if (iter->second.empty()) {
1345             iter = batches.erase(iter);
1346         } else {
1347             iter->second.clear();
1348             ++iter;
1349         }
1350     }
1351 }
1352 } // namespace
1353 
ProcessBatchRenderables(SceneBoundingVolumeHelper & sceneBoundingVolumeHelper)1354 void RenderSystem::ProcessBatchRenderables(SceneBoundingVolumeHelper& sceneBoundingVolumeHelper)
1355 {
1356     for (const auto& batchRef : batches_) {
1357         uint32_t batchIndex = 0;
1358         uint32_t batchedCount = 0;
1359         const uint32_t batchInstCount = static_cast<uint32_t>(batchRef.second.size());
1360         for (uint32_t entIdx = 0; entIdx < batchInstCount; ++entIdx) {
1361             const auto& inst = batchRef.second[entIdx];
1362             const Entity& entRef = inst.entity;
1363             const Entity& meshEntRef = inst.mesh;
1364             if (const auto meshData = meshMgr_->Read(meshEntRef); meshData) {
1365                 const auto& mesh = *meshData;
1366                 const RenderMeshComponent rmc = renderMeshMgr_->Get(entRef);
1367                 // process the first fully
1368                 if (batchIndex == 0) {
1369                     LogBatchValidation(mesh);
1370 
1371                     const uint32_t currPatchCount = Math::min(batchInstCount - batchedCount, MAX_BATCH_OBJECT_COUNT);
1372                     // process AABBs for all instances, the same mesh is used for all instances with their own transform
1373                     MinAndMax mam;
1374                     const BatchIndices batchIndices { ~0u, entIdx + 1, entIdx + currPatchCount };
1375                     CombineBatchWorldMinAndMax(batchRef.second, batchIndices, mesh, mam);
1376                     batchedCount += currPatchCount;
1377                     MeshProcessData mpd { inst.layerMask, currPatchCount - 1u, entRef, meshEntRef, mesh, rmc, inst.mtx,
1378                         inst.prevWorld, sceneBoundingVolumeHelper };
1379                     // Optional skin, cannot change based on submesh)
1380                     if (inst.jointId != IComponentManager::INVALID_COMPONENT_ID) {
1381                         auto const jointMatricesData = jointMatricesMgr_->Read(inst.jointId);
1382                         auto const prevJointMatricesData = prevJointMatricesMgr_->Read(inst.prevJointId);
1383                         const SkinProcessData spd { &(*jointMatricesData), &(*prevJointMatricesData) };
1384                         ProcessMesh(mpd, mam, spd);
1385                     } else {
1386                         ProcessMesh(mpd, mam, {});
1387                     }
1388                 } else {
1389                     // NOTE: normal matrix is missing
1390                     RenderMeshData rmd { inst.mtx, inst.mtx, inst.prevWorld, entRef.id, meshEntRef.id, inst.layerMask };
1391                     std::copy(std::begin(rmc.customData), std::end(rmc.customData), std::begin(rmd.customData));
1392                     dsMaterial_->AddMeshData(rmd);
1393                     // NOTE: we force add a new material for every instance object, but we do not fetch texture handles
1394                     AddSingleMaterial(
1395                         *materialMgr_, *gpuHandleMgr_, *dsMaterial_, mesh.submeshes[0].material, false, false);
1396                 }
1397                 if (++batchIndex == MAX_BATCH_OBJECT_COUNT) {
1398                     batchIndex = 0;
1399                 }
1400             }
1401         }
1402     }
1403     // NOTE: we destroy batch entity if its elements were not used in this frame
1404     DestroyBatchData(batches_);
1405 }
1406 
CombineBatchWorldMinAndMax(const BatchDataVector & batchVec,const BatchIndices & batchIndices,const MeshComponent & mesh,MinAndMax & mam) const1407 void RenderSystem::CombineBatchWorldMinAndMax(
1408     const BatchDataVector& batchVec, const BatchIndices& batchIndices, const MeshComponent& mesh, MinAndMax& mam) const
1409 {
1410     CORE_ASSERT(picking_);
1411     CORE_ASSERT(batchIndices.batchEndCount <= static_cast<uint32_t>(batchVec.size()));
1412     const int32_t batchCount =
1413         static_cast<int32_t>(batchIndices.batchEndCount) - static_cast<int32_t>(batchIndices.batchStartIndex);
1414     if (batchCount <= 1) {
1415         return;
1416     }
1417     if (batchIndices.submeshIndex == ~0u) {
1418         // process first the full mesh, and then only transform per batch the AABB
1419         MinAndMax meshAABB;
1420         for (const auto& subRef : mesh.submeshes) {
1421             const BatchData& bData = batchVec[0u];
1422             const MinAndMax localMam = picking_->GetWorldAABB(bData.mtx, subRef.aabbMin, subRef.aabbMax);
1423             meshAABB.minAABB = Math::min(meshAABB.minAABB, localMam.minAABB);
1424             meshAABB.maxAABB = Math::max(meshAABB.maxAABB, localMam.maxAABB);
1425         }
1426         mam.minAABB = Math::min(mam.minAABB, meshAABB.minAABB);
1427         mam.maxAABB = Math::max(mam.maxAABB, meshAABB.maxAABB);
1428         // then start from 2nd index in batch
1429         for (uint32_t bIdx = batchIndices.batchStartIndex + 1; bIdx < batchIndices.batchEndCount; ++bIdx) {
1430             const BatchData& bData = batchVec[bIdx];
1431             const MinAndMax localMam = picking_->GetWorldAABB(bData.mtx, meshAABB.minAABB, meshAABB.maxAABB);
1432             mam.minAABB = Math::min(mam.minAABB, localMam.minAABB);
1433             mam.maxAABB = Math::max(mam.maxAABB, localMam.maxAABB);
1434         }
1435     } else if (batchIndices.submeshIndex < mesh.submeshes.size()) {
1436         const auto& subRef = mesh.submeshes[batchIndices.submeshIndex];
1437         for (uint32_t bIdx = batchIndices.batchStartIndex; bIdx < batchIndices.batchEndCount; ++bIdx) {
1438             const BatchData& bData = batchVec[bIdx];
1439             const MinAndMax localMam = picking_->GetWorldAABB(bData.mtx, subRef.aabbMin, subRef.aabbMax);
1440             mam.minAABB = Math::min(mam.minAABB, localMam.minAABB);
1441             mam.maxAABB = Math::max(mam.maxAABB, localMam.maxAABB);
1442         }
1443     }
1444 }
1445 
CalculateSceneBounds(const SceneBoundingVolumeHelper & sceneBoundingVolumeHelper)1446 void RenderSystem::CalculateSceneBounds(const SceneBoundingVolumeHelper& sceneBoundingVolumeHelper)
1447 {
1448     if (sceneBoundingVolumeHelper.submeshCount == 0) {
1449         sceneBoundingSphereRadius_ = 0.0f;
1450         sceneBoundingSpherePosition_ = Math::Vec3();
1451     } else {
1452         const auto boundingSpherePosition =
1453             sceneBoundingVolumeHelper.sumOfSubmeshPoints / static_cast<float>(sceneBoundingVolumeHelper.submeshCount);
1454 
1455         const float radMin = Math::Magnitude(boundingSpherePosition - sceneBoundingVolumeHelper.minAABB);
1456         const float radMax = Math::Magnitude(sceneBoundingVolumeHelper.maxAABB - boundingSpherePosition);
1457         const float boundingSphereRadius = Math::max(radMin, radMax);
1458 
1459         // Compensate jitter and adjust scene bounding sphere only if change in bounds is meaningful.
1460         if (sceneBoundingSphereRadius_ > 0.0f) {
1461             // Calculate distance to new bounding sphere origin from current sphere.
1462             const float pointDistance = Math::Magnitude(boundingSpherePosition - sceneBoundingSpherePosition_);
1463             // Calculate distance to edge of new bounding sphere from current sphere origin.
1464             const float sphereEdgeDistance = pointDistance + boundingSphereRadius;
1465 
1466             // Calculate step size for adjustment, use 10% granularity from current bounds.
1467             constexpr float granularityPct = 0.10f;
1468             const float granularity = sceneBoundingSphereRadius_ * granularityPct;
1469 
1470             // Calculate required change of size, in order to fit new sphere inside current bounds.
1471             const float radDifference = sphereEdgeDistance - sceneBoundingSphereRadius_;
1472             const float posDifference = Math::Magnitude(boundingSpherePosition - sceneBoundingSpherePosition_);
1473             // We need to adjust only if the change is bigger than the step size.
1474             if ((Math::abs(radDifference) > granularity) || (posDifference > granularity)) {
1475                 // Calculate how many steps we need to change and in to which direction.
1476                 const int32_t radAmount =
1477                     static_cast<int>(ceil((boundingSphereRadius - sceneBoundingSphereRadius_) / granularity));
1478                 const int32_t posAmount = static_cast<int>(ceil(posDifference / granularity));
1479                 if ((radAmount != 0) || (posAmount != 0)) {
1480                     // Update size and position of the bounds.
1481                     sceneBoundingSpherePosition_ = boundingSpherePosition;
1482                     sceneBoundingSphereRadius_ = sceneBoundingSphereRadius_ + (radAmount * granularity);
1483                 }
1484             }
1485         } else {
1486             // No existing bounds, start with new values.
1487             sceneBoundingSphereRadius_ = boundingSphereRadius;
1488             sceneBoundingSpherePosition_ = boundingSpherePosition;
1489         }
1490     }
1491 }
1492 
ProcessCameras(const RenderConfigurationComponent & renderConfig,const Entity & mainCameraEntity,RenderScene & renderScene)1493 void RenderSystem::ProcessCameras(
1494     const RenderConfigurationComponent& renderConfig, const Entity& mainCameraEntity, RenderScene& renderScene)
1495 {
1496     // The scene camera and active render cameras are added here. ProcessReflections reflection cameras.
1497     // This is temporary when moving towards camera based rendering in 3D context.
1498     const uint32_t mainCameraId = cameraMgr_->GetComponentId(mainCameraEntity);
1499     const auto cameraCount = cameraMgr_->GetComponentCount();
1500     for (IComponentManager::ComponentId id = 0; id < cameraCount; ++id) {
1501         const CameraComponent component = cameraMgr_->Get(id);
1502         if ((mainCameraId != id) && ((component.sceneFlags & CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT) == 0)) {
1503             continue;
1504         }
1505         const Entity cameraEntity = cameraMgr_->GetEntity(id);
1506         const auto worldMatrixComponentId = worldMatrixMgr_->GetComponentId(cameraEntity);
1507         // Make sure we have render matrix.
1508         if (worldMatrixComponentId != IComponentManager::INVALID_COMPONENT_ID) {
1509             const WorldMatrixComponent renderMatrixComponent = worldMatrixMgr_->Get(worldMatrixComponentId);
1510 
1511             float determinant = 0.0f;
1512             const Math::Mat4X4 view = Math::Inverse(Math::Mat4X4(renderMatrixComponent.matrix.data), determinant);
1513 
1514             RenderCamera::Flags rcFlags = 0;
1515             bool createPrePassCam = false;
1516             if (mainCameraId == id) {
1517                 renderScene.cameraIndex = static_cast<uint32_t>(dsCamera_->GetCameraCount());
1518                 rcFlags = RenderCamera::CAMERA_FLAG_MAIN_BIT;
1519                 createPrePassCam = (component.pipelineFlags & CameraComponent::FORCE_COLOR_PRE_PASS_BIT) ||
1520                                    (component.pipelineFlags & CameraComponent::ALLOW_COLOR_PRE_PASS_BIT);
1521                 renderProcessing_.frameFlags |=
1522                     (component.pipelineFlags & CameraComponent::FORCE_COLOR_PRE_PASS_BIT) ? NEEDS_COLOR_PRE_PASS : 0;
1523             }
1524 
1525             bool isCameraNegative = determinant < 0.0f;
1526             const auto proj = CalculateProjectionMatrix(component, isCameraNegative);
1527 
1528             RenderCamera camera;
1529             FillRenderCameraBaseFromCameraComponent(*gpuHandleMgr_, component, camera, true);
1530             // we add entity id as camera name if there isn't name (we need this for render node graphs)
1531             camera.id = cameraEntity.id;
1532             camera.name = GetCameraName(*nameMgr_, cameraEntity);
1533             camera.matrices.view = view;
1534             camera.matrices.proj = proj;
1535             const CameraData prevFrameCamData = UpdateAndGetPreviousFrameCameraData(cameraEntity, view, proj);
1536             camera.matrices.viewPrevFrame = prevFrameCamData.view;
1537             camera.matrices.projPrevFrame = prevFrameCamData.proj;
1538             camera.flags |= (rcFlags | ((isCameraNegative) ? RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT : 0));
1539             camera.environment = GetRenderCameraEnvironmentFromComponent(
1540                 layerMgr_, gpuHandleMgr_, environmentMgr_, materialExtensionMgr_, renderConfig, component);
1541             camera.fog = GetRenderCameraFogFromComponent(layerMgr_, fogMgr_, renderConfig, component);
1542             camera.postProcessName = GetPostProcessName(postProcessMgr_, component.postProcess);
1543 
1544             // NOTE: setting up the color pre pass with a target name is a temporary solution
1545             if (createPrePassCam) {
1546                 camera.prePassColorTargetName = DefaultMaterialCameraConstants::CAMERA_COLOR_PREFIX_NAME +
1547                                                 renderScene.name + to_string(PREPASS_CAMERA_START_UNIQUE_ID);
1548             }
1549             dsCamera_->AddCamera(camera);
1550             // The order of setting cameras matter (main camera index is set already)
1551             if (createPrePassCam) {
1552                 dsCamera_->AddCamera(CreateColorPrePassRenderCamera(
1553                     *gpuHandleMgr_, *cameraMgr_, camera, component.prePassCamera, PREPASS_CAMERA_START_UNIQUE_ID));
1554             }
1555         }
1556     }
1557 }
1558 
ProcessReflection(const ComponentQuery::ResultRow & row,const RenderCamera & camera)1559 bool RenderSystem::ProcessReflection(const ComponentQuery::ResultRow& row, const RenderCamera& camera)
1560 {
1561     // ReflectionsQuery has three required components:
1562     // (0) PlanarReflectionComponent
1563     // (1) WorldMatrixComponent
1564     // (2) NodeComponent
1565     // Skip if this node is disabled.
1566     const NodeComponent nodeComponent = nodeMgr_->Get(row.components[2u]);
1567     if (!nodeComponent.effectivelyEnabled) {
1568         return false;
1569     }
1570     PlanarReflectionComponent reflComponent = planarReflectionMgr_->Get(row.components[0u]);
1571     if ((reflComponent.additionalFlags & PlanarReflectionComponent::FlagBits::ACTIVE_RENDER_BIT) == 0) {
1572         return false;
1573     }
1574     const WorldMatrixComponent reflectionPlaneMatrix = worldMatrixMgr_->Get(row.components[1u]);
1575 
1576     // Calculate reflected view matrix from camera matrix.
1577     // Reflection plane.
1578     const Math::Vec3 translation = reflectionPlaneMatrix.matrix.w;
1579     const Math::Vec3 normal = Math::Normalize(Math::GetColumn(reflectionPlaneMatrix.matrix, 1));
1580     const float distance = -Math::Dot(normal, translation) - reflComponent.clipOffset;
1581     const Math::Vec4 plane { normal.x, normal.y, normal.z, distance };
1582 
1583     // Calculate mirror matrix from plane.
1584     const Math::Mat4X4 reflection = CalculateReflectionMatrix(plane);
1585     const Math::Mat4X4 reflectedView = camera.matrices.view * reflection;
1586 
1587     Math::Mat4X4 reflectedProjection = camera.matrices.proj;
1588 
1589     // NOTE: Should modify near plane of projection matrix to clip in to reflection plane.
1590     // This effectively optimizes away the un-wanted objects that are behind the plane
1591     // and otherwise would be visible in the reflection.
1592     // e.g.
1593     // CalculateCameraSpaceClipPlane()
1594     // calculate camera-space projection matrix that has clip plane as near plane.
1595     // CalculateObliqueProjectionMatrix()
1596 
1597     const ReflectionPlaneTargetUpdate rptu = UpdatePlaneReflectionTargetResolution(
1598         *gpuResourceMgr_, *gpuHandleMgr_, *planarReflectionMgr_, camera, row.entity, reflComponent);
1599     if (rptu.recreated) {
1600         UpdateReflectionPlaneMaterial(*renderMeshMgr_, *meshMgr_, *materialMgr_, row.entity, reflComponent, rptu);
1601     }
1602 
1603     RenderCamera reflCam;
1604     reflCam.id = row.entity.id;
1605     reflCam.layerMask = reflComponent.layerMask;
1606     reflCam.matrices.view = reflectedView;
1607     reflCam.matrices.proj = reflectedProjection;
1608     const CameraData prevFrameCamData =
1609         UpdateAndGetPreviousFrameCameraData(row.entity, reflCam.matrices.view, reflCam.matrices.proj);
1610     reflCam.matrices.viewPrevFrame = prevFrameCamData.view;
1611     reflCam.matrices.projPrevFrame = prevFrameCamData.proj;
1612     reflCam.viewport = { camera.viewport[0u], camera.viewport[1u], camera.viewport[2u], camera.viewport[3u] };
1613     reflCam.targetType = RenderCamera::CameraTargetType::TARGET_TYPE_CUSTOM_TARGETS;
1614     reflCam.depthTarget = gpuHandleMgr_->GetRenderHandleReference(reflComponent.depthRenderTarget);
1615     reflCam.colorTargets[0u] = gpuHandleMgr_->GetRenderHandleReference(reflComponent.colorRenderTarget);
1616 
1617     reflCam.renderResolution = { reflComponent.renderTargetResolution[0], reflComponent.renderTargetResolution[1] };
1618     reflCam.zNear = camera.zNear;
1619     reflCam.zFar = camera.zFar;
1620     reflCam.flags = camera.flags & (~(RenderCamera::CAMERA_FLAG_MSAA_BIT | RenderCamera::CAMERA_FLAG_HISTORY_BIT));
1621     reflCam.flags |= (RenderCamera::CAMERA_FLAG_REFLECTION_BIT | RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT);
1622     reflCam.renderPipelineType = RenderCamera::RenderPipelineType::LIGHT_FORWARD;
1623     reflCam.clearDepthStencil = camera.clearDepthStencil;
1624     reflCam.clearColorValues = camera.clearColorValues;
1625     reflCam.cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
1626     reflCam.environment = camera.environment;
1627     reflCam.postProcessName = DefaultMaterialCameraConstants::CAMERA_REFLECTION_POST_PROCESS_PREFIX_NAME;
1628     dsCamera_->AddCamera(reflCam);
1629 
1630     return true;
1631 }
1632 
ProcessReflections(Entity cameraEntity,const RenderScene & renderScene)1633 bool RenderSystem::ProcessReflections(Entity cameraEntity, const RenderScene& renderScene)
1634 {
1635     reflectionsQuery_.Execute();
1636 
1637     const auto queryResults = reflectionsQuery_.GetResults();
1638     const size_t cameraCount = dsCamera_->GetCameraCount();
1639 #if (CORE3D_VALIDATION_ENABLED == 1)
1640     if ((!queryResults.empty()) && (!EntityUtil::IsValid(cameraEntity))) {
1641         CORE_LOG_ONCE_W("3d_validation_refl_main_cam", "CORE3D_VALIDATION: reflections supported only for main camera");
1642     }
1643 #endif
1644     if ((!EntityUtil::IsValid(cameraEntity)) || queryResults.empty() || (renderScene.cameraIndex >= cameraCount)) {
1645         return false;
1646     }
1647 
1648     // copy needed (a single camera is added to dataStoreCamera_ in every loop)
1649     const auto camera = dsCamera_->GetCameras()[renderScene.cameraIndex];
1650     bool hasReflections = false;
1651     for (const auto& row : queryResults) {
1652         if (ProcessReflection(row, camera)) {
1653             hasReflections = true;
1654         }
1655     }
1656 
1657     // The flag does not have any purpose ATM, remove?
1658     return hasReflections;
1659 }
1660 
ProcessLight(const LightProcessData & lpd)1661 void RenderSystem::ProcessLight(const LightProcessData& lpd)
1662 {
1663     const auto& lightComponent = lpd.lightComponent;
1664     RenderLight light { lpd.entity.id, lightComponent.lightLayerMask,
1665         { lpd.world[3u], 1.0f }, // the last column (3) of the world matrix contains the world position.
1666         { Math::Normalize(lpd.world * Math::Vec4(0.0f, 0.0f, -1.0f, 0.0f)), 0.0f },
1667         { lightComponent.color, lightComponent.intensity } };
1668 
1669     // See:
1670     // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
1671     const float outer = Math::clamp(lightComponent.spotOuterAngle, lightComponent.spotInnerAngle, Math::PI / 2.0f);
1672     const float inner = Math::clamp(lightComponent.spotInnerAngle, 0.0f, outer);
1673 
1674     if (lightComponent.type == LightComponent::Type::DIRECTIONAL) {
1675         light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT;
1676     } else if (lightComponent.type == LightComponent::Type::POINT) {
1677         light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_POINT_LIGHT_BIT;
1678     } else if (lightComponent.type == LightComponent::Type::SPOT) {
1679         light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_SPOT_LIGHT_BIT;
1680 
1681         const float cosInnerConeAngle = cosf(inner);
1682         const float cosOuterConeAngle = cosf(outer);
1683 
1684         const float lightAngleScale = 1.0f / Math::max(0.001f, cosInnerConeAngle - cosOuterConeAngle);
1685         const float lightAngleOffset = -cosOuterConeAngle * lightAngleScale;
1686 
1687         light.spotLightParams = { lightAngleScale, lightAngleOffset, inner, outer };
1688     }
1689     light.range = ComponentUtilFunctions::CalculateSafeLightRange(lightComponent.range, lightComponent.intensity);
1690 
1691     if (lightComponent.shadowEnabled) {
1692         light.shadowFactors = { Math::clamp01(lightComponent.shadowStrength), lightComponent.shadowDepthBias,
1693             lightComponent.shadowNormalBias, 0.0f };
1694         ProcessShadowCamera(lpd, light);
1695     }
1696 
1697     dsLight_->AddLight(light);
1698 }
1699 
ProcessShadowCamera(const LightProcessData lpd,RenderLight & light)1700 void RenderSystem::ProcessShadowCamera(const LightProcessData lpd, RenderLight& light)
1701 {
1702     if ((light.lightUsageFlags &
1703             (RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT | RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT)) == 0) {
1704         return;
1705     }
1706     light.lightUsageFlags |= RenderLight::LightUsageFlagBits::LIGHT_USAGE_SHADOW_LIGHT_BIT;
1707     light.shadowCameraIndex = static_cast<uint32_t>(dsCamera_->GetCameraCount());
1708 
1709     float zNear = 0.0f;
1710     float zFar = 0.0f;
1711     RenderCamera camera;
1712     camera.id = SHADOW_CAMERA_START_UNIQUE_ID + light.shadowCameraIndex; // id used for easier uniqueness
1713     camera.shadowId = lpd.entity.id;
1714     camera.layerMask = lpd.lightComponent.shadowLayerMask; // we respect light shadow rendering mask
1715     if (light.lightUsageFlags & RenderLight::LIGHT_USAGE_DIRECTIONAL_LIGHT_BIT) {
1716         // NOTE: modifies the light camera to follow center of scene
1717         // Add slight bias offset to radius.
1718         const float radius =
1719             lpd.renderScene.worldSceneBoundingSphereRadius + lpd.renderScene.worldSceneBoundingSphereRadius * 0.05f;
1720         const Math::Vec3 lightPos =
1721             lpd.renderScene.worldSceneCenter - Math::Vec3(light.dir.x, light.dir.y, light.dir.z) * radius;
1722         camera.matrices.view = Math::LookAtRh(lightPos, lpd.renderScene.worldSceneCenter, { 0.0f, 1.0f, 0.0f });
1723         camera.matrices.proj = Math::OrthoRhZo(-radius, radius, -radius, radius, 0.001f, radius * 2.0f);
1724         zNear = 0.0f;
1725         zFar = 6.0f;
1726     } else if (light.lightUsageFlags & RenderLight::LIGHT_USAGE_SPOT_LIGHT_BIT) {
1727         float determinant = 0.0f;
1728         camera.matrices.view = Math::Inverse(lpd.world, determinant);
1729         const float yFov = Math::clamp(light.spotLightParams.w * 2.0f, 0.0f, Math::PI);
1730         zFar = light.range; // use light range for z far
1731         zNear = Math::max(0.1f, lpd.lightComponent.nearPlane);
1732         camera.matrices.proj = Math::PerspectiveRhZo(yFov, 1.0f, zNear, zFar);
1733     }
1734 
1735     camera.matrices.proj[1][1] *= -1.0f; // left-hand NDC while Vulkan right-handed -> flip y
1736 
1737     const CameraData prevFrameCamData =
1738         UpdateAndGetPreviousFrameCameraData(lpd.entity, camera.matrices.viewPrevFrame, camera.matrices.projPrevFrame);
1739     camera.matrices.viewPrevFrame = prevFrameCamData.view;
1740     camera.matrices.projPrevFrame = prevFrameCamData.proj;
1741     camera.viewport = { 0.0f, 0.0f, 1.0f, 1.0f };
1742     // get current default resolution
1743     camera.renderResolution = dsLight_->GetShadowQualityResolution();
1744     // NOTE: custom shadow camera targets not yet supported
1745     camera.zNear = zNear;
1746     camera.zFar = zFar;
1747     camera.flags = RenderCamera::CAMERA_FLAG_SHADOW_BIT;
1748     camera.cullType = RenderCamera::CameraCullType::CAMERA_CULL_VIEW_FRUSTUM;
1749 
1750     dsCamera_->AddCamera(camera);
1751 }
1752 
ProcessLights(RenderScene & renderScene)1753 void RenderSystem::ProcessLights(RenderScene& renderScene)
1754 {
1755     lightQuery_.Execute();
1756 
1757     uint32_t spotLightIndex = 0;
1758     for (const auto& row : lightQuery_.GetResults()) {
1759         // In addition to the base our lightQuery has two required components and two optional components:
1760         // (0) LightComponent
1761         // (1) NodeComponent
1762         // (2) WorldMatrixComponent
1763         const LightComponent lightComponent = lightMgr_->Get(row.components[0u]);
1764         const NodeComponent nodeComponent = nodeMgr_->Get(row.components[1u]);
1765         const WorldMatrixComponent renderMatrixComponent = worldMatrixMgr_->Get(row.components[2u]);
1766         const uint64_t layerMask = !row.IsValidComponentId(3u) ? LayerConstants::DEFAULT_LAYER_MASK
1767                                                                : layerMgr_->Get(row.components[3u]).layerMask;
1768         if (nodeComponent.effectivelyEnabled) {
1769             const Math::Mat4X4 world(renderMatrixComponent.matrix.data);
1770             const LightProcessData lpd { layerMask, row.entity, lightComponent, world, renderScene, spotLightIndex };
1771             ProcessLight(lpd);
1772         }
1773     }
1774 }
1775 
ProcessPostProcesses()1776 void RenderSystem::ProcessPostProcesses()
1777 {
1778     if (properties_.dataStoreManager) {
1779         IRenderDataStoreManager& rdsMgr = *properties_.dataStoreManager;
1780         auto* dataStore = static_cast<IRenderDataStorePod*>(rdsMgr.GetRenderDataStore(POD_DATA_STORE_NAME));
1781         if (!dataStore) {
1782             return;
1783         }
1784 
1785         const auto postProcessCount = postProcessMgr_->GetComponentCount();
1786         for (IComponentManager::ComponentId id = 0; id < postProcessCount; ++id) {
1787             if (const auto handle = postProcessMgr_->Read(id); handle) {
1788                 const auto& pp = *handle;
1789 
1790                 // just copy values (no support for fog control)
1791                 PostProcessConfiguration ppConfig;
1792                 ppConfig.enableFlags = pp.enableFlags;
1793                 ppConfig.bloomConfiguration = pp.bloomConfiguration;
1794                 ppConfig.vignetteConfiguration = pp.vignetteConfiguration;
1795                 ppConfig.colorFringeConfiguration = pp.colorFringeConfiguration;
1796                 ppConfig.ditherConfiguration = pp.ditherConfiguration;
1797                 ppConfig.blurConfiguration = pp.blurConfiguration;
1798                 ppConfig.colorConversionConfiguration = pp.colorConversionConfiguration;
1799                 ppConfig.tonemapConfiguration = pp.tonemapConfiguration;
1800                 ppConfig.fxaaConfiguration = pp.fxaaConfiguration;
1801 
1802                 const Entity ppEntity = postProcessMgr_->GetEntity(id);
1803                 const auto ppName = GetPostProcessName(postProcessMgr_, ppEntity);
1804                 auto const dataView = dataStore->Get(ppName);
1805                 if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
1806                     dataStore->Set(ppName, arrayviewU8(ppConfig));
1807                 } else {
1808                     renderProcessing_.postProcessPods.emplace_back(ppName);
1809                     dataStore->CreatePod(POST_PROCESS_NAME, ppName, arrayviewU8(ppConfig));
1810                 }
1811             }
1812         }
1813     }
1814 }
1815 
DestroyRenderDataStores()1816 void RenderSystem::DestroyRenderDataStores()
1817 {
1818     if (properties_.dataStoreManager) {
1819         IRenderDataStoreManager& rdsMgr = *properties_.dataStoreManager;
1820         if (auto* dataStore = static_cast<IRenderDataStorePod*>(rdsMgr.GetRenderDataStore(POD_DATA_STORE_NAME));
1821             dataStore) {
1822             for (const auto& ref : renderProcessing_.postProcessPods) {
1823                 dataStore->DestroyPod(POST_PROCESS_NAME, ref.c_str());
1824             }
1825         }
1826     }
1827 }
1828 
FetchFullScene()1829 void RenderSystem::FetchFullScene()
1830 {
1831     if (!active_) {
1832         return;
1833     }
1834 
1835 #if (CORE3D_DEV_ENABLED == 1)
1836     CORE_CPU_PERF_BEGIN(graphCpuTimer, "ECS", "RenderSystem", "FetchRenderables_Cpu");
1837 #endif
1838 
1839     // Process scene settings (if present), look up first active scene.
1840     const RenderConfigurationComponent renderConfig = GetRenderConfigurationComponent();
1841     const Entity cameraEntity = ProcessScene(renderConfig);
1842 
1843     RenderScene renderDataScene;
1844     if (renderConfig.customRenderNodeGraph) {
1845         renderDataScene.customRenderNodeGraph =
1846             gpuHandleMgr_->GetRenderHandleReference(renderConfig.customRenderNodeGraph);
1847     }
1848     renderDataScene.customRenderNodeGraphFile = renderConfig.customRenderNodeGraphFile;
1849     renderDataScene.name = properties_.dataStoreScene;
1850     renderDataScene.dataStoreNameCamera = properties_.dataStoreCamera;
1851     renderDataScene.dataStoreNameLight = properties_.dataStoreLight;
1852     renderDataScene.dataStoreNameMaterial = properties_.dataStoreMaterial;
1853     renderDataScene.dataStoreNameMorph = properties_.dataStoreMorph;
1854     constexpr double uToMsDiv = 1000.0;
1855     constexpr double uToSDiv = 1000000.0;
1856     renderDataScene.sceneDeltaTime =
1857         static_cast<float>(static_cast<double>(deltaTime_) / uToMsDiv); // real delta time used for scene as well
1858     renderDataScene.totalTime = static_cast<float>(static_cast<double>(totalTime_) / uToSDiv);
1859     renderDataScene.deltaTime = renderDataScene.sceneDeltaTime;
1860     renderDataScene.frameIndex = static_cast<uint32_t>((frameIndex_ % std::numeric_limits<uint32_t>::max()));
1861     renderProcessing_.frameFlags = 0; // zero frame flags for camera processing
1862 
1863     ProcessCameras(renderConfig, cameraEntity, renderDataScene);
1864     ProcessReflections(cameraEntity, renderDataScene);
1865     ProcessPostProcesses();
1866 
1867     SceneBoundingVolumeHelper sceneBoundingVolumeHelper; // does not try to be exact atm
1868 
1869     // Process all render components.
1870     ProcessRenderables(sceneBoundingVolumeHelper);
1871 
1872     // Process render node graphs automatically based on camera if needed bits set for properties
1873     // Some materials might request color pre-pass etc. (needs to be done after renderables are processed)
1874     ProcessRenderNodeGraphs(renderConfig, renderDataScene);
1875 
1876     // NOTE: move world sphere calculation to own system
1877     CalculateSceneBounds(sceneBoundingVolumeHelper);
1878 
1879     renderDataScene.worldSceneCenter = sceneBoundingSpherePosition_;
1880     renderDataScene.worldSceneBoundingSphereRadius = sceneBoundingSphereRadius_;
1881 
1882     // Process lights.
1883     ProcessLights(renderDataScene);
1884 
1885     dsScene_->SetScene(renderDataScene);
1886 
1887     // Remove prev frame data from not used cameras
1888     for (auto iter = cameraData_.begin(); iter != cameraData_.end();) {
1889         if (iter->second.lastFrameIndex != frameIndex_) {
1890             iter = cameraData_.erase(iter);
1891         } else {
1892             ++iter;
1893         }
1894     }
1895 
1896 #if (CORE3D_DEV_ENABLED == 1)
1897     CORE_CPU_PERF_END(graphCpuTimer);
1898 #endif
1899 }
1900 
ProcessRenderNodeGraphs(const RenderConfigurationComponent & renderConfig,const RenderScene & renderScene)1901 void RenderSystem::ProcessRenderNodeGraphs(
1902     const RenderConfigurationComponent& renderConfig, const RenderScene& renderScene)
1903 {
1904     renderProcessing_.orderedRenderNodeGraphs.clear();
1905     const bool createRngs =
1906         (renderConfig.renderingFlags & RenderConfigurationComponent::SceneRenderingFlagBits::CREATE_RNGS_BIT);
1907     if (createRngs && graphicsContext_ && renderUtil_) {
1908         // first create scene render node graph if needed
1909         // we need to have scene render node graph as a separate
1910         renderProcessing_.orderedRenderNodeGraphs.emplace_back(GetSceneRenderNodeGraph(renderScene));
1911 
1912         // NOTE: should combine specific color pre pass for every render camera
1913         RenderHandleReference mainCamRng;
1914         RenderHandleReference mainColorPrePassHandle;
1915         const auto& renderCameras = dsCamera_->GetCameras();
1916         // then process all needed active cameras
1917         for (uint32_t camIdx = 0; camIdx < renderCameras.size(); ++camIdx) {
1918             const auto& camRef = renderCameras[camIdx];
1919             // main camera or shadow cameras are not interesting to us here
1920             if (camRef.flags & RenderCamera::CAMERA_FLAG_SHADOW_BIT) {
1921                 continue;
1922             }
1923             CORE_ASSERT(camRef.id != 0xFFFFFFFFffffffff); // there must be an id for uniqueness
1924             const RenderHandleReference handle = GetCameraRenderNodeGraph(renderScene, camRef);
1925             if (camIdx == renderScene.cameraIndex) {
1926                 mainCamRng = handle;
1927             } else {
1928                 // we do not push pre pass camera to rendering here
1929                 if (camRef.flags & RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT) {
1930                     mainColorPrePassHandle =
1931                         (renderProcessing_.frameFlags & NEEDS_COLOR_PRE_PASS) ? handle : RenderHandleReference {};
1932                 } else {
1933                     // NOTE: temporary insert for "pre-pass" cameras (e.g. reflection)
1934                     // +1 for scene index
1935                     if (camRef.flags & RenderCamera::CAMERA_FLAG_REFLECTION_BIT) {
1936                         renderProcessing_.orderedRenderNodeGraphs.insert(
1937                             renderProcessing_.orderedRenderNodeGraphs.begin() + 1u, handle);
1938                     } else {
1939                         renderProcessing_.orderedRenderNodeGraphs.emplace_back(handle);
1940                     }
1941                 }
1942             }
1943         }
1944 
1945         // then main camera as the final camera
1946         if (renderScene.cameraIndex < renderCameras.size()) {
1947             if (mainColorPrePassHandle) {
1948                 renderProcessing_.orderedRenderNodeGraphs.emplace_back(mainColorPrePassHandle);
1949             }
1950             if (mainCamRng) {
1951                 renderProcessing_.orderedRenderNodeGraphs.emplace_back(mainCamRng);
1952             }
1953         }
1954         // destroy unused after two frames
1955         const uint64_t ageLimit = (frameIndex_ < 2) ? 0 : (frameIndex_ - 2);
1956         for (auto iter = renderProcessing_.camIdToRng.begin(); iter != renderProcessing_.camIdToRng.end();) {
1957             if (iter->second.enableAutoDestroy && iter->second.lastFrameIndex < ageLimit) {
1958                 iter = renderProcessing_.camIdToRng.erase(iter);
1959             } else {
1960                 ++iter;
1961             }
1962         }
1963     }
1964 }
1965 
GetCameraRenderNodeGraph(const RenderScene & renderScene,const RenderCamera & renderCamera)1966 RenderHandleReference RenderSystem::GetCameraRenderNodeGraph(
1967     const RenderScene& renderScene, const RenderCamera& renderCamera)
1968 {
1969     constexpr uint32_t rngChangeFlags = RenderCamera::CAMERA_FLAG_MSAA_BIT;
1970     auto createNewRng = [](auto& rngm, const auto& rnUtil, const auto& scene, const auto& obj) {
1971         const RenderNodeGraphDesc desc = rnUtil->GetRenderNodeGraphDesc(scene, obj, 0);
1972         return rngm.Create(
1973             IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, desc, {}, scene.name);
1974     };
1975 
1976     IRenderNodeGraphManager& rngm = renderContext_->GetRenderNodeGraphManager();
1977     RenderHandleReference handle = renderCamera.customRenderNodeGraph;
1978     if (!handle) {
1979         if (auto iter = renderProcessing_.camIdToRng.find(renderCamera.id);
1980             iter != renderProcessing_.camIdToRng.cend()) {
1981             // NOTE: not optimal, currently re-creates a render node graph if:
1982             // * msaa flags have changed
1983             // * post process name / component has changed
1984             // * pipeline has changed
1985             const bool reCreate = ((iter->second.flags & rngChangeFlags) != (renderCamera.flags & rngChangeFlags)) ||
1986                                   (iter->second.postProcessName != renderCamera.postProcessName) ||
1987                                   (iter->second.renderPipelineType != renderCamera.renderPipelineType);
1988             if (reCreate) {
1989                 iter->second.handle = {};
1990                 iter->second.handle = createNewRng(rngm, renderUtil_, renderScene, renderCamera);
1991             }
1992             iter->second.lastFrameIndex = frameIndex_;
1993             iter->second.flags = renderCamera.flags;
1994             iter->second.renderPipelineType = renderCamera.renderPipelineType;
1995             iter->second.postProcessName = renderCamera.postProcessName;
1996             handle = iter->second.handle;
1997         } else {
1998             auto newRng = createNewRng(rngm, renderUtil_, renderScene, renderCamera);
1999             handle = newRng;
2000             renderProcessing_.camIdToRng[renderCamera.id] = { move(newRng), renderCamera.flags,
2001                 renderCamera.renderPipelineType, frameIndex_,
2002                 !(renderCamera.flags & RenderCamera::CAMERA_FLAG_COLOR_PRE_PASS_BIT), renderCamera.postProcessName };
2003         }
2004     }
2005     return handle;
2006 }
2007 
GetSceneRenderNodeGraph(const RenderScene & renderScene)2008 RenderHandleReference RenderSystem::GetSceneRenderNodeGraph(const RenderScene& renderScene)
2009 {
2010     RenderHandleReference handle = renderScene.customRenderNodeGraph;
2011     if (!handle) {
2012         handle = renderProcessing_.sceneRng;
2013     }
2014     if (!handle) {
2015         IRenderNodeGraphManager& rngm = renderContext_->GetRenderNodeGraphManager();
2016         auto createNewRng = [](auto& rngm, const auto& rnUtil, const auto& scene) {
2017             const RenderNodeGraphDesc desc = rnUtil->GetRenderNodeGraphDesc(scene, 0);
2018             return rngm.Create(
2019                 IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, desc, {}, scene.name);
2020         };
2021 
2022         renderProcessing_.sceneRng = createNewRng(rngm, renderUtil_, renderScene);
2023         handle = renderProcessing_.sceneRng;
2024     }
2025     return handle;
2026 }
2027 
GetRenderNodeGraphs() const2028 array_view<const RenderHandleReference> RenderSystem::GetRenderNodeGraphs() const
2029 {
2030     return renderProcessing_.orderedRenderNodeGraphs;
2031 }
2032 
UpdateAndGetPreviousFrameCameraData(const Entity & entity,const Math::Mat4X4 & view,const Math::Mat4X4 & proj)2033 RenderSystem::CameraData RenderSystem::UpdateAndGetPreviousFrameCameraData(
2034     const Entity& entity, const Math::Mat4X4& view, const Math::Mat4X4& proj)
2035 {
2036     CameraData currData = { view, proj, frameIndex_ };
2037     if (auto iter = cameraData_.find(entity); iter != cameraData_.end()) {
2038         const CameraData prevData = iter->second;
2039         iter->second = currData;
2040         return prevData; // correct previous frame matrices
2041     } else {
2042         cameraData_.insert_or_assign(entity, currData);
2043         return currData; // current frame returned because of no prev frame matrices
2044     }
2045 }
2046 
IRenderSystemInstance(IEcs & ecs)2047 ISystem* IRenderSystemInstance(IEcs& ecs)
2048 {
2049     return new RenderSystem(ecs);
2050 }
2051 
IRenderSystemDestroy(ISystem * instance)2052 void IRenderSystemDestroy(ISystem* instance)
2053 {
2054     delete static_cast<RenderSystem*>(instance);
2055 }
2056 CORE3D_END_NAMESPACE()
2057