Пример #1
0
            /// <summary>
            /// Initializes a new instance of the <see cref="LightSpotShadowMapGroupShaderData" /> class.
            /// </summary>
            /// <param name="compositionKey">The composition key.</param>
            /// <param name="shadowType">Type of the shadow.</param>
            /// <param name="lightCountMax">The light count maximum.</param>
            public LightSpotShadowMapGroupShaderData(string compositionKey, LightShadowType shadowType, int lightCountMax)
            {
                this.shadowType = shadowType;
                worldToShadowCascadeUV = new Matrix[lightCountMax];
                depthBiases = new float[lightCountMax];
                offsetScales = new float[lightCountMax];

                var mixin = new ShaderMixinSource();
                mixin.Mixins.Add(new ShaderClassSource(ShaderName,lightCountMax, (this.shadowType & LightShadowType.Debug) != 0));
                // TODO: Temporary passing filter here

                switch (shadowType & LightShadowType.FilterMask)
                {
                    case LightShadowType.PCF3x3:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 3));
                        break;
                    case LightShadowType.PCF5x5:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 5));
                        break;
                    case LightShadowType.PCF7x7:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 7));
                        break;
                    default:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterDefault"));
                        break;
                }

                shadowShader = mixin;
                shadowMapTextureKey = ShadowMapKeys.Texture.ComposeWith(compositionKey);
                shadowMapTextureSizeKey = ShadowMapKeys.TextureSize.ComposeWith(compositionKey);
                shadowMapTextureTexelSizeKey = ShadowMapKeys.TextureTexelSize.ComposeWith(compositionKey);
                worldToShadowCascadeUVsKey = ShadowMapReceiverBaseKeys.WorldToShadowCascadeUV.ComposeWith(compositionKey);
                depthBiasesKey = ShadowMapReceiverBaseKeys.DepthBiases.ComposeWith(compositionKey);
                offsetScalesKey = ShadowMapReceiverBaseKeys.OffsetScales.ComposeWith(compositionKey);
            }
Пример #2
0
 public LightGroupKey(ILightShadowMapRenderer shadowRenderer,
                      LightShadowType shadowType,
                      ITextureProjectionRenderer textureProjectionRenderer)
 {
     ShadowRenderer            = shadowRenderer;
     ShadowType                = shadowType;
     TextureProjectionRenderer = textureProjectionRenderer;
 }
Пример #3
0
        public int Compare(int a, int b)
        {
            LightShadowType shadowTypeA = GetShadowType(Lights[a]);
            LightShadowType shadowTypeB = GetShadowType(Lights[b]);

            // Decreasing order so that non shadowed lights are last
            return(((int)shadowTypeB).CompareTo((int)shadowTypeA));
        }
Пример #4
0
            /// <summary>
            /// Initializes a new instance of the <see cref="LightDirectionalShadowMapGroupShaderData" /> class.
            /// </summary>
            /// <param name="compositionKey">The composition key.</param>
            /// <param name="shadowType">Type of the shadow.</param>
            /// <param name="lightCountMax">The light count maximum.</param>
            public LightDirectionalShadowMapGroupShaderData(string compositionKey, LightShadowType shadowType, int lightCountMax)
            {
                this.shadowType        = shadowType;
                this.cascadeCount      = 1 << ((int)(shadowType & LightShadowType.CascadeMask) - 1);
                cascadeSplits          = new float[cascadeCount * lightCountMax];
                worldToShadowCascadeUV = new Matrix[cascadeCount * lightCountMax];
                depthBiases            = new float[lightCountMax];
                offsetScales           = new float[lightCountMax];

                var mixin            = new ShaderMixinSource();
                var isDepthRangeAuto = (this.shadowType & LightShadowType.DepthRangeAuto) != 0;

                mixin.Mixins.Add(new ShaderClassSource(ShaderName, cascadeCount, lightCountMax, (this.shadowType & LightShadowType.BlendCascade) != 0 && !isDepthRangeAuto, isDepthRangeAuto, (this.shadowType & LightShadowType.Debug) != 0));
                // TODO: Temporary passing filter here

                switch (shadowType & LightShadowType.FilterMask)
                {
                case LightShadowType.PCF3x3:
                    mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 3));
                    break;

                case LightShadowType.PCF5x5:
                    mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 5));
                    break;

                case LightShadowType.PCF7x7:
                    mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 7));
                    break;

                default:
                    mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterDefault"));
                    break;
                }

                shadowShader                 = mixin;
                shadowMapTextureKey          = ShadowMapKeys.Texture.ComposeWith(compositionKey);
                shadowMapTextureSizeKey      = ShadowMapKeys.TextureSize.ComposeWith(compositionKey);
                shadowMapTextureTexelSizeKey = ShadowMapKeys.TextureTexelSize.ComposeWith(compositionKey);
                cascadeSplitsKey             = ShadowMapReceiverDirectionalKeys.CascadeDepthSplits.ComposeWith(compositionKey);
                worldToShadowCascadeUVsKey   = ShadowMapReceiverBaseKeys.WorldToShadowCascadeUV.ComposeWith(compositionKey);
                depthBiasesKey               = ShadowMapReceiverBaseKeys.DepthBiases.ComposeWith(compositionKey);
                offsetScalesKey              = ShadowMapReceiverBaseKeys.OffsetScales.ComposeWith(compositionKey);
            }
Пример #5
0
 public override ILightShadowMapShaderGroupData CreateShaderGroupData(string compositionKey, LightShadowType shadowType, int maxLightCount)
 {
     return(new LightDirectionalShadowMapGroupShaderData(compositionKey, shadowType, maxLightCount));
 }
Пример #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LightSpotShadowMapGroupShaderData" /> class.
 /// </summary>
 /// <param name="shadowType">Type of the shadow.</param>
 /// <param name="lightCountMax">The light count maximum.</param>
 public LightSpotShadowMapGroupShaderData(LightShadowType shadowType)
 {
     this.shadowType = shadowType;
 }
 public override ILightShadowMapShaderGroupData CreateShaderGroupData(LightShadowType shadowType)
 {
     return(new LightDirectionalShadowMapGroupShaderData(shadowType));
 }
 public ShaderGroupData(LightShadowType shadowType) : base(shadowType)
 {
 }
Пример #9
0
        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 override ILightShadowMapShaderGroupData CreateShaderGroupData(string compositionKey, LightShadowType shadowType, int maxLightCount)
 {
     return new LightDirectionalShadowMapGroupShaderData(compositionKey, shadowType, maxLightCount);
 }
Пример #11
0
        private ILightShadowMapShaderGroupData CreateShadowMapShaderGroupData(ILightShadowMapRenderer shadowRenderer, LightShadowType shadowType)
        {
            ILightShadowMapShaderGroupData shadowGroupData = shadowRenderer?.CreateShaderGroupData(shadowType);

            return(shadowGroupData);
        }
Пример #12
0
        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;)
            {
                // 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:
                LightShadowType         nextShadowType     = 0;
                ILightShadowMapRenderer nextShadowRenderer = 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 (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 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 ||
                    currentShadowType != nextShadowType ||
                    currentShadowRenderer != nextShadowRenderer) // TODO: Refactor this into a little structure instead.
                {
                    if (processedLights.Count > 0)
                    {
                        var lightGroupKey = new LightGroupKey(currentShadowRenderer, currentShadowType);
                        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
                    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();
        }
Пример #13
0
        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 *)&currentShaderKey);
                        }
                        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 *)&currentShaderKey);
                                }

                                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 *)&currentShaderKey);
                        }
                        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);
        }
Пример #14
0
        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 *)&currentShaderKey);
                        }
                        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 *)&currentShaderKey);
                                }

                                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 *)&currentShaderKey);
                        }
                        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 abstract ILightShadowMapShaderGroupData CreateShaderGroupData(string compositionKey, LightShadowType shadowType, int maxLightCount);
Пример #16
0
        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();
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="LightDirectionalShadowMapGroupShaderData" /> class.
 /// </summary>
 /// <param name="shadowType">Type of the shadow.</param>
 /// <param name="lightCountMax">The light count maximum.</param>
 public LightDirectionalShadowMapGroupShaderData(LightShadowType shadowType)
 {
     this.shadowType = shadowType;
     this.cascadeCount = 1 << ((int)(shadowType & LightShadowType.CascadeMask) - 1);
 }
 public LightForwardShaderEntryKey(byte lightRendererId, LightShadowType shadowType, byte lightCount)
 {
     LightRendererId = lightRendererId;
     ShadowType = shadowType;
     LightCount = lightCount;
 }
Пример #19
0
 public LightGroupKey(ILightShadowMapRenderer shadowRenderer, LightShadowType shadowType)
 {
     ShadowRenderer = shadowRenderer;
     ShadowType     = shadowType;
 }
Пример #20
0
 public LightForwardShaderEntryKey(byte lightRendererId, LightShadowType shadowType, byte lightCount)
 {
     LightRendererId = lightRendererId;
     ShadowType      = shadowType;
     LightCount      = lightCount;
 }
            /// <summary>
            /// Initializes a new instance of the <see cref="LightSpotShadowMapGroupShaderData" /> class.
            /// </summary>
            /// <param name="compositionKey">The composition key.</param>
            /// <param name="shadowType">Type of the shadow.</param>
            /// <param name="lightCountMax">The light count maximum.</param>
            public LightSpotShadowMapGroupShaderData(string compositionKey, LightShadowType shadowType, int lightCountMax)
            {
                this.shadowType = shadowType;
                worldToShadowCascadeUV = new Matrix[lightCountMax];
                depthBiases = new float[lightCountMax];
                offsetScales = new float[lightCountMax];

                var mixin = new ShaderMixinSource();
                mixin.Mixins.Add(new ShaderClassSource(ShaderName,lightCountMax, (this.shadowType & LightShadowType.Debug) != 0));
                // TODO: Temporary passing filter here

                switch (shadowType & LightShadowType.FilterMask)
                {
                    case LightShadowType.PCF3x3:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 3));
                        break;
                    case LightShadowType.PCF5x5:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 5));
                        break;
                    case LightShadowType.PCF7x7:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 7));
                        break;
                    default:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterDefault"));
                        break;
                }

                shadowShader = mixin;
                shadowMapTextureKey = ShadowMapKeys.Texture.ComposeWith(compositionKey);
                shadowMapTextureSizeKey = ShadowMapKeys.TextureSize.ComposeWith(compositionKey);
                shadowMapTextureTexelSizeKey = ShadowMapKeys.TextureTexelSize.ComposeWith(compositionKey);
                worldToShadowCascadeUVsKey = ShadowMapReceiverBaseKeys.WorldToShadowCascadeUV.ComposeWith(compositionKey);
                depthBiasesKey = ShadowMapReceiverBaseKeys.DepthBiases.ComposeWith(compositionKey);
                offsetScalesKey = ShadowMapReceiverBaseKeys.OffsetScales.ComposeWith(compositionKey);
            }
Пример #22
0
        private ILightShadowMapShaderGroupData CreateShadowMapShaderGroupData(ILightShadowMapRenderer shadowRenderer, LightShadowType shadowType)
        {
            ILightShadowMapShaderGroupData shadowGroupData = null;

            if (shadowRenderer != null)
            {
                shadowGroupData = shadowRenderer.CreateShaderGroupData(shadowType);
            }

            return(shadowGroupData);
        }
Пример #23
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LightSpotShadowMapGroupShaderData" /> class.
 /// </summary>
 /// <param name="shadowType">Type of the shadow.</param>
 /// <param name="lightCountMax">The light count maximum.</param>
 public LightSpotShadowMapGroupShaderData(LightShadowType shadowType)
 {
     this.shadowType = shadowType;
 }
Пример #24
0
 public override ILightShadowMapShaderGroupData CreateShaderGroupData(LightShadowType shadowType)
 {
     return new LightSpotShadowMapGroupShaderData(shadowType);
 }
Пример #25
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LightSpotShadowMapGroupShaderData" /> class.
 /// </summary>
 /// <param name="shadowType">Type of the shadow.</param>
 /// <param name="lightCountMax">The light count maximum.</param>
 public LightSpotShadowMapGroupShaderData(LightShadowType shadowType) : base(shadowType)
 {
 }
            /// <summary>
            /// Initializes a new instance of the <see cref="LightDirectionalShadowMapGroupShaderData" /> class.
            /// </summary>
            /// <param name="compositionKey">The composition key.</param>
            /// <param name="shadowType">Type of the shadow.</param>
            /// <param name="lightCountMax">The light count maximum.</param>
            public LightDirectionalShadowMapGroupShaderData(string compositionKey, LightShadowType shadowType, int lightCountMax)
            {
                this.shadowType = shadowType;
                this.cascadeCount = 1 << ((int)(shadowType & LightShadowType.CascadeMask) - 1);
                cascadeSplits = new float[cascadeCount * lightCountMax];
                worldToShadowCascadeUV = new Matrix[cascadeCount * lightCountMax];
                depthBiases = new float[lightCountMax];
                offsetScales = new float[lightCountMax];

                var mixin = new ShaderMixinSource();
                var isDepthRangeAuto = (this.shadowType & LightShadowType.DepthRangeAuto) != 0;
                mixin.Mixins.Add(new ShaderClassSource(ShaderName, cascadeCount, lightCountMax, (this.shadowType & LightShadowType.BlendCascade) != 0 && !isDepthRangeAuto, isDepthRangeAuto, (this.shadowType & LightShadowType.Debug) != 0));
                // TODO: Temporary passing filter here

                switch (shadowType & LightShadowType.FilterMask)
                {
                    case LightShadowType.PCF3x3:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 3));
                        break;
                    case LightShadowType.PCF5x5:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 5));
                        break;
                    case LightShadowType.PCF7x7:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterPcf", 7));
                        break;
                    default:
                        mixin.Mixins.Add(new ShaderClassSource("ShadowMapFilterDefault"));
                        break;
                }

                shadowShader = mixin;
                shadowMapTextureKey = ShadowMapKeys.Texture.ComposeWith(compositionKey);
                shadowMapTextureSizeKey = ShadowMapKeys.TextureSize.ComposeWith(compositionKey);
                shadowMapTextureTexelSizeKey = ShadowMapKeys.TextureTexelSize.ComposeWith(compositionKey);
                cascadeSplitsKey = ShadowMapReceiverDirectionalKeys.CascadeDepthSplits.ComposeWith(compositionKey);
                worldToShadowCascadeUVsKey = ShadowMapReceiverBaseKeys.WorldToShadowCascadeUV.ComposeWith(compositionKey);
                depthBiasesKey = ShadowMapReceiverBaseKeys.DepthBiases.ComposeWith(compositionKey);
                offsetScalesKey = ShadowMapReceiverBaseKeys.OffsetScales.ComposeWith(compositionKey);
            }
 /// <summary>
 /// Initializes a new instance of the <see cref="ShaderGroupData" /> class.
 /// </summary>
 /// <param name="shadowType">Type of the shadow.</param>
 /// <param name="lightCountMax">The light count maximum.</param>
 public ShaderGroupData(LightShadowType shadowType) : base(shadowType)
 {
     cascadeCount = 1 << ((int)(shadowType & LightShadowType.CascadeMask) - 1);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="LightDirectionalShadowMapGroupShaderData" /> class.
 /// </summary>
 /// <param name="shadowType">Type of the shadow.</param>
 /// <param name="lightCountMax">The light count maximum.</param>
 public LightDirectionalShadowMapGroupShaderData(LightShadowType shadowType)
 {
     this.shadowType   = shadowType;
     this.cascadeCount = 1 << ((int)(shadowType & LightShadowType.CascadeMask) - 1);
 }
 public LightShadowMapShaderGroupDataBase(LightShadowType shadowType)
 {
     ShadowType = shadowType;
 }
Пример #30
0
 public abstract ILightShadowMapShaderGroupData CreateShaderGroupData(string compositionKey, LightShadowType shadowType, int maxLightCount);
 public abstract ILightShadowMapShaderGroupData CreateShaderGroupData(LightShadowType shadowType);
 public override ILightShadowMapShaderGroupData CreateShaderGroupData(LightShadowType shadowType)
 {
     return(new ShaderGroupData(shadowType));
 }
 public abstract ILightShadowMapShaderGroupData CreateShaderGroupData(LightShadowType shadowType);