public void CollectVoxelizationPasses(ProcessedVoxelVolume data, VoxelStorageContext storageContext)
        {
            Matrix BaseVoxelMatrix = storageContext.Matrix;

            BaseVoxelMatrix.Invert();
            BaseVoxelMatrix = BaseVoxelMatrix * Matrix.Scaling(2f, 2f, 2f);
            if (UpdatesPerFrame != UpdateMethods.AllClipmapsMultipleRenders)
            {
                /*
                 * Having trouble with shadow culling when this is enabled - currently performed in vertex shader instead
                 * if (UpdateMethod == UpdateMethods.OneClipPerFrame)
                 * {
                 *  BaseVoxelMatrix = Matrix.Scaling(PerMapOffsetScale[ClipMapCurrent].W) * Matrix.Translation(PerMapOffsetScale[ClipMapCurrent].XYZ());
                 *  BaseVoxelMatrix = BaseVoxelMatrix * Matrix.Translation(-0.5f,-0.5f,-0.5f);
                 *  BaseVoxelMatrix = BaseVoxelMatrix * Matrix.Scaling(2f, 2f, 2f);
                 * }
                 */
                VoxelStorerClipmap Storer = new VoxelStorerClipmap
                {
                    storageUints      = storageUints,
                    FragmentsBuffer   = FragmentsBuffer,
                    ClipMapCount      = ClipMapCount,
                    ClipMapCurrent    = ClipMapCurrent,
                    ClipMapResolution = ClipMapResolution,
                    PerMapOffsetScale = PerMapOffsetScale,
                    UpdatesPerFrame   = UpdatesPerFrame
                };
                foreach (var attr in data.Attributes)
                {
                    attr.Attribute.CollectVoxelizationPasses(data.passList, Storer, BaseVoxelMatrix, ClipMapResolution, attr.Stage, attr.Output);
                }
            }
            if (UpdatesPerFrame == UpdateMethods.AllClipmapsMultipleRenders)
            {
                for (int i = 0; i < ClipMapCount; i++)
                {
                    VoxelStorerClipmap Storer = new VoxelStorerClipmap
                    {
                        storageUints      = storageUints,
                        FragmentsBuffer   = FragmentsBuffer,
                        ClipMapCount      = ClipMapCount,
                        ClipMapCurrent    = i,
                        ClipMapResolution = ClipMapResolution,
                        PerMapOffsetScale = PerMapOffsetScale,
                        UpdatesPerFrame   = UpdateMethods.SingleClipmap
                    };
                    foreach (var attr in data.Attributes)
                    {
                        attr.Attribute.CollectVoxelizationPasses(data.passList, Storer, BaseVoxelMatrix, ClipMapResolution, attr.Stage, attr.Output);
                    }
                }
            }
        }
Exemple #2
0
        public ShaderSource GetVoxelizationShader(VoxelizationPass pass, ProcessedVoxelVolume data)
        {
            bool              singleClip = UpdatesOneClipPerFrame();
            ShaderSource      VoxelizationMethodSource = pass.method.GetVoxelizationShader();
            ShaderMixinSource cachedMixin = new ShaderMixinSource();

            cachedMixin.Mixins.Add(storage);
            cachedMixin.AddComposition("method", VoxelizationMethodSource);
            if (singleClip)
            {
                cachedMixin.AddMacro("singleClip", true);
            }

            string IndirectStoreMacro = "";

            for (int i = 0; i < pass.AttributesIndirect.Count; i++)
            {
                string iStr = i.ToString();
                IndirectStoreMacro += $"AttributesIndirect[{iStr}].IndirectWrite(fragmentsBuffer, writeindex + {pass.AttributesIndirect[i].BufferOffset});\n";
            }

            cachedMixin.AddMacro("IndirectStoreMacro", IndirectStoreMacro);

            foreach (var attr in pass.AttributesTemp)
            {
                cachedMixin.AddCompositionToArray("AttributesTemp", attr.GetVoxelizationShader());
            }

            foreach (var attr in pass.AttributesDirect)
            {
                cachedMixin.AddCompositionToArray("AttributesDirect", attr.GetVoxelizationShader());
            }

            foreach (var attr in pass.AttributesIndirect)
            {
                cachedMixin.AddCompositionToArray("AttributesIndirect", attr.GetVoxelizationShader());
            }

            return(cachedMixin);
        }
Exemple #3
0
        public virtual void Collect(RenderContext Context, Shadows.IShadowMapRenderer ShadowMapRenderer)
        {
            renderVoxelVolumes    = Context.VisibilityGroup.Tags.Get(CurrentRenderVoxelVolumes);
            renderVoxelVolumeData = Context.VisibilityGroup.Tags.Get(CurrentProcessedVoxelVolumes);

            if (renderVoxelVolumes == null || renderVoxelVolumes.Count == 0)
            {
                return;
            }

            if (Context.RenderSystem.GraphicsDevice.Features.CurrentProfile < GraphicsProfile.Level_11_0)
            {
                throw new ArgumentOutOfRangeException("Graphics Profile Level 11 or higher required for Voxelization.");
            }

            //Setup per volume passes and texture allocations
            foreach (var pair in renderVoxelVolumes)
            {
                var dataVolume = pair.Value;
                var bounds     = dataVolume.VolumeSize;

                ProcessedVoxelVolume processedVolume;
                if (!renderVoxelVolumeData.TryGetValue(pair.Key, out processedVolume))
                {
                    processedVolume = new ProcessedVoxelVolume();
                    renderVoxelVolumeData.Add(pair.Key, processedVolume);
                }


                //Setup matrix
                Vector3 matScale = dataVolume.VolumeSize;
                Vector3 matTrans = dataVolume.VolumeTranslation;

                Matrix corMatrix = Matrix.Scaling(matScale) * Matrix.Translation(matTrans);
                VoxelStorageContext storageContext = new VoxelStorageContext
                {
                    device    = Context.GraphicsDevice,
                    Extents   = bounds,
                    VoxelSize = dataVolume.AproxVoxelSize,
                    Matrix    = corMatrix
                };

                if (dataVolume.VoxelGridSnapping)
                {
                    matTrans  /= storageContext.RealVoxelSize();
                    matTrans.X = MathF.Floor(matTrans.X);
                    matTrans.Y = MathF.Floor(matTrans.Y);
                    matTrans.Z = MathF.Floor(matTrans.Z);
                    matTrans  *= storageContext.RealVoxelSize();

                    corMatrix             = Matrix.Scaling(matScale) * Matrix.Translation(matTrans);
                    storageContext.Matrix = corMatrix;
                }
                storageContext.Translation           = matTrans;
                storageContext.VoxelSpaceTranslation = matTrans / storageContext.RealVoxelSize();

                //Update storage
                dataVolume.Storage.UpdateFromContext(storageContext);

                //Transfer voxelization info
                processedVolume.VisualizeVoxels        = dataVolume.VisualizeVoxels;
                processedVolume.Storage                = dataVolume.Storage;
                processedVolume.StorageContext         = storageContext;
                processedVolume.VoxelizationMethod     = dataVolume.VoxelizationMethod;
                processedVolume.VoxelVisualization     = dataVolume.VoxelVisualization;
                processedVolume.VisualizationAttribute = dataVolume.VisualizationAttribute;
                processedVolume.Voxelize               = dataVolume.Voxelize;
                processedVolume.OutputAttributes       = dataVolume.Attributes;

                processedVolume.Attributes.Clear();
                processedVolume.passList.Clear();
                processedVolume.groupedPasses.Clear();

                processedVolume.passList.defaultVoxelizationMethod = dataVolume.VoxelizationMethod;


                //Create final list of attributes (including temporary ones)
                foreach (var attr in dataVolume.Attributes)
                {
                    attr.CollectAttributes(processedVolume.Attributes, VoxelizationStage.Initial, true);
                }

                //Allocate textures and space in the temporary buffer
                foreach (var attr in processedVolume.Attributes)
                {
                    attr.Attribute.PrepareLocalStorage(storageContext, dataVolume.Storage);
                    if (attr.Output)
                    {
                        attr.Attribute.PrepareOutputStorage(storageContext, dataVolume.Storage);
                    }
                    else
                    {
                        attr.Attribute.ClearOutputStorage();
                    }
                }
                dataVolume.Storage.UpdateTempStorage(storageContext);

                //Create list of voxelization passes that need to be done
                dataVolume.Storage.CollectVoxelizationPasses(processedVolume, storageContext);

                //Group voxelization passes where the RenderStage can be shared
                //TODO: Group identical attributes
                for (int i = 0; i < processedVolume.passList.passes.Count; i++)
                {
                    bool added = false;
                    var  passA = processedVolume.passList.passes[i];
                    for (int group = 0; group < processedVolume.groupedPasses.Count; group++)
                    {
                        var passB = processedVolume.groupedPasses[group][0];
                        if (
                            passB.storer.CanShareRenderStage(passA.storer) &&
                            passB.method.CanShareRenderStage(passA.method) &&
                            passB.AttributesDirect.SequenceEqual(passA.AttributesDirect) &&
                            passB.AttributesIndirect.SequenceEqual(passA.AttributesIndirect) &&
                            passB.AttributesTemp.SequenceEqual(passA.AttributesTemp)
                            )
                        {
                            processedVolume.groupedPasses[group].Add(passA);
                            added = true;
                            break;
                        }
                    }
                    if (!added)
                    {
                        List <VoxelizationPass> newGroup = new List <VoxelizationPass>
                        {
                            passA
                        };
                        processedVolume.groupedPasses.Add(newGroup);
                    }
                }

                if (VoxelStages.Count < processedVolume.groupedPasses.Count)
                {
                    throw new ArgumentOutOfRangeException(processedVolume.groupedPasses.Count.ToString() + " Render Stages required for voxelization, only " + VoxelStages.Count.ToString() + " provided.");
                }

                //Finish preparing the passes, collecting views and setting up shader sources and shadows
                for (int group = 0; group < processedVolume.groupedPasses.Count; group++)
                {
                    foreach (var pass in processedVolume.groupedPasses[group])
                    {
                        pass.renderStage = VoxelStages[group];
                        pass.source      = pass.storer.GetVoxelizationShader(pass, processedVolume);
                        pass.view.RenderStages.Add(pass.renderStage);

                        Context.RenderSystem.Views.Add(pass.view);
                        Context.VisibilityGroup.TryCollect(pass.view);

                        if (pass.requireShadows)
                        {
                            ShadowMapRenderer?.RenderViewsWithShadows.Add(pass.view);
                        }
                    }
                }
            }
        }
Exemple #4
0
 public void PostProcess(VoxelStorageContext context, RenderDrawContext drawContext, ProcessedVoxelVolume data)
 {
 }
        public void PostProcess(VoxelStorageContext storageContext, RenderDrawContext drawContext, ProcessedVoxelVolume data)
        {
            if (Math.Max(Math.Max(ClipMapResolution.X, ClipMapResolution.Y), ClipMapResolution.Z) < 32)
            {
                return;
            }
            if (FragmentsBuffer == null)
            {
                return;
            }
            var context = drawContext.RenderContext;

            if (ClearBuffer == null)
            {
                ClearBuffer = new Stride.Rendering.ComputeEffect.ComputeEffectShader(context)
                {
                    ShaderSourceName = "ClearBuffer"
                };
                BufferToTexture = new Stride.Rendering.ComputeEffect.ComputeEffectShader(context)
                {
                    ShaderSourceName = "BufferToTextureEffect"
                };
                BufferToTextureColumns = new Stride.Rendering.ComputeEffect.ComputeEffectShader(context)
                {
                    ShaderSourceName = "BufferToTextureColumnsEffect"
                };
            }

            bool VoxelsAreIndependent = true;

            List <VoxelAttribute>  IndirectVoxels = new List <VoxelAttribute>();
            List <VoxelAttribute>  TempVoxels     = new List <VoxelAttribute>();
            ShaderSourceCollection Indirect       = new ShaderSourceCollection();
            ShaderSourceCollection Temp           = new ShaderSourceCollection();

            //Assign sample indices and check whether voxels can be calculated independently
            int sampleIndex = 0;

            foreach (var attr in data.Attributes)
            {
                attr.Attribute.LocalSamplerID = sampleIndex;
                VoxelsAreIndependent         &= !attr.Attribute.RequiresColumns();
                sampleIndex++;
            }

            //Populate ShaderSourceCollections and temp lists
            foreach (var attr in data.Attributes)
            {
                if (attr.Stage != VoxelizationStage.Post)
                {
                    continue;
                }
                if (attr.Output)
                {
                    Indirect.Add(attr.Attribute.GetVoxelizationShader());
                    IndirectVoxels.Add(attr.Attribute);
                }
                else
                {
                    Temp.Add(attr.Attribute.GetVoxelizationShader());
                    TempVoxels.Add(attr.Attribute);
                }
            }

            var BufferWriter = VoxelsAreIndependent ? BufferToTexture : BufferToTextureColumns;

            for (int i = 0; i < IndirectVoxels.Count; i++)
            {
                var attr = IndirectVoxels[i];
                attr.UpdateVoxelizationLayout($"AttributesIndirect[{i}]");
            }
            for (int i = 0; i < TempVoxels.Count; i++)
            {
                var attr = TempVoxels[i];
                attr.UpdateVoxelizationLayout($"AttributesTemp[{i}]");
            }
            foreach (var attr in data.Attributes)
            {
                attr.Attribute.ApplyVoxelizationParameters(BufferWriter.Parameters);
            }


            int processYSize = VoxelsAreIndependent ? (int)ClipMapResolution.Y : 1;

            processYSize *= (UpdatesPerFrame == UpdateMethods.SingleClipmap) ? 1 : ClipMapCount;

            BufferWriter.ThreadGroupCounts = VoxelsAreIndependent ? new Int3(32, 32, 32) : new Int3(32, 1, 32);
            BufferWriter.ThreadNumbers     = new Int3((int)ClipMapResolution.X / BufferWriter.ThreadGroupCounts.X, processYSize / BufferWriter.ThreadGroupCounts.Y, (int)ClipMapResolution.Z / BufferWriter.ThreadGroupCounts.Z);

            BufferWriter.Parameters.Set(BufferToTextureKeys.VoxelFragments, FragmentsBuffer);
            BufferWriter.Parameters.Set(BufferToTextureKeys.clipMapResolution, ClipMapResolution);
            BufferWriter.Parameters.Set(BufferToTextureKeys.storageUints, storageUints);

            BufferWriter.Parameters.Set(BufferToTextureKeys.clipOffset, (uint)(UpdatesPerFrame == UpdateMethods.SingleClipmap ? ClipMapCurrent : 0));


            //Modifiers are stored within attributes, yet need to be able to query their results.
            //Ideally a stage stream could resolve this, however due to the lack of pointers, there would be a cyclic dependency of AttributesList->Attribute->Modifier->AttributesList->...
            //So instead the results will be stored within a second array that only contains float4s. Unfortunately the only way to iterate through the AttributesList is by foreach, which
            //makes it difficult to access the results array (AttributeLocalSamples) by index. So instead it's just all done through this macro...
            string IndirectReadAndStoreMacro = "";
            string IndirectStoreMacro        = "";

            for (int i = 0; i < Temp.Count; i++)
            {
                string iStr           = i.ToString();
                string sampleIndexStr = TempVoxels[i].LocalSamplerID.ToString();
                IndirectReadAndStoreMacro += $"AttributesTemp[{iStr}].InitializeFromBuffer(VoxelFragments, VoxelFragmentsIndex + {TempVoxels[i].BufferOffset}, uint2({TempVoxels[i].BufferOffset} + initialVoxelFragmentsIndex, yStride));\n" +
                                             $"streams.LocalSample[{sampleIndexStr}] = AttributesTemp[{iStr}].SampleLocal();\n\n";
                IndirectStoreMacro += $"streams.LocalSample[{sampleIndexStr}] = AttributesTemp[{iStr}].SampleLocal();\n";
            }
            for (int i = 0; i < Indirect.Count; i++)
            {
                string iStr           = i.ToString();
                string sampleIndexStr = IndirectVoxels[i].LocalSamplerID.ToString();
                IndirectReadAndStoreMacro += $"AttributesIndirect[{iStr}].InitializeFromBuffer(VoxelFragments, VoxelFragmentsIndex + {IndirectVoxels[i].BufferOffset}, uint2({IndirectVoxels[i].BufferOffset} + initialVoxelFragmentsIndex, yStride));\n" +
                                             $"streams.LocalSample[{sampleIndexStr}] = AttributesIndirect[{iStr}].SampleLocal();\n\n";
                IndirectStoreMacro += $"streams.LocalSample[{sampleIndexStr}] = AttributesIndirect[{iStr}].SampleLocal();\n";
            }



            BufferWriter.Parameters.Set(BufferToTextureKeys.AttributesIndirect, Indirect);
            BufferWriter.Parameters.Set(BufferToTextureKeys.AttributesTemp, Temp);
            BufferWriter.Parameters.Set(BufferToTextureKeys.IndirectReadAndStoreMacro, IndirectReadAndStoreMacro);
            BufferWriter.Parameters.Set(BufferToTextureKeys.IndirectStoreMacro, IndirectStoreMacro);

            ((RendererBase)BufferWriter).Draw(drawContext);



            ClearBuffer.Parameters.Set(ClearBufferKeys.buffer, FragmentsBuffer);

            if (UpdatesPerFrame != UpdateMethods.SingleClipmap)
            {
                //Clear all
                ClearBuffer.ThreadNumbers     = new Int3(1024, 1, 1);
                ClearBuffer.ThreadGroupCounts = new Int3(FragmentsBuffer.ElementCount / 1024, 1, 1);
                ClearBuffer.Parameters.Set(ClearBufferKeys.offset, 0);
            }
            else
            {
                //Clear next clipmap buffer
                ClearBuffer.ThreadNumbers     = new Int3(1024, 1, 1);
                ClearBuffer.ThreadGroupCounts = new Int3((int)(ClipMapResolution.X * ClipMapResolution.Y * ClipMapResolution.Z * storageUints) / 1024, 1, 1);
                ClearBuffer.Parameters.Set(ClearBufferKeys.offset, (int)(((ClipMapCurrent + 1) % ClipMapCount) * ClipMapResolution.X * ClipMapResolution.Y * ClipMapResolution.Z * storageUints));
            }
            ((RendererBase)ClearBuffer).Draw(drawContext);
        }