public void UpdateTempStorage(VoxelStorageContext context) { storageUints = (tempStorageCounter + 31) / 32; tempStorageCounter = 0; var resolution = ClipMapResolution; int fragments = (int)(resolution.X * resolution.Y * resolution.Z) * ClipMapCount; if (VoxelUtils.DisposeBufferBySpecs(FragmentsBuffer, storageUints * fragments) && storageUints * fragments > 0) { FragmentsBuffer = Stride.Graphics.Buffer.Typed.New(context.device, storageUints * fragments, PixelFormat.R32_UInt, true); } }
public void UpdateTexture(VoxelStorageContext context, ref IVoxelStorageTexture texture, Stride.Graphics.PixelFormat pixelFormat, int LayoutSize) { if (texture is not VoxelStorageTextureClipmap clipmap) { clipmap = new VoxelStorageTextureClipmap(); } Vector3 ClipMapTextureResolution = new Vector3(ClipMapResolution.X, ClipMapResolution.Y * ClipMapCount * LayoutSize, ClipMapResolution.Z); Vector3 MipMapResolution = new Vector3(ClipMapResolution.X / 2, ClipMapResolution.Y / 2 * LayoutSize, ClipMapResolution.Z / 2); if (VoxelUtils.DisposeTextureBySpecs(clipmap.ClipMaps, ClipMapTextureResolution, pixelFormat)) { clipmap.ClipMaps = Texture.New3D(context.device, (int)ClipMapTextureResolution.X, (int)ClipMapTextureResolution.Y, (int)ClipMapTextureResolution.Z, new MipMapCount(false), pixelFormat, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess); } if (VoxelUtils.DisposeTextureBySpecs(clipmap.MipMaps, MipMapResolution, pixelFormat)) { if (clipmap.TempMipMaps != null) { for (int i = 0; i < clipmap.TempMipMaps.Length; i++) { clipmap.TempMipMaps[i].Dispose(); } } Vector3 MipMapResolutionMax = MipMapResolution; clipmap.MipMaps = Texture.New3D(context.device, (int)MipMapResolution.X, (int)MipMapResolution.Y, (int)MipMapResolution.Z, new MipMapCount(true), pixelFormat, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess); clipmap.TempMipMaps = new Texture[MipMapCount]; for (int i = 0; i < clipmap.TempMipMaps.Length; i++) { clipmap.TempMipMaps[i] = Texture.New3D(context.device, (int)MipMapResolutionMax.X, (int)MipMapResolutionMax.Y, (int)MipMapResolutionMax.Z, false, pixelFormat, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess); MipMapResolutionMax /= 2; } } clipmap.DownsampleFinerClipMaps = DownsampleFinerClipMaps; clipmap.ClipMapResolution = ClipMapResolution; clipmap.ClipMapCount = ClipMapCount; clipmap.LayoutSize = LayoutSize; clipmap.VoxelSize = context.RealVoxelSize(); clipmap.VolumeTranslation = new Int3((int)context.VoxelSpaceTranslation.X, (int)context.VoxelSpaceTranslation.Y, (int)context.VoxelSpaceTranslation.Z); Array.Copy(MippingOffset, clipmap.MippingOffset, MippingOffset.Length); Array.Copy(PerMapOffsetScale, clipmap.PerMapOffsetScale, PerMapOffsetScale.Length); texture = clipmap; }
public void Render(VoxelStorageContext storageContext, RenderDrawContext drawContext, RenderView view) { RenderView voxelizationView = view; Int2 ViewSize = VoxelizationViewSizes[view]; if (VoxelUtils.DisposeTextureBySpecs(MSAARenderTarget, new Vector3(ViewSize.X, ViewSize.Y, 1), PixelFormat.R8G8B8A8_UNorm, MultisampleCount)) { MSAARenderTarget = Texture.New(storageContext.device, TextureDescription.New2D(ViewSize.X, ViewSize.Y, new MipMapCount(false), PixelFormat.R8G8B8A8_UNorm, TextureFlags.RenderTarget, 1, GraphicsResourceUsage.Default, MultisampleCount), null); } drawContext.CommandList.ResetTargets(); if (MSAARenderTarget != null) { drawContext.CommandList.SetRenderTarget(null, MSAARenderTarget); } var renderSystem = drawContext.RenderContext.RenderSystem; drawContext.CommandList.SetViewport(new Viewport(0, 0, ViewSize.X, ViewSize.Y)); renderSystem.Draw(drawContext, voxelizationView, renderSystem.RenderStages[voxelizationView.RenderStages[0].Index]); }
public abstract void PrepareOutputStorage(VoxelStorageContext context, IVoxelStorage storage);
public override void PrepareLocalStorage(VoxelStorageContext context, IVoxelStorage storage) { BufferOffset = storage.RequestTempStorage(32); }
public override void PrepareOutputStorage(VoxelStorageContext context, IVoxelStorage storage) { storage.UpdateTexture(context, ref CoverageTex, Graphics.PixelFormat.R11G11B10_Float, 1); }
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); } } } } }
public int PrepareLocalStorage(VoxelStorageContext context, IVoxelStorage storage, int channels, int layoutCount) { return(storage.RequestTempStorage(TempStorageFormat.GetBits(channels) * layoutCount)); }
public void Render(VoxelStorageContext storageContext, RenderDrawContext drawContext, RenderView view) { }
public virtual void Draw(RenderDrawContext drawContext, Shadows.IShadowMapRenderer ShadowMapRenderer) { if (renderVoxelVolumes == null || renderVoxelVolumes.Count == 0) { return; } if (drawContext.GraphicsDevice.Features.CurrentProfile < GraphicsProfile.Level_11_0) { return; } var context = drawContext; using (drawContext.PushRenderTargetsAndRestore()) { // Draw all shadow views generated for the current view foreach (var processedVolumeKeyValue in renderVoxelVolumeData) { var processedVolume = processedVolumeKeyValue.Value; if (!processedVolume.Voxelize) { continue; } VoxelStorageContext storageContext = processedVolume.StorageContext; using (drawContext.QueryManager.BeginProfile(Color.Black, PassesVoxelizationProfilingKey)) { foreach (VoxelizationPass pass in processedVolume.passList.passes) { RenderView voxelizeRenderView = pass.view; if (pass.requireShadows) { //Render Shadow Maps RenderView oldView = drawContext.RenderContext.RenderView; drawContext.RenderContext.RenderView = voxelizeRenderView; ShadowMapRenderer.Draw(drawContext); drawContext.RenderContext.RenderView = oldView; } //Render/Collect voxel fragments using (drawContext.QueryManager.BeginProfile(Color.Black, FragmentVoxelizationProfilingKey)) { using (drawContext.PushRenderTargetsAndRestore()) { pass.method.Render(storageContext, context, pass.view); } } } foreach (VoxelizationPass pass in processedVolume.passList.passes) { pass.method.Reset(); } } //Fill and write to voxel volume using (drawContext.QueryManager.BeginProfile(Color.Black, BufferProcessingVoxelizationProfilingKey)) { processedVolume.Storage.PostProcess(storageContext, context, processedVolume); } //Mipmap using (drawContext.QueryManager.BeginProfile(Color.Black, MipmappingVoxelizationProfilingKey)) { foreach (var attr in processedVolume.Attributes) { if (attr.Output) { attr.Attribute.PostProcess(context); } } } } } }
virtual public int PrepareLocalStorage(VoxelStorageContext context, IVoxelStorage storage) { return(StorageMethod.PrepareLocalStorage(context, storage, 4, LayoutCount)); }
virtual public void PrepareOutputStorage(VoxelStorageContext context, IVoxelStorage storage) { storage.UpdateTexture(context, ref storageTex, StorageFormatToPixelFormat(), LayoutCount); }
public abstract void PrepareLocalStorage(VoxelStorageContext context, IVoxelStorage storage);
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); }
public override void PrepareOutputStorage(VoxelStorageContext context, IVoxelStorage storage) { VoxelLayout.PrepareOutputStorage(context, storage); }
public override void PrepareLocalStorage(VoxelStorageContext context, IVoxelStorage storage) { BufferOffset = VoxelLayout.PrepareLocalStorage(context, storage); }
public override void PrepareOutputStorage(VoxelStorageContext context, IVoxelStorage storage) { storage.UpdateTexture(context, ref SolidityTex, Graphics.PixelFormat.R8_UNorm, 1); }
public void PostProcess(VoxelStorageContext context, RenderDrawContext drawContext, ProcessedVoxelVolume data) { }
public void UpdateFromContext(VoxelStorageContext context) { var virtualResolution = context.Resolution(); var largestDimension = (double)Math.Max(virtualResolution.X, Math.Max(virtualResolution.Y, virtualResolution.Z)); ClipMapCount = (int)Math.Log(largestDimension / Math.Min(largestDimension, (double)ClipResolution), 2) + 1; ClipMapCurrent++; if (ClipMapCurrent >= ClipMapCount) { ClipMapCurrent = 0; } float FinestClipMapScale = (float)Math.Pow(2, ClipMapCount - 1); ClipMapResolution = new Vector3(virtualResolution.X, virtualResolution.Y, virtualResolution.Z) / FinestClipMapScale; MipMapCount = (int)Math.Floor(Math.Log(Math.Min(ClipMapResolution.X, Math.Min(ClipMapResolution.Y, ClipMapResolution.Z)), 2)); int voxelScale = 1; for (int i = 0; i < (ClipMapCount + MipMapCount); i++) { Vector3 SnappedVolumeTranslation = context.VoxelSpaceTranslation; SnappedVolumeTranslation.X = MathF.Floor(SnappedVolumeTranslation.X / voxelScale) * voxelScale; SnappedVolumeTranslation.Y = MathF.Floor(SnappedVolumeTranslation.Y / voxelScale) * voxelScale; SnappedVolumeTranslation.Z = MathF.Floor(SnappedVolumeTranslation.Z / voxelScale) * voxelScale; if (ShouldUpdateClipIndex(i)) { PerMapSnappingOffset[i] = -SnappedVolumeTranslation *context.RealVoxelSize(); MippingOffsetTranslation[i] = new Int3((int)SnappedVolumeTranslation.X, (int)SnappedVolumeTranslation.Y, (int)SnappedVolumeTranslation.Z); } voxelScale *= 2; } float extentScale = (float)Math.Pow(2f, ClipMapCount - 1); voxelScale = 1; for (int i = 0; i < (ClipMapCount + MipMapCount); i++) { if (ShouldUpdateClipIndex(i)) { Vector3 offset = (PerMapSnappingOffset[i]) * extentScale / context.Extents + 0.5f; PerMapOffsetScale[i] = new Vector4(offset, (1.0f / context.Extents.X) * extentScale); } if (i + 1 == ClipMapCurrent || ShouldUpdateClipIndex(i)) { MippingOffset[i] = (Vector3)((MippingOffsetTranslation[i] - MippingOffsetTranslation[i + 1]) / voxelScale); } if (i < ClipMapCount - 1) { extentScale /= 2; } voxelScale *= 2; } }