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