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