/// <summary> /// Collects the visible lights by intersecting them with the frustum. /// </summary> private void CollectVisibleLights() { foreach (var renderView in RenderSystem.Views) { if (renderView.GetType() != typeof(RenderView)) { continue; } lightProcessor = renderView.SceneInstance.GetProcessor <LightProcessor>(); // No light processors means no light in the scene, so we can early exit if (lightProcessor == null) { continue; } RenderViewLightData renderViewLightData; if (!renderViewDatas.TryGetValue(renderView, out renderViewLightData)) { renderViewLightData = new RenderViewLightData(); renderViewDatas.Add(renderView, renderViewLightData); } else { // 1) Clear the cache of current lights (without destroying collections but keeping previously allocated ones) ClearCache(renderViewLightData.ActiveLightGroups); } renderViewLightData.VisibleLights.Clear(); renderViewLightData.VisibleLightsWithShadows.Clear(); // TODO GRAPHICS REFACTOR var sceneCullingMask = renderView.CullingMask; // 2) Cull lights with the frustum var frustum = renderView.Frustum; foreach (var light in lightProcessor.Lights) { // If light is not part of the culling mask group, we can skip it var entityLightMask = (EntityGroupMask)(1 << (int)light.Entity.Group); if ((entityLightMask & sceneCullingMask) == 0 && (light.CullingMask & sceneCullingMask) == 0) { continue; } // If light is not in the frustum, we can skip it var directLight = light.Type as IDirectLight; if (directLight != null && directLight.HasBoundingBox && !frustum.Contains(ref light.BoundingBoxExt)) { continue; } // Find the group for this light var lightGroup = GetLightGroup(renderViewLightData, light); lightGroup.PrepareLight(light); // This is a visible light renderViewLightData.VisibleLights.Add(light); // Add light to a special list if it has shadows if (directLight != null && directLight.Shadow.Enabled && ShadowMapRenderer != null) { // A visible light with shadows renderViewLightData.VisibleLightsWithShadows.Add(light); } } // 3) Allocate collection based on their culling mask AllocateCollectionsPerGroupOfCullingMask(renderViewLightData.ActiveLightGroups); // 4) Collect lights to the correct light collection group foreach (var light in renderViewLightData.VisibleLights) { var lightGroup = GetLightGroup(renderViewLightData, light); lightGroup.AddLight(light); } } }
protected override void DrawCore(RenderContext context) { modelProcessor = SceneInstance.GetCurrent(context).GetProcessor <ModelProcessor>(); lightProcessor = SceneInstance.GetCurrent(context).GetProcessor <LightProcessor>(); // No light processors means no light in the scene, so we can early exit if (lightProcessor == null || modelProcessor == null) { return; } // Not in the context of a SceneCameraRenderer? just exit sceneCameraRenderer = context.Tags.Get(SceneCameraRenderer.Current); sceneCamera = context.Tags.Get(CameraComponentRenderer.Current); if (sceneCameraRenderer == null || sceneCamera == null) { return; } sceneCullingMask = sceneCameraRenderer.CullingMask; // Setup the callback on the ModelRenderer and shadow map LightGroupRenderer if (!isModelComponentRendererSetup) { // TODO: Check if we could discover declared renderers in a better way than just hacking the tags of a component var modelRenderer = ModelComponentRenderer.GetAttached(sceneCameraRenderer); if (modelRenderer == null) { return; } modelRenderer.Callbacks.PreRenderModel += PrepareRenderModelForRendering; modelRenderer.Callbacks.PreRenderMesh += PreRenderMesh; // TODO: Make this pluggable // TODO: Shadows should work on mobile platforms if (context.GraphicsDevice.Features.Profile >= GraphicsProfile.Level_10_0 && (Platform.Type == PlatformType.Windows || Platform.Type == PlatformType.WindowsStore || Platform.Type == PlatformType.Windows10)) { shadowMapRenderer = new ShadowMapRenderer(modelRenderer.EffectName); shadowMapRenderer.Renderers.Add(typeof(LightDirectional), new LightDirectionalShadowMapRenderer()); shadowMapRenderer.Renderers.Add(typeof(LightSpot), new LightSpotShadowMapRenderer()); } isModelComponentRendererSetup = true; } // Collect all visible lights CollectVisibleLights(); // Draw shadow maps if (shadowMapRenderer != null) { shadowMapRenderer.Draw(context, visibleLightsWithShadows); } // Prepare active renderers in an ordered list (by type and shadow on/off) CollectActiveLightRenderers(context); currentModelLightShadersPermutationEntry = null; currentModelShadersParameters = null; currentShadowReceiver = true; // Clear the cache of parameter entries lightParameterEntries.Clear(); parameterCollectionEntryPool.Clear(); // Clear association between model and lights modelToLights.Clear(); // Clear all data generated by shader entries foreach (var shaderEntry in shaderEntries) { shaderEntry.Value.ResetGroupDatas(); } }