public void UpdateTexture(VoxelStorageContext context, ref IVoxelStorageTexture texture, Stride.Graphics.PixelFormat pixelFormat, int LayoutSize) { VoxelStorageTextureClipmap clipmap = texture as VoxelStorageTextureClipmap; if (clipmap == null) { 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 = Stride.Graphics.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 = Stride.Graphics.Texture.New3D(context.device, (int)MipMapResolution.X, (int)MipMapResolution.Y, (int)MipMapResolution.Z, new MipMapCount(true), pixelFormat, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess); clipmap.TempMipMaps = new Stride.Graphics.Texture[MipMapCount]; for (int i = 0; i < clipmap.TempMipMaps.Length; i++) { clipmap.TempMipMaps[i] = Stride.Graphics.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 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 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; } }