• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "render_node_default_cameras.h"
17 
18 #include <3d/render/default_material_constants.h>
19 #include <3d/render/intf_render_data_store_default_camera.h>
20 #include <3d/render/intf_render_data_store_default_light.h>
21 #include <base/containers/allocator.h>
22 #include <base/math/matrix_util.h>
23 #include <base/math/quaternion_util.h>
24 #include <core/log.h>
25 #include <core/namespace.h>
26 #include <core/util/intf_frustum_util.h>
27 #include <render/datastore/intf_render_data_store.h>
28 #include <render/datastore/intf_render_data_store_manager.h>
29 #include <render/device/intf_gpu_resource_manager.h>
30 #include <render/nodecontext/intf_render_node_context_manager.h>
31 #include <render/nodecontext/intf_render_node_graph_share_manager.h>
32 
33 namespace {
34 #include "3d/shaders/common/3d_dm_structures_common.h"
35 } // namespace
36 
37 CORE3D_BEGIN_NAMESPACE()
38 using namespace BASE_NS;
39 using namespace CORE_NS;
40 using namespace RENDER_NS;
41 
42 namespace {
43 constexpr BASE_NS::Math::Mat4X4 ZERO_MATRIX_4X4 = {};
44 constexpr BASE_NS::Math::Mat4X4 SHADOW_BIAS_MATRIX = BASE_NS::Math::Mat4X4 { 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,
45     0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.0f, 1.0f };
GetShadowBias(const uint32_t shadowIndex,const uint32_t shadowCount)46 constexpr BASE_NS::Math::Mat4X4 GetShadowBias(const uint32_t shadowIndex, const uint32_t shadowCount)
47 {
48     const float theShadowCount = static_cast<float>(Math::max(1u, shadowCount));
49     const float invShadowCount = (1.0f / theShadowCount);
50     const float sc = 0.5f * invShadowCount;
51     const float so = invShadowCount * static_cast<float>(shadowIndex);
52     return BASE_NS::Math::Mat4X4 { sc, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, sc + so, 0.5f,
53         0.0f, 1.0f };
54 }
55 
56 constexpr float CUBE_MAP_LOD_COEFF { 8.0f };
57 // nine vectors which are used in spherical harmonics calculations
58 constexpr BASE_NS::Math::Vec4 DEFAULT_SH_INDIRECT_COEFFICIENTS[9u] {
59     { 1.0f, 1.0f, 1.0f, 1.0f },
60     { 0.0f, 0.0f, 0.0f, 0.0f },
61     { 0.0f, 0.0f, 0.0f, 0.0f },
62     { 0.0f, 0.0f, 0.0f, 0.0f },
63     { 0.0f, 0.0f, 0.0f, 0.0f },
64     { 0.0f, 0.0f, 0.0f, 0.0f },
65     { 0.0f, 0.0f, 0.0f, 0.0f },
66     { 0.0f, 0.0f, 0.0f, 0.0f },
67     { 0.0f, 0.0f, 0.0f, 0.0f },
68 };
69 
70 constexpr uint32_t CUBEMAP_EXTRA_CAMERA_COUNT { 5U };
71 constexpr uint32_t HALTON_SAMPLE_COUNT { 16u };
GetHaltonOffset(const uint32_t haltonIndex)72 Math::Vec2 GetHaltonOffset(const uint32_t haltonIndex)
73 {
74     // positive halton
75     constexpr const Math::Vec2 halton16[] = {
76         { 0.500000f, 0.333333f }, // 00
77         { 0.250000f, 0.666667f }, // 01
78         { 0.750000f, 0.111111f }, // 02
79         { 0.125000f, 0.444444f }, // 03
80         { 0.625000f, 0.777778f }, // 04
81         { 0.375000f, 0.222222f }, // 05
82         { 0.875000f, 0.555556f }, // 06
83         { 0.062500f, 0.888889f }, // 07
84         { 0.562500f, 0.037037f }, // 08
85         { 0.312500f, 0.370370f }, // 09
86         { 0.812500f, 0.703704f }, // 10
87         { 0.187500f, 0.148148f }, // 11
88         { 0.687500f, 0.481481f }, // 12
89         { 0.437500f, 0.814815f }, // 13
90         { 0.937500f, 0.259259f }, // 14
91         { 0.031250f, 0.592593f }, // 15
92     };
93     return halton16[haltonIndex];
94 }
95 
GenerateCubemapMatrices(vector<Math::Mat4X4> & matrices)96 void GenerateCubemapMatrices(vector<Math::Mat4X4>& matrices)
97 {
98     if (matrices.empty()) {
99         matrices.resize(CUBEMAP_EXTRA_CAMERA_COUNT);
100         // x-
101         matrices[0U] = Mat4Cast(Math::AngleAxis((Math::DEG2RAD * -90.0f), Math::Vec3(0.0f, 1.0f, 0.0f)));
102         matrices[0U] = Math::Scale(matrices[0U], { 1.f, 1.f, -1.f });
103         // +y
104         matrices[1U] = Mat4Cast(Math::AngleAxis((Math::DEG2RAD * -90.0f), Math::Vec3(1.0f, 0.0f, 0.0f)));
105         matrices[1U] = Math::Scale(matrices[1U], { 1.f, 1.f, -1.f });
106         // -y
107         matrices[2U] = Mat4Cast(Math::AngleAxis((Math::DEG2RAD * 90.0f), Math::Vec3(1.0f, 0.0f, 0.0f)));
108         matrices[2U] = Math::Scale(matrices[2U], { 1.f, 1.f, -1.f });
109         // +z
110         matrices[3U] = Mat4Cast(Math::AngleAxis((Math::DEG2RAD * 180.0f), Math::Vec3(0.0f, 1.0f, 0.0f)));
111         matrices[3U] = Math::Scale(matrices[3U], { -1.f, 1.f, 1.f });
112         // -z
113         matrices[4U] = Mat4Cast(Math::AngleAxis((Math::DEG2RAD * 0.0f), Math::Vec3(0.0f, 1.0f, 0.0f)));
114         matrices[4U] = Math::Scale(matrices[4U], { -1.f, 1.f, 1.f });
115     }
116 }
117 
GetPacked64(const uint64_t value)118 inline constexpr Math::UVec2 GetPacked64(const uint64_t value)
119 {
120     return { static_cast<uint32_t>(value >> 32) & 0xFFFFffff, static_cast<uint32_t>(value & 0xFFFFffff) };
121 }
122 
GetMultiViewCameraIndicesFunc(const IRenderDataStoreDefaultCamera * rds,const RenderCamera & cam)123 constexpr Math::UVec4 GetMultiViewCameraIndicesFunc(const IRenderDataStoreDefaultCamera* rds, const RenderCamera& cam)
124 {
125     Math::UVec4 mvIndices { 0U, 0U, 0U, 0U };
126     CORE_STATIC_ASSERT(RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT == 7U);
127     const uint32_t inputCount =
128         Math::min(cam.multiViewCameraCount, RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT);
129     for (uint32_t idx = 0U; idx < inputCount; ++idx) {
130         const uint64_t id = cam.multiViewCameraIds[idx];
131         if (id != RenderSceneDataConstants::INVALID_ID) {
132             mvIndices[0U]++; // recalculates the count
133             const uint32_t index = mvIndices[0U];
134             const uint32_t viewIndexShift =
135                 (index >= CORE_MULTI_VIEW_VIEW_INDEX_MODULO) ? CORE_MULTI_VIEW_VIEW_INDEX_SHIFT : 0U;
136             const uint32_t finalViewIndex = index % CORE_MULTI_VIEW_VIEW_INDEX_MODULO;
137             mvIndices[finalViewIndex] =
138                 (Math::min(rds->GetCameraIndex(id), CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT - 1U) &
139                     CORE_MULTI_VIEW_VIEW_INDEX_MASK)
140                 << viewIndexShift;
141         }
142     }
143     return mvIndices;
144 }
145 
GetCubemapMultiViewCameraIndicesFunc(const IRenderDataStoreDefaultCamera * rds,const RenderCamera & cam,const array_view<const uint32_t> cameraIndices)146 constexpr Math::UVec4 GetCubemapMultiViewCameraIndicesFunc(
147     const IRenderDataStoreDefaultCamera* rds, const RenderCamera& cam, const array_view<const uint32_t> cameraIndices)
148 {
149     Math::UVec4 mvIndices { 0U, 0U, 0U, 0U };
150     CORE_STATIC_ASSERT(RenderSceneDataConstants::MAX_MULTI_VIEW_LAYER_CAMERA_COUNT == 7U);
151     constexpr uint32_t inputCount = CUBEMAP_EXTRA_CAMERA_COUNT;
152     mvIndices[0U] = inputCount; // multi-view camera count
153     // NOTE: keeps compatibility with the old code
154     for (uint32_t idx = 0U; idx < inputCount; ++idx) {
155         const uint32_t writeIndex = idx + 1U;
156         const uint32_t viewIndexShift =
157             (writeIndex >= CORE_MULTI_VIEW_VIEW_INDEX_MODULO) ? CORE_MULTI_VIEW_VIEW_INDEX_SHIFT : 0U;
158         const uint32_t finalViewIndex = writeIndex % CORE_MULTI_VIEW_VIEW_INDEX_MODULO;
159         const uint32_t camId = cameraIndices[idx];
160         mvIndices[finalViewIndex] |=
161             (Math::min(camId, CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT - 1U) & CORE_MULTI_VIEW_VIEW_INDEX_MASK)
162             << viewIndexShift;
163     }
164     return mvIndices;
165 }
166 } // namespace
167 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)168 void RenderNodeDefaultCameras::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
169 {
170     renderNodeContextMgr_ = &renderNodeContextMgr;
171 
172     // Get IFrustumUtil from global plugin registry.
173     frustumUtil_ = GetInstance<IFrustumUtil>(UID_FRUSTUM_UTIL);
174 
175     const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
176     stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
177         renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
178 
179     CORE_STATIC_ASSERT((sizeof(DefaultCameraMatrixStruct) % CORE_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT) == 0);
180     auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
181     {
182         const string bufferName =
183             stores_.dataStoreNameScene.c_str() + DefaultMaterialCameraConstants::CAMERA_DATA_BUFFER_NAME;
184         camHandle_ = gpuResourceMgr.Create(
185             bufferName, { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
186                             (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
187                             CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER,
188                             sizeof(DefaultCameraMatrixStruct) * CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT });
189     }
190     {
191         const string bufferName =
192             stores_.dataStoreNameScene.c_str() + DefaultMaterialSceneConstants::SCENE_ENVIRONMENT_DATA_BUFFER_NAME;
193         envHandle_ = gpuResourceMgr.Create(
194             bufferName, { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
195                             (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
196                             CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER,
197                             sizeof(DefaultMaterialEnvironmentStruct) * CORE_DEFAULT_MATERIAL_MAX_ENVIRONMENT_COUNT });
198     }
199 
200     IRenderNodeGraphShareManager& rngShareMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
201     const RenderHandle outputs[2U] { camHandle_.GetHandle(), envHandle_.GetHandle() };
202     rngShareMgr.RegisterRenderNodeOutputs(outputs);
203 }
204 
PreExecuteFrame()205 void RenderNodeDefaultCameras::PreExecuteFrame()
206 {
207     IRenderNodeGraphShareManager& rngShareMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
208     const RenderHandle outputs[2U] { camHandle_.GetHandle(), envHandle_.GetHandle() };
209     rngShareMgr.RegisterRenderNodeOutputs(outputs);
210     // reset
211     cubemapCameras_.clear();
212 }
213 
ExecuteFrame(IRenderCommandList & cmdList)214 void RenderNodeDefaultCameras::ExecuteFrame(IRenderCommandList& cmdList)
215 {
216     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
217     const IRenderDataStoreDefaultCamera* dsCamera =
218         static_cast<IRenderDataStoreDefaultCamera*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameCamera));
219     const IRenderDataStoreDefaultLight* dsLight =
220         static_cast<IRenderDataStoreDefaultLight*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameLight));
221     if (!dsCamera) {
222         return;
223     }
224     const auto& cameras = dsCamera->GetCameras();
225     const auto& environments = dsCamera->GetEnvironments();
226     if (cameras.empty() && environments.empty()) {
227         return;
228     }
229     const auto& gpuResMgr = renderNodeContextMgr_->GetGpuResourceManager();
230     if (uint8_t* data = reinterpret_cast<uint8_t*>(gpuResMgr.MapBuffer(camHandle_.GetHandle())); data) {
231         const uint32_t originalCameraCount = static_cast<uint32_t>(cameras.size());
232         // add normal cameras to GPU
233         AddCameras(dsCamera, dsLight, cameras, data, 0U);
234         // add cubemap cameras to GPU
235         AddCameras(dsCamera, dsLight, cubemapCameras_, data, originalCameraCount);
236 
237         gpuResMgr.UnmapBuffer(camHandle_.GetHandle());
238     }
239     jitterIndex_ = (jitterIndex_ + 1) % HALTON_SAMPLE_COUNT;
240 
241     if (uint8_t* data = reinterpret_cast<uint8_t*>(gpuResMgr.MapBuffer(envHandle_.GetHandle())); data) {
242         AddEnvironments(dsCamera, environments, data);
243 
244         gpuResMgr.UnmapBuffer(envHandle_.GetHandle());
245     }
246 }
247 
AddCameras(const IRenderDataStoreDefaultCamera * dsCamera,const IRenderDataStoreDefaultLight * dsLight,const array_view<const RenderCamera> cameras,uint8_t * const data,const uint32_t cameraOffset)248 void RenderNodeDefaultCameras::AddCameras(const IRenderDataStoreDefaultCamera* dsCamera,
249     const IRenderDataStoreDefaultLight* dsLight, const array_view<const RenderCamera> cameras, uint8_t* const data,
250     const uint32_t cameraOffset)
251 {
252     const uint32_t cameraCount = static_cast<uint32_t>(
253         Math::max(0, Math::min(static_cast<int32_t>(CORE_DEFAULT_MATERIAL_MAX_CAMERA_COUNT - cameraOffset),
254             static_cast<int32_t>(cameras.size()))));
255     for (uint32_t idx = 0; idx < cameraCount; ++idx) {
256         const auto& currCamera = cameras[idx];
257         // take into account the offset to GPU cameras
258         auto dat = reinterpret_cast<DefaultCameraMatrixStruct* const>(
259             data + sizeof(DefaultCameraMatrixStruct) * (idx + cameraOffset));
260 
261         const auto view = ResolveViewMatrix(currCamera);
262         const JitterProjection jp = GetProjectionMatrix(currCamera, false);
263         const Math::Mat4X4 viewProj = jp.proj * view;
264         dat->view = view;
265         dat->proj = jp.proj;
266         dat->viewProj = viewProj;
267 
268         dat->viewInv = Math::Inverse(view);
269         dat->projInv = Math::Inverse(jp.proj);
270         dat->viewProjInv = Math::Inverse(viewProj);
271 
272         const JitterProjection jpPrevFrame = GetProjectionMatrix(currCamera, true);
273         const Math::Mat4X4 viewProjPrevFrame = jpPrevFrame.proj * currCamera.matrices.viewPrevFrame;
274         dat->viewPrevFrame = currCamera.matrices.viewPrevFrame;
275         dat->projPrevFrame = jpPrevFrame.proj;
276         dat->viewProjPrevFrame = viewProjPrevFrame;
277 
278         // possible shadow matrices
279         const Math::Mat4X4 shadowViewProj = GetShadowBiasMatrix(dsLight, currCamera) * viewProj;
280         dat->shadowViewProj = shadowViewProj;
281         dat->shadowViewProjInv = Math::Inverse(shadowViewProj);
282 
283         // jitter data
284         dat->jitter = jp.jitter;
285         dat->jitterPrevFrame = jpPrevFrame.jitter;
286 
287         const Math::UVec2 packedId = GetPacked64(currCamera.id);
288         const Math::UVec2 packedLayer = GetPacked64(currCamera.layerMask);
289         dat->indices = { packedId.x, packedId.y, packedLayer.x, packedLayer.y };
290         dat->multiViewIndices = GetMultiViewCameraIndices(dsCamera, currCamera, cameraCount);
291 
292         // frustum planes
293         if (frustumUtil_) {
294             // frustum planes created without jitter
295             const Frustum frustum = frustumUtil_->CreateFrustum(jp.baseProj * view);
296             CloneData(dat->frustumPlanes, CORE_DEFAULT_CAMERA_FRUSTUM_PLANE_COUNT * sizeof(Math::Vec4), frustum.planes,
297                 Frustum::PLANE_COUNT * sizeof(Math::Vec4));
298         }
299 
300         // padding
301         dat->counts = { currCamera.environment.multiEnvCount, 0U, 0U, 0U };
302         dat->pad0 = { 0U, 0U, 0U, 0U };
303         dat->matPad0 = ZERO_MATRIX_4X4;
304         dat->matPad1 = ZERO_MATRIX_4X4;
305     }
306 }
307 
GetMultiViewCameraIndices(const IRenderDataStoreDefaultCamera * rds,const RenderCamera & cam,const uint32_t cameraCount)308 BASE_NS::Math::UVec4 RenderNodeDefaultCameras::GetMultiViewCameraIndices(
309     const IRenderDataStoreDefaultCamera* rds, const RenderCamera& cam, const uint32_t cameraCount)
310 {
311     // first check if cubemap
312     if (cam.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_CUBEMAP_BIT) {
313         // generate new indices and add cameras
314         const size_t currSize = cubemapCameras_.size();
315         cubemapCameras_.resize(currSize + CUBEMAP_EXTRA_CAMERA_COUNT);
316         GenerateCubemapMatrices(cubemapMatrices_);
317 
318         const uint32_t startCameraIndex = cameraCount + static_cast<uint32_t>(currSize);
319         const uint32_t camIndices[CUBEMAP_EXTRA_CAMERA_COUNT] = {
320             startCameraIndex + 0U,
321             startCameraIndex + 1U,
322             startCameraIndex + 2U,
323             startCameraIndex + 3U,
324             startCameraIndex + 4U,
325         };
326         for (size_t idx = 0; idx < CUBEMAP_EXTRA_CAMERA_COUNT; ++idx) {
327             CORE_ASSERT(currSize + idx < cubemapCameras_.size());
328             CORE_ASSERT(idx < cubemapMatrices_.size());
329             auto& currCamera = cubemapCameras_[currSize + idx];
330             currCamera = cam;
331             currCamera.flags = 0U;
332             currCamera.matrices.view = cubemapMatrices_[idx] * currCamera.matrices.view;
333             currCamera.matrices.viewPrevFrame = currCamera.matrices.view;
334         }
335         return GetCubemapMultiViewCameraIndicesFunc(rds, cam, { camIndices, CUBEMAP_EXTRA_CAMERA_COUNT });
336     } else {
337         return GetMultiViewCameraIndicesFunc(rds, cam);
338     }
339 }
340 
ResolveViewMatrix(const RenderCamera & camera) const341 BASE_NS::Math::Mat4X4 RenderNodeDefaultCameras::ResolveViewMatrix(const RenderCamera& camera) const
342 {
343     auto view = camera.matrices.view;
344     if (camera.flags & RenderCamera::CAMERA_FLAG_CUBEMAP_BIT) {
345         Math::Mat4X4 temporary = Mat4Cast(Math::AngleAxis((Math::DEG2RAD * 90.0f), Math::Vec3(0.0f, 1.0f, 0.0f)));
346         temporary = Math::Scale(temporary, { 1.f, 1.f, -1.f });
347         view = temporary * view;
348     }
349     return view;
350 }
351 
GetProjectionMatrix(const RenderCamera & camera,const bool prevFrame) const352 RenderNodeDefaultCameras::JitterProjection RenderNodeDefaultCameras::GetProjectionMatrix(
353     const RenderCamera& camera, const bool prevFrame) const
354 {
355     JitterProjection jp;
356     jp.baseProj = prevFrame ? camera.matrices.projPrevFrame : camera.matrices.proj;
357     jp.proj = jp.baseProj;
358     if (camera.flags & RenderCamera::CameraFlagBits::CAMERA_FLAG_JITTER_BIT) {
359         // NOTE: currently calculates the same jitter for both frames to get zero velocity
360         const uint32_t jitterIndex = jitterIndex_;
361         const Math::Vec2 renderRes = Math::Vec2(static_cast<float>(Math::max(1u, camera.renderResolution.x)),
362             static_cast<float>(Math::max(1u, camera.renderResolution.y)));
363         const Math::Vec2 haltonOffset = GetHaltonOffset(jitterIndex);
364         const Math::Vec2 haltonOffsetRes =
365             Math::Vec2((haltonOffset.x * 2.0f - 1.0f) / renderRes.x, (haltonOffset.y * 2.0f - 1.0f) / renderRes.y);
366 
367         jp.jitter = Math::Vec4(haltonOffset.x, haltonOffset.y, haltonOffsetRes.x, haltonOffsetRes.y);
368         jp.proj[2U][0U] += haltonOffsetRes.x;
369         jp.proj[2U][1U] += haltonOffsetRes.y;
370     }
371     return jp;
372 }
373 
GetShadowBiasMatrix(const IRenderDataStoreDefaultLight * dataStore,const RenderCamera & camera) const374 BASE_NS::Math::Mat4X4 RenderNodeDefaultCameras::GetShadowBiasMatrix(
375     const IRenderDataStoreDefaultLight* dataStore, const RenderCamera& camera) const
376 {
377     if (dataStore) {
378         const auto lightCounts = dataStore->GetLightCounts();
379         const uint32_t shadowCount = lightCounts.shadowCount;
380         const auto lights = dataStore->GetLights();
381         for (const auto& lightRef : lights) {
382             if (lightRef.id == camera.shadowId) {
383                 return GetShadowBias(lightRef.shadowIndex, shadowCount);
384             }
385         }
386     }
387     return SHADOW_BIAS_MATRIX;
388 }
389 
390 namespace {
GetMultiEnvironmentIndices(const RenderCamera::Environment & env,const array_view<const RenderCamera::Environment> envs)391 Math::UVec4 GetMultiEnvironmentIndices(
392     const RenderCamera::Environment& env, const array_view<const RenderCamera::Environment> envs)
393 {
394     if (env.multiEnvCount > 0U) {
395         Math::UVec4 multiEnvIndices = { 0U, 0U, 0U, 0U };
396         // the first value in multiEnvIndices is the count
397         // first index is the main environment, next indices are the blend environments
398         const uint32_t maxEnvCount = Math::min(env.multiEnvCount, 3U);
399         for (uint32_t idx = 0U; idx < maxEnvCount; ++idx) {
400             multiEnvIndices[0U]++;
401             uint32_t multiEnvIdx = 0U;
402             for (uint32_t envIdx = 0U; envIdx < static_cast<uint32_t>(envs.size()); ++envIdx) {
403                 const auto& envRef = envs[envIdx];
404                 if (envRef.id == env.multiEnvIds[idx]) {
405                     multiEnvIdx = envIdx;
406                 }
407             }
408             CORE_ASSERT(idx + 1U <= 3U);
409             multiEnvIndices[idx + 1U] = multiEnvIdx;
410         }
411         return multiEnvIndices;
412     } else {
413         return { 0U, 0U, 0U, 0U };
414     }
415 }
416 } // namespace
417 
AddEnvironments(const IRenderDataStoreDefaultCamera * dsCamera,const array_view<const RenderCamera::Environment> environments,uint8_t * const data)418 void RenderNodeDefaultCameras::AddEnvironments(const IRenderDataStoreDefaultCamera* dsCamera,
419     const array_view<const RenderCamera::Environment> environments, uint8_t* const data)
420 {
421     CORE_ASSERT(data);
422     const auto* dataEnd = data + sizeof(DefaultMaterialEnvironmentStruct) * CORE_DEFAULT_MATERIAL_MAX_ENVIRONMENT_COUNT;
423 
424     const uint32_t envCount = static_cast<uint32_t>(
425         Math::min(CORE_DEFAULT_MATERIAL_MAX_ENVIRONMENT_COUNT, static_cast<uint32_t>(environments.size())));
426     for (uint32_t idx = 0; idx < envCount; ++idx) {
427         auto* dat = data + (sizeof(DefaultMaterialEnvironmentStruct) * idx);
428 
429         const auto& currEnv = environments[idx];
430         const Math::UVec4 multiEnvIndices = GetMultiEnvironmentIndices(currEnv, environments);
431         const Math::UVec2 id = GetPacked64(currEnv.id);
432         const Math::UVec2 layer = GetPacked64(currEnv.layerMask);
433         const float radianceCubemapLodCoeff =
434             (currEnv.radianceCubemapMipCount != 0)
435                 ? Math::min(CUBE_MAP_LOD_COEFF, static_cast<float>(currEnv.radianceCubemapMipCount))
436                 : CUBE_MAP_LOD_COEFF;
437         DefaultMaterialEnvironmentStruct envStruct {
438             Math::Vec4((Math::Vec3(currEnv.indirectSpecularFactor) * currEnv.indirectSpecularFactor.w),
439                 currEnv.indirectSpecularFactor.w),
440             Math::Vec4(Math::Vec3(currEnv.indirectDiffuseFactor) * currEnv.indirectDiffuseFactor.w,
441                 currEnv.indirectDiffuseFactor.w),
442             Math::Vec4(Math::Vec3(currEnv.envMapFactor) * currEnv.envMapFactor.w, currEnv.envMapFactor.w),
443             Math::Vec4(radianceCubemapLodCoeff, currEnv.envMapLodLevel, 0.0f, 0.0f),
444             currEnv.blendFactor,
445             Math::Mat4Cast(currEnv.rotation),
446             Math::UVec4(id.x, id.y, layer.x, layer.y),
447             {},
448             multiEnvIndices,
449         };
450         constexpr size_t countOfSh = countof(envStruct.shIndirectCoefficients);
451         if (currEnv.radianceCubemap || (currEnv.multiEnvCount > 0U)) {
452             for (size_t jdx = 0; jdx < countOfSh; ++jdx) {
453                 envStruct.shIndirectCoefficients[jdx] = currEnv.shIndirectCoefficients[jdx];
454             }
455         } else {
456             for (size_t jdx = 0; jdx < countOfSh; ++jdx) {
457                 envStruct.shIndirectCoefficients[jdx] = DEFAULT_SH_INDIRECT_COEFFICIENTS[jdx];
458             }
459         }
460 
461         if (!CloneData(dat, size_t(dataEnd - dat), &envStruct, sizeof(DefaultMaterialEnvironmentStruct))) {
462             CORE_LOG_E("environment ubo copying failed.");
463         }
464     }
465 }
466 
467 // for plugin / factory interface
Create()468 RENDER_NS::IRenderNode* RenderNodeDefaultCameras::Create()
469 {
470     return new RenderNodeDefaultCameras();
471 }
472 
Destroy(IRenderNode * instance)473 void RenderNodeDefaultCameras::Destroy(IRenderNode* instance)
474 {
475     delete static_cast<RenderNodeDefaultCameras*>(instance);
476 }
477 CORE3D_END_NAMESPACE()
478