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