public LightEntry(int currentLightGroupIndex, int currentLightGroupIndexNoShadows, LightComponent light, LightShadowMapTexture shadow) { GroupIndex = currentLightGroupIndex; GroupIndexNoShadows = currentLightGroupIndexNoShadows; Light = light; Shadow = shadow; }
public LightDynamicEntry(LightComponent light, LightShadowMapTexture shadowMapTexture) { Light = light; ShadowMapTexture = shadowMapTexture; }
public override void ProcessLights(ProcessLightsParameters parameters) { if (parameters.LightCollection.Count == 0) { return; } // Check if we have a fallback renderer next in the chain, in case we don't need shadows bool hasNextRenderer = parameters.RendererIndex < (parameters.Renderers.Length - 1); var currentGroupParameters = SpotLightGroupParameters.Null; // Start by filtering/sorting what can be processed shadowComparer.ShadowMapTexturesPerLight = parameters.ShadowMapTexturesPerLight; shadowComparer.Lights = parameters.LightCollection; parameters.LightIndices.Sort(0, parameters.LightIndices.Count, shadowComparer); // Loop over the number of lights + 1 where the last iteration will always flush the last batch of lights for (int j = 0; j < parameters.LightIndices.Count + 1;) { // TODO: Eventually move this loop to a separate function that returns a structure. // These variables will contain the relevant parameters of the next usable light: var nextGroupParameters = SpotLightGroupParameters.Null; LightShadowMapTexture nextShadowTexture = null; RenderLight nextLight = null; // Find the next light whose attributes aren't null: if (j < parameters.LightIndices.Count) { nextLight = parameters.LightCollection[parameters.LightIndices[j]]; if (nextLight.Type is LightSpot spotLight) { if (spotLight.ProjectiveTexture != null) // TODO: Remove this branch?! { nextGroupParameters.SpotParameters.ProjectionTexture = spotLight.ProjectiveTexture; nextGroupParameters.SpotParameters.FlipMode = spotLight.FlipMode; nextGroupParameters.SpotParameters.UVScale = spotLight.UVScale; nextGroupParameters.SpotParameters.UVOffset = spotLight.UVOffset; } } if (parameters.ShadowMapRenderer != null && parameters.ShadowMapTexturesPerLight.TryGetValue(nextLight, out nextShadowTexture) && nextShadowTexture.Atlas != null) // atlas could not be allocated? treat it as a non-shadowed texture { nextGroupParameters.ShadowType = nextShadowTexture.ShadowType; nextGroupParameters.ShadowRenderer = nextShadowTexture.Renderer; } } // Flush current group // If we detect that the previous light's attributes don't match the next one's, create a new group (or add to an existing one that has the same attributes): if (j == parameters.LightIndices.Count || !currentGroupParameters.Equals(ref nextGroupParameters)) { if (processedLights.Count > 0) { ITextureProjectionRenderer currentTextureProjectionRenderer = FindOrCreateTextureProjectionRenderer(currentGroupParameters); var lightGroupKey = new LightGroupKey(currentGroupParameters.ShadowRenderer, currentGroupParameters.ShadowType, currentTextureProjectionRenderer); LightShaderGroupDynamic lightShaderGroup = FindOrCreateLightShaderGroup(lightGroupKey, parameters); // Add view and lights to the current group: var allowedLightCount = lightShaderGroup.AddView(parameters.ViewIndex, parameters.View, processedLights.Count); for (int i = 0; i < allowedLightCount; ++i) { LightDynamicEntry light = processedLights[i]; lightShaderGroup.AddLight(light.Light, light.ShadowMapTexture); } // TODO: assign extra lights to non-shadow rendering if possible //for (int i = lightCount; i < processedLights.Count; ++i) // XXX.AddLight(processedLights[i], null); // Add the current light shader group to the collection if it hasn't already been added: var lightShaderGroupEntry = new LightShaderGroupEntry <LightGroupKey>(lightGroupKey, lightShaderGroup); if (!lightShaderGroups.Contains(lightShaderGroupEntry)) { lightShaderGroups.Add(lightShaderGroupEntry); } processedLights.Clear(); } // Start next group currentGroupParameters = nextGroupParameters; } if (j < parameters.LightIndices.Count) { // Do we need to process non shadowing lights or defer it to something else? if (nextShadowTexture == null && hasNextRenderer) { // Break out so the remaining lights can be handled by the next renderer break; } parameters.LightIndices.RemoveAt(j); processedLights.Add(new LightDynamicEntry(nextLight, nextShadowTexture)); } else { j++; } } processedLights.Clear(); }
private bool PrepareRenderModelForRendering(RenderContext context, RenderModel model) { var shaderKeyIdBuilder = new ObjectIdSimpleBuilder(); var parametersKeyIdBuilder = new ObjectIdSimpleBuilder(); //var idBuilder = new ObjectIdBuilder(); var modelComponent = model.ModelComponent; var group = modelComponent.Entity.Group; var modelBoundingBox = modelComponent.BoundingBox; directLightsPerModel.Clear(); directLightShaderGroupEntryKeys.Clear(); directLightShaderGroupEntryKeysNoShadows.Clear(); environmentLightsPerModel.Clear(); environmentLightShaderGroupEntryKeys.Clear(); // This loop is looking for visible lights per render model and calculate a ShaderId and ParametersId // TODO: Part of this loop could be processed outisde of the PrepareRenderModelForRendering // For example: Environment lights or directional lights are always active, so we could pregenerate part of the // id and groups outside this loop. Also considering that each light renderer has a maximum of lights // we could pre foreach (var activeRenderer in activeRenderers) { var lightRenderer = activeRenderer.LightRenderer; var lightCollection = activeRenderer.LightGroup.FindLightCollectionByGroup(group); var lightCount = lightCollection == null ? 0 : lightCollection.Count; int lightMaxCount = Math.Min(lightCount, lightRenderer.LightMaxCount); var lightRendererId = lightRenderer.LightRendererId; var allocCountForNewLightType = lightRenderer.AllocateLightMaxCount ? (byte)lightRenderer.LightMaxCount : (byte)1; var currentShaderKey = new LightForwardShaderEntryKey(); // Path for environment lights if (lightRenderer.IsEnvironmentLight) { // The loop is simpler for environment lights (single group per light, no shadow maps, no bounding box...etc) for (int i = 0; i < lightMaxCount; i++) { var light = lightCollection[i]; currentShaderKey = new LightForwardShaderEntryKey(lightRendererId, 0, allocCountForNewLightType); unsafe { shaderKeyIdBuilder.Write(*(uint *)¤tShaderKey); } parametersKeyIdBuilder.Write(light.Id); environmentLightsPerModel.Add(new LightEntry(environmentLightShaderGroupEntryKeys.Count, 0, light, null)); environmentLightShaderGroupEntryKeys.Add(new LightForwardShaderFullEntryKey(currentShaderKey, lightRenderer, null)); } } else { ILightShadowMapRenderer currentShadowRenderer = null; for (int i = 0; i < lightMaxCount; i++) { var light = lightCollection[i]; var directLight = (IDirectLight)light.Type; // If the light does not intersects the model, we can skip it if (directLight.HasBoundingBox && !light.BoundingBox.Intersects(ref modelBoundingBox)) { continue; } LightShadowMapTexture shadowTexture = null; LightShadowType shadowType = 0; ILightShadowMapRenderer newShadowRenderer = null; if (shadowMapRenderer != null && shadowMapRenderer.LightComponentsWithShadows.TryGetValue(light, out shadowTexture)) { shadowType = shadowTexture.ShadowType; newShadowRenderer = shadowTexture.Renderer; } if (i == 0) { currentShaderKey = new LightForwardShaderEntryKey(lightRendererId, shadowType, allocCountForNewLightType); currentShadowRenderer = newShadowRenderer; } else { if (currentShaderKey.LightRendererId == lightRendererId && currentShaderKey.ShadowType == shadowType) { if (!lightRenderer.AllocateLightMaxCount) { currentShaderKey.LightCount++; } } else { unsafe { shaderKeyIdBuilder.Write(*(uint *)¤tShaderKey); } directLightShaderGroupEntryKeys.Add(new LightForwardShaderFullEntryKey(currentShaderKey, lightRenderer, currentShadowRenderer)); currentShaderKey = new LightForwardShaderEntryKey(lightRendererId, shadowType, allocCountForNewLightType); currentShadowRenderer = newShadowRenderer; } } parametersKeyIdBuilder.Write(light.Id); directLightsPerModel.Add(new LightEntry(directLightShaderGroupEntryKeys.Count, directLightShaderGroupEntryKeysNoShadows.Count, light, shadowTexture)); } if (directLightsPerModel.Count > 0) { directLightShaderGroupEntryKeysNoShadows.Add(new LightForwardShaderFullEntryKey(new LightForwardShaderEntryKey(lightRendererId, 0, (byte)directLightsPerModel.Count), lightRenderer, null)); unsafe { shaderKeyIdBuilder.Write(*(uint *)¤tShaderKey); } directLightShaderGroupEntryKeys.Add(new LightForwardShaderFullEntryKey(currentShaderKey, lightRenderer, currentShadowRenderer)); } } } // Find or create an existing shaders/parameters permutation // Build the keys for Shaders and Parameters permutations ObjectId shaderKeyId; ObjectId parametersKeyId; shaderKeyIdBuilder.ComputeHash(out shaderKeyId); parametersKeyIdBuilder.ComputeHash(out parametersKeyId); // Calculate the shader parameters just once // If we don't have already this permutation, use it LightShaderPermutationEntry newLightShaderPermutationEntry; if (!shaderEntries.TryGetValue(shaderKeyId, out newLightShaderPermutationEntry)) { newLightShaderPermutationEntry = CreateShaderPermutationEntry(); shaderEntries.Add(shaderKeyId, newLightShaderPermutationEntry); } LightParametersPermutationEntry newShaderEntryParameters; // Calculate the shader parameters just once per light combination and for this rendering pass if (!lightParameterEntries.TryGetValue(parametersKeyId, out newShaderEntryParameters)) { newShaderEntryParameters = CreateParametersPermutationEntry(newLightShaderPermutationEntry); lightParameterEntries.Add(parametersKeyId, newShaderEntryParameters); } modelToLights.Add(model, new RenderModelLights(newLightShaderPermutationEntry, newShaderEntryParameters)); return(true); }
public override void ProcessLights(ProcessLightsParameters parameters) { if (parameters.LightCollection.Count == 0) { return; } // Check if we have a fallback renderer next in the chain, in case we don't need shadows bool hasNextRenderer = parameters.RendererIndex < (parameters.Renderers.Length - 1); ILightShadowMapRenderer currentShadowRenderer = null; LightShadowType currentShadowType = 0; // Start by filtering/sorting what can be processed shadowComparer.ShadowMapTexturesPerLight = parameters.ShadowMapTexturesPerLight; shadowComparer.Lights = parameters.LightCollection; parameters.LightIndices.Sort(0, parameters.LightIndices.Count, shadowComparer); // Loop over the number of lights + 1 where the last iteration will always flush the last batch of lights for (int j = 0; j < parameters.LightIndices.Count + 1;) { LightShadowType nextShadowType = 0; ILightShadowMapRenderer nextShadowRenderer = null; LightShadowMapTexture nextShadowTexture = null; LightComponent nextLight = null; if (j < parameters.LightIndices.Count) { nextLight = parameters.LightCollection[parameters.LightIndices[j]]; if (parameters.ShadowMapRenderer != null && parameters.ShadowMapTexturesPerLight.TryGetValue(nextLight, out nextShadowTexture) && nextShadowTexture.Atlas != null) // atlas could not be allocated? treat it as a non-shadowed texture { nextShadowType = nextShadowTexture.ShadowType; nextShadowRenderer = nextShadowTexture.Renderer; } } // Flush current group if (j == parameters.LightIndices.Count || currentShadowType != nextShadowType || currentShadowRenderer != nextShadowRenderer) { if (processedLights.Count > 0) { var lightGroupKey = new LightGroupKey(currentShadowRenderer, currentShadowType); LightShaderGroupDynamic lightShaderGroup; if (!lightShaderGroupPool.TryGetValue(lightGroupKey, out lightShaderGroup)) { ILightShadowMapShaderGroupData shadowGroupData = null; if (currentShadowRenderer != null) { shadowGroupData = currentShadowRenderer.CreateShaderGroupData(currentShadowType); } lightShaderGroup = CreateLightShaderGroup(parameters.Context, shadowGroupData); lightShaderGroup.SetViews(parameters.Views); lightShaderGroupPool.Add(lightGroupKey, lightShaderGroup); } // Add view and lights var allowedLightCount = lightShaderGroup.AddView(parameters.ViewIndex, parameters.View, processedLights.Count); for (int i = 0; i < allowedLightCount; ++i) { var light = processedLights[i]; lightShaderGroup.AddLight(light.Light, light.ShadowMapTexture); } // TODO: assign extra lights to non-shadow rendering if possible //for (int i = lightCount; i < processedLights.Count; ++i) // XXX.AddLight(processedLights[i], null); var lightShaderGroupEntry = new LightShaderGroupEntry(lightGroupKey, lightShaderGroup); if (!lightShaderGroups.Contains(lightShaderGroupEntry)) { lightShaderGroups.Add(lightShaderGroupEntry); } processedLights.Clear(); } // Start next group currentShadowType = nextShadowType; currentShadowRenderer = nextShadowRenderer; } if (j < parameters.LightIndices.Count) { // Do we need to process non shadowing lights or defer it to something else? if (nextShadowTexture == null && hasNextRenderer) { // Break out so the remaining lights can be handled by the next renderer break; } parameters.LightIndices.RemoveAt(j); processedLights.Add(new LightDynamicEntry(nextLight, nextShadowTexture)); } else { j++; } } processedLights.Clear(); }
public void AddLight(LightComponent light, LightShadowMapTexture shadowMapTexture) { AddLightInternal(light); ShadowGroup?.SetShadowMapShaderData(Count, shadowMapTexture.ShaderData); Count++; }
private void SetupLight(RenderDrawContext context, LightShaftProcessor.AssociatedData lightShaft, LightShadowMapTexture shadowMapTexture, ParameterCollection lightParameterCollection) { BoundingBoxExt box = new BoundingBoxExt(new Vector3(-float.MaxValue), new Vector3(float.MaxValue)); // TODO LightShaftRenderData data; if (!renderData.TryGetValue(lightShaft.Light, out data)) { data = new LightShaftRenderData(); renderData.Add(lightShaft.Light, data); UpdateRenderData(context, data, lightShaft, shadowMapTexture); } if (shadowMapTexture != null && data.ShadowMapRenderer != null) { // Detect changed shadow map renderer or type if (data.ShadowMapRenderer != shadowMapTexture.Renderer || data.ShadowType != shadowMapTexture.ShadowType) { UpdateRenderData(context, data, lightShaft, shadowMapTexture); } } else if (shadowMapTexture?.Renderer != data.ShadowMapRenderer) // Change from no shadows to shadows { UpdateRenderData(context, data, lightShaft, shadowMapTexture); } data.RenderViews[0] = context.RenderContext.RenderView; data.ShaderGroup.Reset(); data.ShaderGroup.SetViews(data.RenderViews); data.ShaderGroup.AddView(0, context.RenderContext.RenderView, 1); data.ShaderGroup.AddLight(lightShaft.LightComponent, shadowMapTexture); data.ShaderGroup.UpdateLayout("lightGroup"); lightParameterCollection.Set(LightShaftsEffectKeys.LightGroup, data.ShaderGroup.ShaderSource); // Update the effect here so the layout is correct lightShaftsEffectShader.EffectInstance.UpdateEffect(GraphicsDevice); data.ShaderGroup.ApplyViewParameters(context, 0, lightParameterCollection); data.ShaderGroup.ApplyDrawParameters(context, 0, lightParameterCollection, ref box); data.UsageCounter = usageCounter; }
/// <summary> /// Try to add light to this group (returns false if not possible). /// </summary> /// <param name="light"></param> /// <param name="shadowMapTexture"></param> /// <returns></returns> public bool AddLight(LightComponent light, LightShadowMapTexture shadowMapTexture) { Lights.Add(new LightDynamicEntry(light, shadowMapTexture)); return(true); }
private void UpdateRenderData(RenderDrawContext context, LightShaftRenderData data, LightShaftProcessor.AssociatedData lightShaft, LightShadowMapTexture shadowMapTexture) { if (lightShaft.Light is LightPoint) { data.GroupRenderer = new LightPointGroupRenderer(); } else if (lightShaft.Light is LightSpot) { data.GroupRenderer = new LightSpotGroupRenderer(); } else if (lightShaft.Light is LightDirectional) { data.GroupRenderer = new LightDirectionalGroupRenderer(); } else { throw new InvalidOperationException("Unsupported light type"); } ILightShadowMapShaderGroupData shadowGroup = null; if (shadowMapTexture != null) { data.ShadowType = shadowMapTexture.ShadowType; data.ShadowMapRenderer = shadowMapTexture.Renderer; shadowGroup = data.ShadowMapRenderer.CreateShaderGroupData(data.ShadowType); } else { data.ShadowType = 0; data.ShadowMapRenderer = null; } data.ShaderGroup = data.GroupRenderer.CreateLightShaderGroup(context, shadowGroup); // TODO: Implement support for texture projection and attenuation? }
public LightDynamicEntry(RenderLight light, LightShadowMapTexture shadowMapTexture) { Light = light; ShadowMapTexture = shadowMapTexture; }
/// <summary> /// Try to add light to this group (returns false if not possible). /// </summary> /// <param name="light"></param> /// <param name="shadowMapTexture"></param> /// <returns></returns> public bool AddLight(RenderLight light, LightShadowMapTexture shadowMapTexture) { lights.Add(new LightDynamicEntry(light, shadowMapTexture)); return(true); }
private LightParametersPermutationEntry PreparePermutationEntryForRendering(RenderViewLightData renderViewData, bool isShadowReceiver, ref BoundingBox boundingBox, EntityGroup group, int effectSlot) { var shaderKeyIdBuilder = new ObjectIdSimpleBuilder(); var parametersKeyIdBuilder = new ObjectIdSimpleBuilder(); directLightsPerMesh.Clear(); directLightShaderGroupEntryKeys.Clear(); environmentLightsPerMesh.Clear(); environmentLightShaderGroupEntryKeys.Clear(); // Create different parameter collections depending on shadows // TODO GRAPHICS REFACTOR can we use the same parameter collection for shadowed/non-shadowed? parametersKeyIdBuilder.Write(isShadowReceiver ? 1U : 0U); shaderKeyIdBuilder.Write(isShadowReceiver ? 1U : 0U); shaderKeyIdBuilder.Write((uint)effectSlot); // This loop is looking for visible lights per render model and calculate a ShaderId and ParametersId // TODO: Part of this loop could be processed outisde of the PrepareRenderMeshForRendering // For example: Environment lights or directional lights are always active, so we could pregenerate part of the // id and groups outside this loop. Also considering that each light renderer has a maximum of lights // we could pre foreach (var activeRenderer in renderViewData.ActiveRenderers) { var lightRenderer = activeRenderer.LightRenderer; var lightCollection = activeRenderer.LightGroup.FindLightCollectionByGroup(group); var lightCount = lightCollection == null ? 0 : lightCollection.Count; int lightMaxCount = Math.Min(lightCount, lightRenderer.LightMaxCount); var lightRendererId = lightRenderer.LightRendererId; var allocCountForNewLightType = lightRenderer.AllocateLightMaxCount ? (byte)lightRenderer.LightMaxCount : (byte)1; var currentShaderKey = new LightForwardShaderEntryKey(); // Path for environment lights if (lightRenderer.IsEnvironmentLight) { // The loop is simpler for environment lights (single group per light, no shadow maps, no bounding box...etc) for (int i = 0; i < lightMaxCount; i++) { var light = lightCollection[i]; currentShaderKey = new LightForwardShaderEntryKey(lightRendererId, 0, allocCountForNewLightType); unsafe { shaderKeyIdBuilder.Write(*(uint *)¤tShaderKey); } parametersKeyIdBuilder.Write(light.Id); environmentLightsPerMesh.Add(new LightEntry(environmentLightShaderGroupEntryKeys.Count, light, null)); environmentLightShaderGroupEntryKeys.Add(new LightForwardShaderFullEntryKey(currentShaderKey, lightRenderer, null)); } } else { ILightShadowMapRenderer currentShadowRenderer = null; bool hasDirectLight = false; for (int i = 0; i < lightMaxCount; i++) { var light = lightCollection[i]; var directLight = (IDirectLight)light.Type; // If the light does not intersects the model, we can skip it if (directLight.HasBoundingBox && !light.BoundingBox.Intersects(ref boundingBox)) { continue; } LightShadowMapTexture shadowTexture = null; LightShadowType shadowType = 0; ILightShadowMapRenderer newShadowRenderer = null; if (ShadowMapRenderer != null && renderViewData.LightComponentsWithShadows.TryGetValue(light, out shadowTexture)) { shadowType = shadowTexture.ShadowType; newShadowRenderer = (ILightShadowMapRenderer)shadowTexture.Renderer; } if (!hasDirectLight) { hasDirectLight = true; currentShaderKey = new LightForwardShaderEntryKey(lightRendererId, shadowType, allocCountForNewLightType); currentShadowRenderer = newShadowRenderer; } else { if (currentShaderKey.LightRendererId == lightRendererId && currentShaderKey.ShadowType == shadowType) { if (!lightRenderer.AllocateLightMaxCount) { currentShaderKey.LightCount++; } } else { unsafe { shaderKeyIdBuilder.Write(*(uint *)¤tShaderKey); } directLightShaderGroupEntryKeys.Add(new LightForwardShaderFullEntryKey(currentShaderKey, lightRenderer, isShadowReceiver ? currentShadowRenderer : null)); currentShaderKey = new LightForwardShaderEntryKey(lightRendererId, shadowType, allocCountForNewLightType); currentShadowRenderer = newShadowRenderer; } } parametersKeyIdBuilder.Write(light.Id); directLightsPerMesh.Add(new LightEntry(directLightShaderGroupEntryKeys.Count, light, shadowTexture)); } if (hasDirectLight) { unsafe { shaderKeyIdBuilder.Write(*(uint *)¤tShaderKey); } directLightShaderGroupEntryKeys.Add(new LightForwardShaderFullEntryKey(currentShaderKey, lightRenderer, isShadowReceiver ? currentShadowRenderer : null)); } } } // Find or create an existing shaders/parameters permutation // Build the keys for Shaders and Parameters permutations ObjectId shaderKeyId; ObjectId parametersKeyId; shaderKeyIdBuilder.ComputeHash(out shaderKeyId); parametersKeyIdBuilder.ComputeHash(out parametersKeyId); // Calculate the shader parameters just once // If we don't have already this permutation, use it LightShaderPermutationEntry newLightShaderPermutationEntry; if (!shaderEntries.TryGetValue(shaderKeyId, out newLightShaderPermutationEntry)) { newLightShaderPermutationEntry = CreateShaderPermutationEntry(); shaderEntries.Add(shaderKeyId, newLightShaderPermutationEntry); } // Calculate the shader parameters just once per light combination and for this rendering pass LightParametersPermutationEntry newShaderEntryParameters; if (!lightParameterEntries.TryGetValue(parametersKeyId, out newShaderEntryParameters)) { newShaderEntryParameters = CreateParametersPermutationEntry(newLightShaderPermutationEntry); lightParameterEntries.Add(parametersKeyId, newShaderEntryParameters); } return(newShaderEntryParameters); }
public override void ProcessLights(ProcessLightsParameters parameters) { if (parameters.LightCollection.Count == 0) { return; } ILightShadowMapRenderer currentShadowRenderer = null; LightShadowType currentShadowType = 0; // Start by filtering/sorting what can be processed shadowComparer.ShadowMapTexturesPerLight = parameters.ShadowMapTexturesPerLight; parameters.LightCollection.Sort(parameters.LightStart, parameters.LightEnd - parameters.LightStart, shadowComparer); for (int index = parameters.LightStart; index <= parameters.LightEnd; index++) { LightShadowType nextShadowType = 0; ILightShadowMapRenderer nextShadowRenderer = null; LightShadowMapTexture nextShadowTexture = null; LightComponent nextLight = null; if (index < parameters.LightEnd) { nextLight = parameters.LightCollection[index]; if (parameters.ShadowMapRenderer != null && parameters.ShadowMapTexturesPerLight.TryGetValue(nextLight, out nextShadowTexture) && nextShadowTexture.Atlas != null) // atlas could not be allocated? treat it as a non-shadowed texture { nextShadowType = nextShadowTexture.ShadowType; nextShadowRenderer = nextShadowTexture.Renderer; } } // Flush current group if (index == parameters.LightEnd || currentShadowType != nextShadowType || currentShadowRenderer != nextShadowRenderer) { if (processedLights.Count > 0) { var lightGroupKey = new LightGroupKey(currentShadowRenderer, currentShadowType); LightShaderGroupDynamic lightShaderGroup; if (!lightShaderGroupPool.TryGetValue(lightGroupKey, out lightShaderGroup)) { ILightShadowMapShaderGroupData shadowGroupData = null; if (currentShadowRenderer != null) { shadowGroupData = currentShadowRenderer.CreateShaderGroupData(currentShadowType); } lightShaderGroup = CreateLightShaderGroup(parameters.Context, shadowGroupData); lightShaderGroup.SetViews(parameters.Views); lightShaderGroupPool.Add(lightGroupKey, lightShaderGroup); } // Add view and lights var allowedLightCount = lightShaderGroup.AddView(parameters.ViewIndex, parameters.View, processedLights.Count); for (int i = 0; i < allowedLightCount; ++i) { var light = processedLights[i]; lightShaderGroup.AddLight(light.Light, light.ShadowMapTexture); } // TODO: assign extra lights to non-shadow rendering if possible //for (int i = lightCount; i < processedLights.Count; ++i) // XXX.AddLight(processedLights[i], null); var lightShaderGroupEntry = new LightShaderGroupEntry(lightGroupKey, lightShaderGroup); if (!lightShaderGroups.Contains(lightShaderGroupEntry)) { lightShaderGroups.Add(lightShaderGroupEntry); } processedLights.Clear(); } // Start next group currentShadowType = nextShadowType; currentShadowRenderer = nextShadowRenderer; } if (index < parameters.LightEnd) { // Do we need to process non shadowing lights or defer it to something else? if (nextShadowTexture == null && NonShadowRenderer != null) { parameters.LightStart = index; NonShadowRenderer.ProcessLights(parameters); break; } processedLights.Add(new LightDynamicEntry(nextLight, nextShadowTexture)); } } processedLights.Clear(); }