Plasma Engine  2.0
Loading...
Searching...
No Matches
ClusteredDataUtils.h
1#pragma once
2
3#include <RendererCore/Decals/DecalComponent.h>
4#include <RendererCore/Lights/DirectionalLightComponent.h>
5#include <RendererCore/Lights/Implementation/ReflectionProbeData.h>
6#include <RendererCore/Lights/PointLightComponent.h>
7#include <RendererCore/Lights/SpotLightComponent.h>
8#include <RendererFoundation/Shader/ShaderUtils.h>
9
10#include <RendererCore/../../../Data/Base/Shaders/Common/LightData.h>
11PL_DEFINE_AS_POD_TYPE(plPerLightData);
12PL_DEFINE_AS_POD_TYPE(plPerDecalData);
13PL_DEFINE_AS_POD_TYPE(plPerReflectionProbeData);
14PL_DEFINE_AS_POD_TYPE(plPerClusterData);
15
16#include <Core/Graphics/Camera.h>
17#include <Foundation/Math/Float16.h>
18#include <Foundation/SimdMath/SimdConversion.h>
19#include <Foundation/SimdMath/SimdVec4i.h>
20#include <Foundation/Utilities/GraphicsUtils.h>
21
22namespace
23{
25 static float s_fMinLightDistance = 5.0f;
26 static float s_fMaxLightDistance = 500.0f;
27
28 static float s_fDepthSliceScale = (NUM_CLUSTERS_Z - 1) / (plMath::Log2(s_fMaxLightDistance) - plMath::Log2(s_fMinLightDistance));
29 static float s_fDepthSliceBias = -s_fDepthSliceScale * plMath::Log2(s_fMinLightDistance) + 1.0f;
30
31 PL_ALWAYS_INLINE float GetDepthFromSliceIndex(plUInt32 uiSliceIndex)
32 {
33 return plMath::Pow(2.0f, (uiSliceIndex - s_fDepthSliceBias + 1.0f) / s_fDepthSliceScale);
34 }
35
36 PL_ALWAYS_INLINE plUInt32 GetSliceIndexFromDepth(float fLinearDepth)
37 {
38 return plMath::Clamp((plInt32)(plMath::Log2(fLinearDepth) * s_fDepthSliceScale + s_fDepthSliceBias), 0, NUM_CLUSTERS_Z - 1);
39 }
40
41 PL_ALWAYS_INLINE plUInt32 GetClusterIndexFromCoord(plUInt32 x, plUInt32 y, plUInt32 z)
42 {
43 return z * NUM_CLUSTERS_XY + y * NUM_CLUSTERS_X + x;
44 }
45
46 // in order: tlf, trf, blf, brf, tln, trn, bln, brn
47 PL_FORCE_INLINE void GetClusterCornerPoints(
48 const plCamera& camera, float fZf, float fZn, float fTanLeft, float fTanRight, float fTanBottom, float fTanTop, plInt32 x, plInt32 y, plInt32 z, plVec3* out_pCorners)
49 {
50 const plVec3& pos = camera.GetPosition();
51 const plVec3& dirForward = camera.GetDirForwards();
52 const plVec3& dirRight = camera.GetDirRight();
53 const plVec3& dirUp = camera.GetDirUp();
54
55 const float fStartXf = fZf * fTanLeft;
56 const float fStartYf = fZf * fTanBottom;
57 const float fEndXf = fZf * fTanRight;
58 const float fEndYf = fZf * fTanTop;
59
60 float fStepXf = (fEndXf - fStartXf) / NUM_CLUSTERS_X;
61 float fStepYf = (fEndYf - fStartYf) / NUM_CLUSTERS_Y;
62
63 float fXf = fStartXf + x * fStepXf;
64 float fYf = fStartYf + y * fStepYf;
65
66 out_pCorners[0] = pos + dirForward * fZf + dirRight * fXf - dirUp * fYf;
67 out_pCorners[1] = out_pCorners[0] + dirRight * fStepXf;
68 out_pCorners[2] = out_pCorners[0] - dirUp * fStepYf;
69 out_pCorners[3] = out_pCorners[2] + dirRight * fStepXf;
70
71 const float fStartXn = fZn * fTanLeft;
72 const float fStartYn = fZn * fTanBottom;
73 const float fEndXn = fZn * fTanRight;
74 const float fEndYn = fZn * fTanTop;
75
76 float fStepXn = (fEndXn - fStartXn) / NUM_CLUSTERS_X;
77 float fStepYn = (fEndYn - fStartYn) / NUM_CLUSTERS_Y;
78 float fXn = fStartXn + x * fStepXn;
79 float fYn = fStartYn + y * fStepYn;
80
81 out_pCorners[4] = pos + dirForward * fZn + dirRight * fXn - dirUp * fYn;
82 out_pCorners[5] = out_pCorners[4] + dirRight * fStepXn;
83 out_pCorners[6] = out_pCorners[4] - dirUp * fStepYn;
84 out_pCorners[7] = out_pCorners[6] + dirRight * fStepXn;
85 }
86
87 void FillClusterBoundingSpheres(const plCamera& camera, float fAspectRatio, plArrayPtr<plSimdBSphere> clusterBoundingSpheres)
88 {
89 PL_PROFILE_SCOPE("FillClusterBoundingSpheres");
90
92 if (camera.IsOrthographic())
93 return;
94
95 plMat4 mProj;
96 camera.GetProjectionMatrix(fAspectRatio, mProj);
97
98 plSimdVec4f stepScale;
99 plSimdVec4f tanLBLB;
100 {
101 plAngle fFovLeft;
102 plAngle fFovRight;
103 plAngle fFovBottom;
104 plAngle fFovTop;
105 plGraphicsUtils::ExtractPerspectiveMatrixFieldOfView(mProj, fFovLeft, fFovRight, fFovBottom, fFovTop);
106
107 const float fTanLeft = plMath::Tan(fFovLeft);
108 const float fTanRight = plMath::Tan(fFovRight);
109 const float fTanBottom = plMath::Tan(fFovBottom);
110 const float fTanTop = plMath::Tan(fFovTop);
111
112 float fStepXf = (fTanRight - fTanLeft) / NUM_CLUSTERS_X;
113 float fStepYf = (fTanTop - fTanBottom) / NUM_CLUSTERS_Y;
114
115 stepScale = plSimdVec4f(fStepXf, fStepYf, fStepXf, fStepYf);
116 tanLBLB = plSimdVec4f(fTanLeft, fTanBottom, fTanLeft, fTanBottom);
117 }
118
119 plSimdVec4f pos = plSimdConversion::ToVec3(camera.GetPosition());
120 plSimdVec4f dirForward = plSimdConversion::ToVec3(camera.GetDirForwards());
121 plSimdVec4f dirRight = plSimdConversion::ToVec3(camera.GetDirRight());
122 plSimdVec4f dirUp = plSimdConversion::ToVec3(camera.GetDirUp());
123
124
126 plSimdVec4f cc[8];
127
128 for (plInt32 z = 0; z < NUM_CLUSTERS_Z; z++)
129 {
130 plSimdVec4f fZf = plSimdVec4f(GetDepthFromSliceIndex(z));
131 plSimdVec4f zff_znn = fZf.GetCombined<plSwizzle::XXXX>(fZn);
132 plSimdVec4f steps = zff_znn.CompMul(stepScale);
133
134 plSimdVec4f depthF = pos + dirForward * fZf.x();
135 plSimdVec4f depthN = pos + dirForward * fZn.x();
136
137 plSimdVec4f startLBLB = zff_znn.CompMul(tanLBLB);
138
139 for (plInt32 y = 0; y < NUM_CLUSTERS_Y; y++)
140 {
141 for (plInt32 x = 0; x < NUM_CLUSTERS_X; x++)
142 {
143 plSimdVec4f xyxy = plSimdVec4i(x, y, x, y).ToFloat();
144 plSimdVec4f xfyf = startLBLB + (xyxy).CompMul(steps);
145
146 cc[0] = depthF + dirRight * xfyf.x() - dirUp * xfyf.y();
147 cc[1] = cc[0] + dirRight * steps.x();
148 cc[2] = cc[0] - dirUp * steps.y();
149 cc[3] = cc[2] + dirRight * steps.x();
150
151 cc[4] = depthN + dirRight * xfyf.z() - dirUp * xfyf.w();
152 cc[5] = cc[4] + dirRight * steps.z();
153 cc[6] = cc[4] - dirUp * steps.w();
154 cc[7] = cc[6] + dirRight * steps.z();
155
156 clusterBoundingSpheres[GetClusterIndexFromCoord(x, y, z)] = plSimdBSphere::MakeFromPoints(cc, 8);
157 }
158 }
159
160 fZn = fZf;
161 }
162 }
163
164 PL_ALWAYS_INLINE void FillLightData(plPerLightData& ref_perLightData, const plLightRenderData* pLightRenderData, plUInt8 uiType)
165 {
166 plMemoryUtils::ZeroFill(&ref_perLightData, 1);
167
168 plColorLinearUB lightColor = pLightRenderData->m_LightColor;
169 lightColor.a = uiType;
170
171 ref_perLightData.colorAndType = *reinterpret_cast<plUInt32*>(&lightColor.r);
172 ref_perLightData.intensity = pLightRenderData->m_fIntensity;
173 ref_perLightData.specularMultiplier = pLightRenderData->m_fSpecularMultiplier;
174 ref_perLightData.width = pLightRenderData->m_fWidth;
175 ref_perLightData.length = pLightRenderData->m_fLength;
176 ref_perLightData.shadowDataOffset = pLightRenderData->m_uiShadowDataOffset;
177 ref_perLightData.upDirection = plShaderUtils::Float3ToRGB10(pLightRenderData->m_GlobalTransform.m_qRotation * plVec3(0, 0, 1));
178 }
179
180 void FillPointLightData(plPerLightData& ref_perLightData, const plPointLightRenderData* pPointLightRenderData)
181 {
182 FillLightData(ref_perLightData, pPointLightRenderData, LIGHT_TYPE_POINT);
183
184 ref_perLightData.position = pPointLightRenderData->m_GlobalTransform.m_vPosition;
185 ref_perLightData.invSqrAttRadius = 1.0f / (pPointLightRenderData->m_fRange * pPointLightRenderData->m_fRange);
186 ref_perLightData.falloff = pPointLightRenderData->m_fFalloff;
187 }
188
189 void FillSpotLightData(plPerLightData& ref_perLightData, const plSpotLightRenderData* pSpotLightRenderData)
190 {
191 FillLightData(ref_perLightData, pSpotLightRenderData, LIGHT_TYPE_SPOT);
192
193 ref_perLightData.direction = plShaderUtils::Float3ToRGB10(pSpotLightRenderData->m_GlobalTransform.m_qRotation * plVec3(-1, 0, 0));
194 ref_perLightData.position = pSpotLightRenderData->m_GlobalTransform.m_vPosition;
195 ref_perLightData.invSqrAttRadius = 1.0f / (pSpotLightRenderData->m_fRange * pSpotLightRenderData->m_fRange);
196 ref_perLightData.falloff = pSpotLightRenderData->m_fFalloff;
197
198 const float fCosInner = plMath::Cos(pSpotLightRenderData->m_InnerSpotAngle * 0.5f);
199 const float fCosOuter = plMath::Cos(pSpotLightRenderData->m_OuterSpotAngle * 0.5f);
200 const float fSpotParamScale = 1.0f / plMath::Max(0.001f, (fCosInner - fCosOuter));
201 const float fSpotParamOffset = -fCosOuter * fSpotParamScale;
202 ref_perLightData.spotParams = plShaderUtils::Float2ToRG16F(plVec2(fSpotParamScale, fSpotParamOffset));
203 }
204
205 void FillDirLightData(plPerLightData& ref_perLightData, const plDirectionalLightRenderData* pDirLightRenderData)
206 {
207 FillLightData(ref_perLightData, pDirLightRenderData, LIGHT_TYPE_DIR);
208
209 ref_perLightData.direction = plShaderUtils::Float3ToRGB10(pDirLightRenderData->m_GlobalTransform.m_qRotation * plVec3(-1, 0, 0));
210 }
211
212 void FillDecalData(plPerDecalData& ref_perDecalData, const plDecalRenderData* pDecalRenderData)
213 {
214 plVec3 position = pDecalRenderData->m_GlobalTransform.m_vPosition;
215 plVec3 dirForwards = pDecalRenderData->m_GlobalTransform.m_qRotation * plVec3(1.0f, 0.0, 0.0f);
216 plVec3 dirUp = pDecalRenderData->m_GlobalTransform.m_qRotation * plVec3(0.0f, 0.0, 1.0f);
217 plVec3 scale = pDecalRenderData->m_GlobalTransform.m_vScale;
218
219 // the CompMax prevents division by zero (thus inf, thus NaN later, then crash)
220 // if negative scaling should be allowed, this would need to be changed
221 scale = plVec3(1.0f).CompDiv(scale.CompMax(plVec3(0.00001f)));
222
223 const plMat4 lookAt = plGraphicsUtils::CreateLookAtViewMatrix(position, position + dirForwards, dirUp);
224 plMat4 scaleMat = plMat4::MakeScaling(plVec3(scale.y, -scale.z, scale.x));
225
226 ref_perDecalData.worldToDecalMatrix = scaleMat * lookAt;
227 ref_perDecalData.applyOnlyToId = pDecalRenderData->m_uiApplyOnlyToId;
228 ref_perDecalData.decalFlags = pDecalRenderData->m_uiFlags;
229 ref_perDecalData.angleFadeParams = pDecalRenderData->m_uiAngleFadeParams;
230 ref_perDecalData.baseColor = *reinterpret_cast<const plUInt32*>(&pDecalRenderData->m_BaseColor.r);
231 ref_perDecalData.emissiveColorRG = plShaderUtils::PackFloat16intoUint(pDecalRenderData->m_EmissiveColor.r, pDecalRenderData->m_EmissiveColor.g);
232 ref_perDecalData.emissiveColorBA = plShaderUtils::PackFloat16intoUint(pDecalRenderData->m_EmissiveColor.b, pDecalRenderData->m_EmissiveColor.a);
233 ref_perDecalData.baseColorAtlasScale = pDecalRenderData->m_uiBaseColorAtlasScale;
234 ref_perDecalData.baseColorAtlasOffset = pDecalRenderData->m_uiBaseColorAtlasOffset;
235 ref_perDecalData.normalAtlasScale = pDecalRenderData->m_uiNormalAtlasScale;
236 ref_perDecalData.normalAtlasOffset = pDecalRenderData->m_uiNormalAtlasOffset;
237 ref_perDecalData.ormAtlasScale = pDecalRenderData->m_uiORMAtlasScale;
238 ref_perDecalData.ormAtlasOffset = pDecalRenderData->m_uiORMAtlasOffset;
239 }
240
241 void FillReflectionProbeData(plPerReflectionProbeData& ref_perReflectionProbeData, const plReflectionProbeRenderData* pReflectionProbeRenderData)
242 {
243 plVec3 position = pReflectionProbeRenderData->m_GlobalTransform.m_vPosition;
244 plVec3 scale = pReflectionProbeRenderData->m_GlobalTransform.m_vScale.CompMul(pReflectionProbeRenderData->m_vHalfExtents);
245
246 // We store scale separately so we easily transform into probe projection space (with scale), influence space (scale + offset) and cube map space (no scale).
247 auto trans = pReflectionProbeRenderData->m_GlobalTransform;
248 trans.m_vScale = plVec3(1.0f, 1.0f, 1.0f);
249 auto inverse = trans.GetAsMat4().GetInverse();
250
251 // the CompMax prevents division by zero (thus inf, thus NaN later, then crash)
252 // if negative scaling should be allowed, this would need to be changed
253 scale = plVec3(1.0f).CompDiv(scale.CompMax(plVec3(0.00001f)));
254 ref_perReflectionProbeData.WorldToProbeProjectionMatrix = inverse;
255
256 ref_perReflectionProbeData.ProbePosition = pReflectionProbeRenderData->m_vProbePosition.GetAsVec4(1.0f); // W isn't used.
257 ref_perReflectionProbeData.Scale = scale.GetAsVec4(0.0f); // W isn't used.
258
259 ref_perReflectionProbeData.InfluenceScale = pReflectionProbeRenderData->m_vInfluenceScale.GetAsVec4(0.0f);
260 ref_perReflectionProbeData.InfluenceShift = pReflectionProbeRenderData->m_vInfluenceShift.CompMul(plVec3(1.0f) - pReflectionProbeRenderData->m_vInfluenceScale).GetAsVec4(0.0f);
261
262 ref_perReflectionProbeData.PositiveFalloff = pReflectionProbeRenderData->m_vPositiveFalloff.GetAsVec4(0.0f);
263 ref_perReflectionProbeData.NegativeFalloff = pReflectionProbeRenderData->m_vNegativeFalloff.GetAsVec4(0.0f);
264 ref_perReflectionProbeData.Index = pReflectionProbeRenderData->m_uiIndex;
265 }
266
267
268 PL_FORCE_INLINE plSimdBBox GetScreenSpaceBounds(const plSimdBSphere& sphere, const plSimdMat4f& mViewMatrix, const plSimdMat4f& mProjectionMatrix)
269 {
270 plSimdVec4f viewSpaceCenter = mViewMatrix.TransformPosition(sphere.GetCenter());
271 plSimdFloat depth = viewSpaceCenter.z();
272 plSimdFloat radius = sphere.GetRadius();
273
274 plSimdVec4f mi;
275 plSimdVec4f ma;
276
277 if (viewSpaceCenter.GetLength<3>() > radius && depth > radius)
278 {
279 plSimdVec4f one = plSimdVec4f(1.0f);
280 plSimdVec4f oneNegOne = plSimdVec4f(1.0f, -1.0f, 1.0f, -1.0f);
281
282 plSimdVec4f pRadius = plSimdVec4f(radius / depth);
283 plSimdVec4f pRadius2 = pRadius.CompMul(pRadius);
284
285 plSimdVec4f xy = viewSpaceCenter / depth;
286 plSimdVec4f xxyy = xy.Get<plSwizzle::XXYY>();
287 plSimdVec4f nom = (pRadius2.CompMul(xxyy.CompMul(xxyy) - pRadius2 + one)).GetSqrt() - xxyy.CompMul(oneNegOne);
288 plSimdVec4f denom = pRadius2 - one;
289
290 plSimdVec4f projection = mProjectionMatrix.m_col0.GetCombined<plSwizzle::XXYY>(mProjectionMatrix.m_col1);
291 plSimdVec4f minXmaxX_minYmaxY = nom.CompDiv(denom).CompMul(oneNegOne).CompMul(projection);
292
293 mi = minXmaxX_minYmaxY.Get<plSwizzle::XZXX>();
294 ma = minXmaxX_minYmaxY.Get<plSwizzle::YWYY>();
295 }
296 else
297 {
298 mi = plSimdVec4f(-1.0f);
299 ma = plSimdVec4f(1.0f);
300 }
301
302 mi.SetZ(depth - radius);
303 ma.SetZ(depth + radius);
304
305 return plSimdBBox(mi, ma);
306 }
307
308 template <typename Cluster, typename IntersectionFunc>
309 PL_FORCE_INLINE void FillCluster(const plSimdBBox& screenSpaceBounds, plUInt32 uiBlockIndex, plUInt32 uiMask, Cluster* pClusters, IntersectionFunc func)
310 {
311 plSimdVec4f scale = plSimdVec4f(0.5f * NUM_CLUSTERS_X, -0.5f * NUM_CLUSTERS_Y, 1.0f, 1.0f);
312 plSimdVec4f bias = plSimdVec4f(0.5f * NUM_CLUSTERS_X, 0.5f * NUM_CLUSTERS_Y, 0.0f, 0.0f);
313
314 plSimdVec4f mi = plSimdVec4f::MulAdd(screenSpaceBounds.m_Min, scale, bias);
315 plSimdVec4f ma = plSimdVec4f::MulAdd(screenSpaceBounds.m_Max, scale, bias);
316
317 plSimdVec4i minXY_maxXY = plSimdVec4i::Truncate(mi.GetCombined<plSwizzle::XYXY>(ma));
318
319 plSimdVec4i maxClusterIndex = plSimdVec4i(NUM_CLUSTERS_X, NUM_CLUSTERS_Y, NUM_CLUSTERS_X, NUM_CLUSTERS_Y);
320 minXY_maxXY = minXY_maxXY.CompMin(maxClusterIndex - plSimdVec4i(1));
321 minXY_maxXY = minXY_maxXY.CompMax(plSimdVec4i::MakeZero());
322
323 plUInt32 xMin = minXY_maxXY.x();
324 plUInt32 yMin = minXY_maxXY.w();
325
326 plUInt32 xMax = minXY_maxXY.z();
327 plUInt32 yMax = minXY_maxXY.y();
328
329 plUInt32 zMin = GetSliceIndexFromDepth(screenSpaceBounds.m_Min.z());
330 plUInt32 zMax = GetSliceIndexFromDepth(screenSpaceBounds.m_Max.z());
331
332 for (plUInt32 z = zMin; z <= zMax; ++z)
333 {
334 for (plUInt32 y = yMin; y <= yMax; ++y)
335 {
336 for (plUInt32 x = xMin; x <= xMax; ++x)
337 {
338 plUInt32 uiClusterIndex = GetClusterIndexFromCoord(x, y, z);
339 if (func(uiClusterIndex))
340 {
341 pClusters[uiClusterIndex].m_BitMask[uiBlockIndex] |= uiMask;
342 }
343 }
344 }
345 }
346 }
347
348 template <typename Cluster>
349 void RasterizeSphere(const plSimdBSphere& pointLightSphere, plUInt32 uiLightIndex, const plSimdMat4f& mViewMatrix,
350 const plSimdMat4f& mProjectionMatrix, Cluster* pClusters, plSimdBSphere* pClusterBoundingSpheres)
351 {
352 plSimdBBox screenSpaceBounds = GetScreenSpaceBounds(pointLightSphere, mViewMatrix, mProjectionMatrix);
353
354 const plUInt32 uiBlockIndex = uiLightIndex / 32;
355 const plUInt32 uiMask = 1 << (uiLightIndex - uiBlockIndex * 32);
356
357 FillCluster(screenSpaceBounds, uiBlockIndex, uiMask, pClusters,
358 [&](plUInt32 uiClusterIndex) { return pointLightSphere.Overlaps(pClusterBoundingSpheres[uiClusterIndex]); });
359 }
360
361 struct BoundingCone
362 {
363 plSimdBSphere m_BoundingSphere;
364 plSimdVec4f m_PositionAndRange;
365 plSimdVec4f m_ForwardDir;
366 plSimdVec4f m_SinCosAngle;
367 };
368
369 template <typename Cluster>
370 void RasterizeSpotLight(const BoundingCone& spotLightCone, plUInt32 uiLightIndex, const plSimdMat4f& mViewMatrix,
371 const plSimdMat4f& mProjectionMatrix, Cluster* pClusters, plSimdBSphere* pClusterBoundingSpheres)
372 {
373 plSimdVec4f position = spotLightCone.m_PositionAndRange;
374 plSimdFloat range = spotLightCone.m_PositionAndRange.w();
375 plSimdVec4f forwardDir = spotLightCone.m_ForwardDir;
376 plSimdFloat sinAngle = spotLightCone.m_SinCosAngle.x();
377 plSimdFloat cosAngle = spotLightCone.m_SinCosAngle.y();
378
379 // First calculate a bounding sphere around the cone to get min and max bounds
380 plSimdVec4f bSphereCenter;
381 plSimdFloat bSphereRadius;
382 if (sinAngle > 0.707107f) // sin(45)
383 {
384 bSphereCenter = position + forwardDir * cosAngle * range;
385 bSphereRadius = sinAngle * range;
386 }
387 else
388 {
389 bSphereRadius = range / (cosAngle + cosAngle);
390 bSphereCenter = position + forwardDir * bSphereRadius;
391 }
392
393 plSimdBSphere spotLightSphere(bSphereCenter, bSphereRadius);
394 plSimdBBox screenSpaceBounds = GetScreenSpaceBounds(spotLightSphere, mViewMatrix, mProjectionMatrix);
395
396 const plUInt32 uiBlockIndex = uiLightIndex / 32;
397 const plUInt32 uiMask = 1 << (uiLightIndex - uiBlockIndex * 32);
398
399 FillCluster(screenSpaceBounds, uiBlockIndex, uiMask, pClusters, [&](plUInt32 uiClusterIndex) {
400 plSimdBSphere clusterSphere = pClusterBoundingSpheres[uiClusterIndex];
401 plSimdFloat clusterRadius = clusterSphere.GetRadius();
402
403 plSimdVec4f toConePos = clusterSphere.m_CenterAndRadius - position;
404 plSimdFloat projected = forwardDir.Dot<3>(toConePos);
405 plSimdFloat distToConeSq = toConePos.Dot<3>(toConePos);
406 plSimdFloat distClosestP = cosAngle * (distToConeSq - projected * projected).GetSqrt() - projected * sinAngle;
407
408 bool angleCull = distClosestP > clusterRadius;
409 bool frontCull = projected > clusterRadius + range;
410 bool backCull = projected < -clusterRadius;
411
412 return !(angleCull || frontCull || backCull); });
413 }
414
415 template <typename Cluster>
416 void RasterizeDirLight(const plDirectionalLightRenderData* pDirLightRenderData, plUInt32 uiLightIndex, plArrayPtr<Cluster> clusters)
417 {
418 const plUInt32 uiBlockIndex = uiLightIndex / 32;
419 const plUInt32 uiMask = 1 << (uiLightIndex - uiBlockIndex * 32);
420
421 for (plUInt32 i = 0; i < clusters.GetCount(); ++i)
422 {
423 clusters[i].m_BitMask[uiBlockIndex] |= uiMask;
424 }
425 }
426
427 template <typename Cluster>
428 void RasterizeBox(const plTransform& transform, plUInt32 uiDecalIndex, const plSimdMat4f& mViewProjectionMatrix, Cluster* pClusters,
429 plSimdBSphere* pClusterBoundingSpheres)
430 {
431 plSimdMat4f decalToWorld = plSimdConversion::ToTransform(transform).GetAsMat4();
432 plSimdMat4f worldToDecal = decalToWorld.GetInverse();
433
434 plVec3 corners[8];
436
437 plSimdMat4f decalToScreen = mViewProjectionMatrix * decalToWorld;
438 plSimdBBox screenSpaceBounds = plSimdBBox::MakeInvalid();
439 bool bInsideBox = false;
440 for (plUInt32 i = 0; i < 8; ++i)
441 {
442 plSimdVec4f corner = plSimdConversion::ToVec3(corners[i]);
443 plSimdVec4f screenSpaceCorner = decalToScreen.TransformPosition(corner);
444 plSimdFloat depth = screenSpaceCorner.w();
445 bInsideBox |= depth < plSimdFloat::MakeZero();
446
447 screenSpaceCorner /= depth;
448 screenSpaceCorner = screenSpaceCorner.GetCombined<plSwizzle::XYZW>(plSimdVec4f(depth));
449
450 screenSpaceBounds.m_Min = screenSpaceBounds.m_Min.CompMin(screenSpaceCorner);
451 screenSpaceBounds.m_Max = screenSpaceBounds.m_Max.CompMax(screenSpaceCorner);
452 }
453
454 if (bInsideBox)
455 {
456 screenSpaceBounds.m_Min = plSimdVec4f(-1.0f).GetCombined<plSwizzle::XYZW>(screenSpaceBounds.m_Min);
457 screenSpaceBounds.m_Max = plSimdVec4f(1.0f).GetCombined<plSwizzle::XYZW>(screenSpaceBounds.m_Max);
458 }
459
460 plSimdVec4f decalHalfExtents = plSimdVec4f(1.0f);
461 plSimdBBox localDecalBounds = plSimdBBox(-decalHalfExtents, decalHalfExtents);
462
463 const plUInt32 uiBlockIndex = uiDecalIndex / 32;
464 const plUInt32 uiMask = 1 << (uiDecalIndex - uiBlockIndex * 32);
465
466 FillCluster(screenSpaceBounds, uiBlockIndex, uiMask, pClusters, [&](plUInt32 uiClusterIndex) {
467 plSimdBSphere clusterSphere = pClusterBoundingSpheres[uiClusterIndex];
468 clusterSphere.Transform(worldToDecal);
469
470 return localDecalBounds.Overlaps(clusterSphere); });
471 }
472} // namespace
Float wrapper struct for a safe usage and conversions of angles.
Definition Angle.h:10
This class encapsulates an array and it's size. It is recommended to use this class instead of plain ...
Definition ArrayPtr.h:37
PL_ALWAYS_INLINE plUInt32 GetCount() const
Returns the number of elements in the array.
Definition ArrayPtr.h:142
void GetCorners(plVec3Template< Type > *out_pCorners) const
Writes the 8 different corners of the box to the given array.
Definition BoundingBox_inl.h:62
static plBoundingBoxTemplate< float > MakeFromMinMax(const plVec3Template< float > &vMin, const plVec3Template< float > &vMax)
Definition BoundingBox_inl.h:42
A camera class that stores the orientation and some basic camera settings.
Definition Camera.h:41
plVec3 GetPosition(plCameraEye eye=plCameraEye::Left) const
Returns the position of the camera that should be used for rendering etc.
Definition Camera.cpp:63
void GetProjectionMatrix(float fAspectRatioWidthDivHeight, plMat4 &out_mProjectionMatrix, plCameraEye eye=plCameraEye::Left, plClipSpaceDepthRange::Enum depthRange=plClipSpaceDepthRange::Default) const
Calculates the projection matrix from the current camera properties and stores it in out_projectionMa...
Definition Camera.cpp:280
plVec3 GetDirForwards(plCameraEye eye=plCameraEye::Left) const
Returns the forwards vector that should be used for rendering etc.
Definition Camera.cpp:68
plVec3 GetDirRight(plCameraEye eye=plCameraEye::Left) const
Returns the right vector that should be used for rendering etc.
Definition Camera.cpp:84
plVec3 GetDirUp(plCameraEye eye=plCameraEye::Left) const
Returns the up vector that should be used for rendering etc.
Definition Camera.cpp:76
A 8bit per channel unsigned normalized (values interpreted as 0-1) color storage format that represen...
Definition Color8UNorm.h:61
Definition DecalComponent.h:27
The render data object for directional lights.
Definition DirectionalLightComponent.h:10
Base class for light render data objects.
Definition LightComponent.h:10
static plMat4Template< float > MakeScaling(const plVec3Template< float > &vScale)
Definition Mat4_inl.h:158
static void ZeroFill(T *pDestination, size_t uiCount=1)
Zeros every byte in the provided memory buffer.
The render data object for point lights.
Definition PointLightComponent.h:11
Render data for a reflection probe.
Definition ReflectionProbeData.h:54
plVec3 m_vProbePosition
Probe position in world space.
Definition ReflectionProbeData.h:66
Definition SimdBBox.h:6
bool Overlaps(const plSimdBBox &rhs) const
Checks whether this box overlaps with the given box.
Definition SimdBBox_inl.h:133
static plSimdBBox MakeInvalid()
Creates a box that is in an invalid state. ExpandToInclude can then be used to make it into a boundin...
Definition SimdBBox_inl.h:16
Definition SimdBSphere.h:6
plSimdFloat GetRadius() const
Returns the radius.
Definition SimdBSphere_inl.h:85
static plSimdBSphere MakeFromPoints(const plSimdVec4f *pPoints, plUInt32 uiNumPoints, plUInt32 uiStride=sizeof(plSimdVec4f))
Creates a bounding sphere around the provided points.
Definition SimdBSphere_inl.h:30
void Transform(const plSimdTransform &t)
Transforms the sphere in its local space.
Definition SimdBSphere_inl.h:129
bool Overlaps(const plSimdBSphere &rhs) const
Checks whether the two objects overlap.
Definition SimdBSphere_inl.h:171
plSimdVec4f GetCenter() const
Returns the center.
Definition SimdBSphere_inl.h:80
Definition SimdFloat.h:7
static plSimdFloat MakeZero()
Creates an plSimdFloat that is initialized to zero.
Definition FPUFloat_inl.h:36
A 4x4 matrix class.
Definition SimdMat4f.h:7
plSimdMat4f GetInverse(const plSimdFloat &fEpsilon=plMath::SmallEpsilon< float >()) const
Returns the inverse of this matrix.
Definition SimdMat4f_inl.h:89
plSimdVec4f TransformPosition(const plSimdVec4f &v) const
Matrix-vector multiplication, assuming the 4th component of the vector is one (default behavior).
Definition SimdMat4f_inl.h:141
A 4-component SIMD vector class.
Definition SimdVec4f.h:8
static plSimdVec4f MakeZero()
Creates an plSimdVec4f that is initialized to zero.
Definition SimdVec4f_inl.h:8
plSimdVec4f GetCombined(const plSimdVec4f &other) const
x = this[s0], y = this[s1], z = other[s2], w = other[s3]
A SIMD 4-component vector class of signed 32b integers.
Definition SimdVec4i.h:9
static plSimdVec4i MakeZero()
Creates an plSimdVec4i that is initialized to zero.
Definition FPUVec4i_inl.h:25
The render data object for spot lights.
Definition SpotLightComponent.h:11
const plMat4Template< Type > GetAsMat4() const
Returns the transformation as a matrix.
Definition Transform_inl.h:111
const plVec3Template< Type > CompDiv(const plVec3Template< Type > &rhs) const
Returns the component-wise division of *this and rhs.
Definition Vec3_inl.h:354
const plVec4Template< Type > GetAsVec4(Type w) const
Returns an plVec4Template with x,y,z from this vector and w set to the parameter.
Definition Vec4_inl.h:35
const plVec3Template< Type > CompMax(const plVec3Template< Type > &rhs) const
Returns the component-wise maximum of *this and rhs.
Definition Vec3_inl.h:326
const plVec3Template< Type > CompMul(const plVec3Template< Type > &rhs) const
Returns the component-wise multiplication of *this and rhs.
Definition Vec3_inl.h:345
constexpr PL_ALWAYS_INLINE T Clamp(T value, T min_val, T max_val)
Clamps "value" to the range [min; max]. Returns "value", if it is inside the range already.
Definition Math_inl.h:51
PL_ALWAYS_INLINE float Tan(plAngle a)
Takes an angle, returns its tangent.
Definition MathFloat_inl.h:72
PL_ALWAYS_INLINE float Cos(plAngle a)
Takes an angle, returns its cosine.
Definition MathFloat_inl.h:67
constexpr PL_ALWAYS_INLINE T Max(T f1, T f2)
Returns the greater value, f1 or f2.
Definition Math_inl.h:39