@@ -194,11 +194,12 @@ namespace cage
194194 return uni;
195195 }
196196
197- UniLight initializeLightUni (const Mat4 &model, const LightComponent &lc)
197+ UniLight initializeLightUni (const Mat4 &model, const LightComponent &lc, const Vec3 &cameraCenter )
198198 {
199199 CAGE_ASSERT (lc.minDistance > 0 && lc.maxDistance > lc.minDistance );
200200 static constexpr Real RoundingOffset = 1e-7 ;
201201 UniLight uni;
202+
202203 uni.color = Vec4 (colorGammaToLinear (lc.color ), lc.intensity );
203204 {
204205 // move as much of the energy from the intensity to the color
@@ -207,20 +208,22 @@ namespace cage
207208 c = clamp (c, 0.01 , 1 );
208209 uni.color = Vec4 (Vec3 (uni.color ) / c, uni.color [3 ] * c);
209210 }
211+
210212 uni.position = model * Vec4 (0 , 0 , 0 , 1 );
211- uni.direction = model * Vec4 (0 , 0 , -1 , 0 );
212- if (lc.lightType == LightTypeEnum::Directional)
213- {
214- uni.attenuation = Vec4 (0 );
215- uni.position [3 ] = Real::Infinity ();
216- }
217- else
213+ uni.direction = normalize (model * Vec4 (0 , 0 , -1 , 0 ));
214+
215+ if (lc.lightType != LightTypeEnum::Directional)
218216 {
219217 uni.attenuation [0 ] = (int )lc.attenuation + RoundingOffset;
220218 uni.attenuation [1 ] = lc.minDistance ;
221219 uni.attenuation [2 ] = lc.maxDistance ;
222- uni.position [3 ] = lc.maxDistance ;
223220 }
221+
222+ if (lc.lightType == LightTypeEnum::Point)
223+ uni.position [3 ] = lc.maxDistance / (distance (Vec3 (uni.position ), cameraCenter) + 1e-5 );
224+ else
225+ uni.position [3 ] = Real::Infinity ();
226+
224227 uni.params [0 ] = [&]() -> Real
225228 {
226229 switch (lc.lightType )
@@ -238,28 +241,22 @@ namespace cage
238241 uni.params [1 ] = lc.ssaoFactor ;
239242 uni.params [2 ] = cos (lc.spotAngle * 0.5 );
240243 uni.params [3 ] = lc.spotExponent ;
244+
241245 return uni;
242246 }
243247
244- void filterLightsOverLimit (std::vector<UniLight> &lights, Vec3 cameraCenter )
248+ void filterLightsOverLimit (std::vector<UniLight> &lights, uint32 limit )
245249 {
246- std::sort (lights.begin (), lights.end (),
247- [&](const UniLight &a, const UniLight &b)
248- {
249- const Real aa = a.position [3 ] / (1 + distance (Vec3 (a.position ), cameraCenter));
250- const Real bb = b.position [3 ] / (1 + distance (Vec3 (b.position ), cameraCenter));
251- return aa > bb;
252- });
253- if (lights.size () > CAGE_SHADER_MAX_LIGHTS)
254- lights.resize (CAGE_SHADER_MAX_LIGHTS);
250+ std::sort (lights.begin (), lights.end (), [&](const UniLight &a, const UniLight &b) { return a.position [3 ] > b.position [3 ]; });
251+ limit = min (limit, (uint32)CAGE_SHADER_MAX_LIGHTS);
252+ if (lights.size () > limit)
253+ lights.resize (limit);
255254
256255 // fade-out lights close to limit
257- Real intensity = 1 ;
258- for (uint32 i = CAGE_SHADER_MAX_LIGHTS * 85 / 100 ; i < lights.size (); i++)
259- {
260- intensity *= 0.9 ;
261- lights[i].color [3 ] *= intensity;
262- }
256+ const uint32 s = max (limit * 85 / 100 , 10u );
257+ const Real f = 1.0 / (limit - s + 1 );
258+ for (uint32 i = s; i < lights.size (); i++)
259+ lights[i].color [3 ] *= saturate (1 - (i - s + 1 ) * f);
263260 }
264261
265262 void updateShaderRoutinesForTextures (const std::array<Holder<Texture>, MaxTexturesCountPerMaterial> &textures, UniOptions &options)
@@ -895,13 +892,13 @@ namespace cage
895892 return ;
896893 if (e->has <ShadowmapComponent>())
897894 return ;
898- UniLight uni = initializeLightUni (modelTransform (e), lc);
895+ UniLight uni = initializeLightUni (modelTransform (e), lc, data. transform . position );
899896 if (lc.lightType == LightTypeEnum::Point && !intersects (frustum, Sphere (Vec3 (uni.position ), uni.position [3 ])))
900897 return ;
901898 lights.push_back (uni);
902899 },
903900 +scene, false );
904- filterLightsOverLimit (lights, data. transform . position );
901+ filterLightsOverLimit (lights, camera. maxLights );
905902 data.lightsCount = numeric_cast<uint32>(lights.size ());
906903 if (!lights.empty ())
907904 renderQueue->universalUniformArray <UniLight>(lights, CAGE_SHADER_UNIBLOCK_LIGHTS);
@@ -1176,6 +1173,7 @@ namespace cage
11761173 Holder<AsyncTask> prepareShadowmap (CameraData &camera, Entity *e, const LightComponent &lc, const ShadowmapComponent &sc) const
11771174 {
11781175 ShadowmapData &data = camera.shadowmaps [e];
1176+ CAGE_ASSERT (e->id () != 0 ); // lights with shadowmap may not be anonymous
11791177 data.name = Stringizer () + camera.name + " _shadowmap_" + e->id ();
11801178 data.camera .sceneMask = camera.camera .sceneMask ;
11811179 data.lightComponent = lc;
@@ -1216,7 +1214,7 @@ namespace cage
12161214
12171215 {
12181216 UniShadowedLight &uni = data.shadowUni ;
1219- (UniLight &)uni = initializeLightUni (data.model , data.lightComponent );
1217+ (UniLight &)uni = initializeLightUni (data.model , data.lightComponent , data. transform . position );
12201218 uni.shadowParams [2 ] = data.shadowmapComponent .normalOffsetScale ;
12211219 uni.shadowParams [3 ] = data.shadowmapComponent .shadowFactor ;
12221220 uni.params [0 ] += 1 ; // shadowed light type
0 commit comments