| 1189 | } |
| 1190 | |
| 1191 | void BindlessDeferred::UpdateLights() |
| 1192 | { |
| 1193 | const uint64 numSpotLights = Min<uint64>(spotLights.Size(), AppSettings::MaxLightClamp); |
| 1194 | |
| 1195 | // This is an additional scale factor that's needed to make sure that our polygonal bounding cone |
| 1196 | // fully encloses the actual cone representing the light's area of influence |
| 1197 | const float inRadius = std::cos(Pi / NumConeSides); |
| 1198 | const float scaleCorrection = 1.0f / inRadius; |
| 1199 | |
| 1200 | const Float4x4 viewMatrix = camera.ViewMatrix(); |
| 1201 | const float nearClip = camera.NearClip(); |
| 1202 | const float farClip = camera.FarClip(); |
| 1203 | const float zRange = farClip - nearClip; |
| 1204 | const Float3 cameraPos = camera.Position(); |
| 1205 | const uint64 numConeVerts = coneVertices.Size(); |
| 1206 | |
| 1207 | // Come up with a bounding sphere that surrounds the near clipping plane. We'll test this sphere |
| 1208 | // for intersection with the spot light's bounding cone, and use that to over-estimate if the bounding |
| 1209 | // geometry will end up getting clipped by the camera's near clipping plane |
| 1210 | Float3 nearClipCenter = cameraPos + nearClip * camera.Forward(); |
| 1211 | Float4x4 invViewProjection = Float4x4::Invert(camera.ViewProjectionMatrix()); |
| 1212 | Float3 nearTopRight = Float3::Transform(Float3(1.0f, 1.0f, 0.0f), invViewProjection); |
| 1213 | float nearClipRadius = Float3::Length(nearTopRight - nearClipCenter); |
| 1214 | |
| 1215 | ClusterBounds* boundsData = spotLightBoundsBuffer.Map<ClusterBounds>(); |
| 1216 | bool intersectsCamera[AppSettings::MaxDecals] = { }; |
| 1217 | |
| 1218 | // Update the light bounds buffer |
| 1219 | for(uint64 spotLightIdx = 0; spotLightIdx < numSpotLights; ++spotLightIdx) |
| 1220 | { |
| 1221 | const SpotLight& spotLight = spotLights[spotLightIdx]; |
| 1222 | const ModelSpotLight& srcSpotLight = currentModel->SpotLights()[spotLightIdx]; |
| 1223 | ClusterBounds bounds; |
| 1224 | bounds.Position = spotLight.Position; |
| 1225 | bounds.Orientation = srcSpotLight.Orientation; |
| 1226 | bounds.Scale.x = bounds.Scale.y = std::tan(srcSpotLight.AngularAttenuation.y / 2.0f) * spotLight.Range * scaleCorrection; |
| 1227 | bounds.Scale.z = spotLight.Range; |
| 1228 | |
| 1229 | // Compute conservative Z bounds for the light based on vertices of the bounding geometry |
| 1230 | float minZ = FloatMax; |
| 1231 | float maxZ = -FloatMax; |
| 1232 | for(uint64 i = 0; i < numConeVerts; ++i) |
| 1233 | { |
| 1234 | Float3 coneVert = coneVertices[i] * bounds.Scale; |
| 1235 | coneVert = Float3::Transform(coneVert, bounds.Orientation); |
| 1236 | coneVert += bounds.Position; |
| 1237 | |
| 1238 | float vertZ = Float3::Transform(coneVert, viewMatrix).z; |
| 1239 | minZ = Min(minZ, vertZ); |
| 1240 | maxZ = Max(maxZ, vertZ); |
| 1241 | } |
| 1242 | |
| 1243 | minZ = Saturate((minZ - nearClip) / zRange); |
| 1244 | maxZ = Saturate((maxZ - nearClip) / zRange); |
| 1245 | |
| 1246 | bounds.ZBounds.x = uint32(minZ * AppSettings::NumZTiles); |
| 1247 | bounds.ZBounds.y = Min(uint32(maxZ * AppSettings::NumZTiles), uint32(AppSettings::NumZTiles - 1)); |
| 1248 | |