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