protected override void DrawCore(RenderDrawContext context) { var output = GetOutput(context.RenderContext); if (output != null) { try { // TODO GRAPHICS REFACTOR //context.PushParameters(Parameters); ActivateOutput(context); DrawCore(context, output); } finally { // TODO GRAPHICS REFACTOR //context.PopParameters(); if (ResetGraphicsStates) { // Make sure that states are clean after this rendering // TODO GRAPHICS REFACTOR //context.GraphicsDevice.ResetStates(); } } } }
public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { lock (drawLock) { DrawInternal(context, renderView, renderViewStage, startIndex, endIndex); } }
protected override void LoadContent() { var assetManager = Services.GetSafeServiceAs<ContentManager>(); var graphicsContext = Services.GetSafeServiceAs<GraphicsContext>(); // Preload the scene if it exists if (InitialSceneUrl != null && assetManager.Exists(InitialSceneUrl)) { SceneInstance = new SceneInstance(Services, assetManager.Load<Scene>(InitialSceneUrl)); } if (MainRenderFrame == null) { // TODO GRAPHICS REFACTOR Check if this is a good idea to use Presenter targets MainRenderFrame = RenderFrame.FromTexture(GraphicsDevice.Presenter?.BackBuffer, GraphicsDevice.Presenter?.DepthStencilBuffer); if (MainRenderFrame != null) { previousWidth = MainRenderFrame.Width; previousHeight = MainRenderFrame.Height; } } // Create the drawing context renderContext = RenderContext.GetShared(Services); renderDrawContext = new RenderDrawContext(Services, renderContext, graphicsContext); }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutationsImpl(RenderDrawContext context) { var renderEffects = RenderData.GetData(RenderEffectKey); foreach (var renderObject in RenderObjects) { var staticObjectNode = renderObject.StaticObjectNode; for (int i = 0; i < EffectPermutationSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * EffectPermutationSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; var renderSkybox = (RenderSkybox)renderObject; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) continue; var parameters = renderSkybox.Background == SkyboxBackground.Irradiance ? renderSkybox.Skybox.DiffuseLightingParameters : renderSkybox.Skybox.Parameters; var shader = parameters.Get(SkyboxKeys.Shader); if (shader == null) { renderEffect.EffectValidator.ShouldSkip = true; } renderEffect.EffectValidator.ValidateParameter(SkyboxKeys.Shader, shader); } } transformRenderFeature.PrepareEffectPermutations(context); }
protected override void DrawCore(RenderDrawContext context) { if (string.IsNullOrEmpty(ShaderSourceName)) return; Parameters.Set(ComputeEffectShaderKeys.ThreadNumbers, ThreadNumbers); Parameters.Set(ComputeEffectShaderKeys.ComputeShaderName, ShaderSourceName); Parameters.Set(ComputeShaderBaseKeys.ThreadGroupCountGlobal, ThreadGroupCounts); if (EffectInstance.UpdateEffect(GraphicsDevice) || pipelineStateDirty || previousBytecode != EffectInstance.Effect.Bytecode) { // The EffectInstance might have been updated from outside previousBytecode = EffectInstance.Effect.Bytecode; pipelineState.State.SetDefaults(); pipelineState.State.RootSignature = EffectInstance.RootSignature; pipelineState.State.EffectBytecode = EffectInstance.Effect.Bytecode; pipelineState.Update(); pipelineStateDirty = false; } // Apply pipeline state context.CommandList.SetPipelineState(pipelineState.CurrentState); // Apply the effect EffectInstance.Apply(context.GraphicsContext); // Draw a full screen quad context.CommandList.Dispatch(ThreadGroupCounts.X, ThreadGroupCounts.Y, ThreadGroupCounts.Z); // Un-apply //throw new InvalidOperationException(); //EffectInstance.Effect.UnbindResources(GraphicsDevice); }
/// <inheritdoc/> public override void PrepareEffectPermutations(RenderDrawContext context) { var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; foreach (var renderObject in RootRenderFeature.RenderObjects) { var staticObjectNode = renderObject.StaticObjectNode; var renderMesh = (RenderMesh)renderObject; for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) continue; // Generate shader permuatations renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableBend, renderMesh.Mesh.Parameters.Get(GameParameters.EnableBend)); renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableFog, renderMesh.Mesh.Parameters.Get(GameParameters.EnableFog)); renderEffect.EffectValidator.ValidateParameter(GameParameters.EnableOnflyTextureUVChange, renderMesh.Mesh.Parameters.Get(GameParameters.EnableOnflyTextureUVChange)); } } }
protected override void PreDrawCore(RenderDrawContext context) { base.PreDrawCore(context); // Default handler for parameters UpdateParameters(); }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutations(RenderDrawContext context) { var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; foreach (var renderObject in RootRenderFeature.RenderObjects) { var staticObjectNode = renderObject.StaticObjectNode; for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; var renderMesh = (RenderMesh)renderObject; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) continue; if (renderMesh.Mesh.Skinning != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningPosition, renderMesh.Mesh.Parameters.Get(MaterialKeys.HasSkinningPosition)); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningNormal, renderMesh.Mesh.Parameters.Get(MaterialKeys.HasSkinningNormal)); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningTangent, renderMesh.Mesh.Parameters.Get(MaterialKeys.HasSkinningTangent)); var skinningBones = Math.Max(MaxBones, renderMesh.Mesh.Skinning.Bones.Length); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.SkinningMaxBones, skinningBones); } } } }
protected override void DrawCore(RenderDrawContext context, RenderFrame output) { var commandList = context.CommandList; // clear the targets if (output.DepthStencil != null && (ClearFlags == ClearRenderFrameFlags.ColorAndDepth || ClearFlags == ClearRenderFrameFlags.DepthOnly)) { const DepthStencilClearOptions ClearOptions = DepthStencilClearOptions.DepthBuffer | DepthStencilClearOptions.Stencil; commandList.Clear(output.DepthStencil, ClearOptions, Depth, Stencil); } if (ClearFlags == ClearRenderFrameFlags.ColorAndDepth || ClearFlags == ClearRenderFrameFlags.ColorOnly) { foreach (var renderTarget in output.RenderTargets) { if (renderTarget != null) { // If color is in GammeSpace and rendertarget is either SRgb or HDR, use a linear value to clear the buffer. // TODO: We will need to move this color transform code to a shareable component var color = Color.ToColorSpace(ColorSpace, (renderTarget.Format.IsSRgb() || renderTarget.Format.IsHDR()) ? ColorSpace.Linear : context.GraphicsDevice.ColorSpace); commandList.Clear(renderTarget, color); } } } }
protected override void DrawCore(RenderDrawContext context) { using (context.RenderContext.PushTagAndRestore(SceneCameraSlotCollection.Current, Cameras)) { base.DrawCore(context); } }
protected override void DrawCore(RenderDrawContext context, RenderFrame output) { var input = Input.GetSafeRenderFrame(context.RenderContext); // If RenderFrame input or output are null, we can't do anything if (input == null) { return; } // If an effect is set, we are using it if (Effect != null) { Effect.SetInput(0, input); if (input.DepthStencil != null) { Effect.SetInput(1, input.DepthStencil); } Effect.SetOutput(output); Effect.Draw(context); } else if (input != output) { // Else only use a scaler if input and output don't match // TODO: Is this something we want by default or we just don't output anything? var effect = context.GetSharedEffect<ImageScaler>(); effect.SetInput(0, input); effect.SetOutput(output); ((RendererBase)effect).Draw(context); } // Switch back last output as render target context.CommandList.ResourceBarrierTransition(output, GraphicsResourceState.RenderTarget); }
protected override void PreDrawCore(RenderDrawContext context) { base.PreDrawCore(context); int value = InputCount; Parameters.Set(FactorCount, value); Parameters.Set(ColorCombinerShaderKeys.Factors, factors); Parameters.Set(ColorCombinerShaderKeys.ModulateRGB, ModulateRGB); }
/// <summary> /// Activates the output to the current <see cref="GraphicsDevice"/>. /// </summary> /// <param name="context">The context.</param> /// <param name="disableDepth">if set to <c>true</c> [disable depth].</param> public void ActivateOutput(RenderDrawContext context, bool disableDepth = false) { var output = GetOutput(context.RenderContext); if (output != null) { ActivateOutputCore(context, output, disableDepth); } }
private void RenderQuad(RenderDrawContext renderContext, RenderFrame frame) { customEffectInstance.Parameters.Set(EffectKeys.Phase, -3 * (float)Game.UpdateTime.Total.TotalSeconds); spriteBatch.Begin(renderContext.GraphicsContext, blendState: BlendStates.NonPremultiplied, depthStencilState: DepthStencilStates.None, effect: customEffectInstance); spriteBatch.Draw(Logo, new RectangleF(0, 0, 1, 1), Color.White); spriteBatch.End(); }
protected override void DrawCore(RenderDrawContext context, RenderFrame output) { var sceneInstance = GetChildSceneInstance(); if (sceneInstance == null) return; // Draw scene recursively sceneInstance.Draw(context, output, GraphicsCompositorOverride); }
/// <summary> /// Draws this renderer with the specified context. /// </summary> /// <param name="context">The context.</param> /// <exception cref="System.ArgumentNullException">context</exception> /// <exception cref="System.InvalidOperationException">Cannot use a different context between Load and Draw</exception> public void Draw(RenderDrawContext context) { if (Enabled) { PreDrawCoreInternal(context); DrawCore(context); PostDrawCoreInternal(context); } }
/// <inheritdoc/> public override void Prepare(RenderDrawContext context) { base.Prepare(context); // Prepare each sub render feature foreach (var renderFeature in RenderFeatures) { renderFeature.Prepare(context); } }
protected override void Draw(GameTime gameTime) { if (!ScreenShotAutomationEnabled) AdjustEffectParameters(); var renderDrawContext = new RenderDrawContext(Services, RenderContext.GetShared(Services), GraphicsContext); DrawCustomEffect(renderDrawContext); base.Draw(gameTime); }
protected override void DrawCore(RenderDrawContext context) { var input = GetInput(0); var output = GetOutput(0); if (FadeOutSpeed == 0f) { // Nothing to do if (input != output) { context.CommandList.Copy(input, output); } return; } if (input == output) { var newInput = NewScopedRenderTarget2D(input.Description); context.CommandList.Copy(input, newInput); input = newInput; } // Check we have a render target to hold the persistence over a few frames if (persistenceTexture == null || persistenceTexture.Description != output.Description) { // We need to re-allocate the texture if (persistenceTexture != null) { Context.Allocator.ReleaseReference(persistenceTexture); } persistenceTexture = Context.Allocator.GetTemporaryTexture2D(output.Description); // Initializes to black context.CommandList.Clear(persistenceTexture, Color.Black); } var accumulationPersistence = NewScopedRenderTarget2D(persistenceTexture.Description); // For persistence, we combine the current brightness with the one of the previous frames. bloomAfterimageShader.Parameters.Set(BloomAfterimageShaderKeys.FadeOutSpeed, FadeOutSpeed); bloomAfterimageShader.Parameters.Set(BloomAfterimageShaderKeys.Sensitivity, Sensitivity / 100f); bloomAfterimageShader.SetInput(0, input); bloomAfterimageShader.SetInput(1, persistenceTexture); bloomAfterimageShader.SetOutput(accumulationPersistence); bloomAfterimageShader.Draw(context, "Afterimage persistence accumulation"); // Keep the final brightness buffer for the following frames context.CommandList.Copy(accumulationPersistence, persistenceTexture); // Merge persistence and current bloom into the final result bloomAfterimageCombineShader.SetInput(0, input); bloomAfterimageCombineShader.SetInput(1, persistenceTexture); bloomAfterimageCombineShader.SetOutput(output); bloomAfterimageCombineShader.Draw(context, "Afterimage persistence combine"); }
protected override void DrawCore(RenderDrawContext context) { var output = PrefilteredRadiance; if (output == null || (output.Dimension != TextureDimension.Texture2D && output.Dimension != TextureDimension.TextureCube) || output.ArraySize != 6) throw new NotSupportedException("Only array of 2D textures are currently supported as output"); if (!output.IsRenderTarget) throw new NotSupportedException("Only render targets are supported as output"); var input = RadianceMap; if (input == null || input.Dimension != TextureDimension.TextureCube) throw new NotSupportedException("Only cubemaps are currently supported as input"); var roughness = 0f; var faceCount = output.ArraySize; var levelSize = new Int2(output.Width, output.Height); var mipCount = MipmapGenerationCount == 0 ? output.MipLevels : MipmapGenerationCount; for (int mipLevel = 0; mipLevel < mipCount; mipLevel++) { if (mipLevel == 0 && DoNotFilterHighestLevel && input.Width >= output.Width) { var inputLevel = MathUtil.Log2(input.Width / output.Width); for (int faceIndex = 0; faceIndex < 6; faceIndex++) { var inputSubresource = inputLevel + faceIndex * input.MipLevels; var outputSubresource = 0 + faceIndex * output.MipLevels; context.CommandList.CopyRegion(input, inputSubresource, null, output, outputSubresource); } } else { for (int faceIndex = 0; faceIndex < faceCount; faceIndex++) { using (var outputView = output.ToTextureView(ViewType.Single, faceIndex, mipLevel)) { shader.Parameters.Set(RadiancePrefilteringGGXNoComputeShaderKeys.Face, faceIndex); shader.Parameters.Set(RadiancePrefilteringGGXNoComputeShaderKeys.Roughness, roughness); shader.Parameters.Set(RadiancePrefilteringGGXNoComputeShaderKeys.MipmapCount, input.MipLevels - 1); shader.Parameters.Set(RadiancePrefilteringGGXNoComputeShaderKeys.RadianceMap, input); shader.Parameters.Set(RadiancePrefilteringGGXNoComputeShaderKeys.RadianceMapSize, input.Width); shader.Parameters.Set(RadiancePrefilteringGGXNoComputeParams.NbOfSamplings, SamplingsCount); shader.SetOutput(outputView); ((RendererBase)shader).Draw(context); } } } if (mipCount > 1) { roughness += 1f / (mipCount - 1); levelSize /= 2; } } }
protected override void DrawCore(RenderDrawContext context) { var output = PrefilteredRadiance; if(output == null || (output.Dimension != TextureDimension.Texture2D && output.Dimension != TextureDimension.TextureCube) || output.ArraySize != 6) throw new NotSupportedException("Only array of 2D textures are currently supported as output"); if (!output.IsUnorderedAccess || output.IsRenderTarget) throw new NotSupportedException("Only non-rendertarget unordered access textures are supported as output"); var input = RadianceMap; if(input == null || input.Dimension != TextureDimension.TextureCube) throw new NotSupportedException("Only cubemaps are currently supported as input"); var roughness = 0f; var faceCount = output.ArraySize; var levelSize = new Int2(output.Width, output.Height); var mipCount = MipmapGenerationCount == 0 ? output.MipLevels : MipmapGenerationCount; for (int l = 0; l < mipCount; l++) { if (l == 0 && DoNotFilterHighestLevel && input.Width >= output.Width) { var inputLevel = MathUtil.Log2(input.Width / output.Width); for (int f = 0; f < 6; f++) { var inputSubresource = inputLevel + f * input.MipLevels; var outputSubresource = 0 + f * output.MipLevels; context.CommandList.CopyRegion(input, inputSubresource, null, output, outputSubresource); } } else { var outputView = output.ToTextureView(ViewType.MipBand, 0, l); computeShader.ThreadGroupCounts = new Int3(levelSize.X, levelSize.Y, faceCount); computeShader.ThreadNumbers = new Int3(SamplingsCount, 1, 1); computeShader.Parameters.Set(RadiancePrefilteringGGXShaderKeys.Roughness, roughness); computeShader.Parameters.Set(RadiancePrefilteringGGXShaderKeys.MipmapCount, input.MipLevels - 1); computeShader.Parameters.Set(RadiancePrefilteringGGXShaderKeys.RadianceMap, input); computeShader.Parameters.Set(RadiancePrefilteringGGXShaderKeys.RadianceMapSize, input.Width); computeShader.Parameters.Set(RadiancePrefilteringGGXShaderKeys.FilteredRadiance, outputView); computeShader.Parameters.Set(RadiancePrefilteringGGXParams.NbOfSamplings, SamplingsCount); ((RendererBase)computeShader).Draw(context); outputView.Dispose(); } if (mipCount > 1) { roughness += 1f / (mipCount - 1); levelSize /= 2; } } }
/// <summary> /// Activates the output to the current <see cref="GraphicsDevice" />. /// </summary> /// <param name="context">The context.</param> /// <param name="output">The output.</param> /// <param name="disableDepth">if set to <c>true</c> [disable depth].</param> protected virtual void ActivateOutputCore(RenderDrawContext context, RenderFrame output, bool disableDepth) { // Set default render target states foreach (var renderTarget in output.RenderTargets) { context.CommandList.ResourceBarrierTransition(renderTarget, GraphicsResourceState.RenderTarget); } context.CommandList.ResourceBarrierTransition(output.DepthStencil, GraphicsResourceState.DepthWrite); // Setup the render target context.CommandList.SetRenderTargetsAndViewport(disableDepth ? null : output.DepthStencil, output.RenderTargets); }
protected override void DrawCore(RenderDrawContext context) { var inputTexture = GetSafeInput(0); // Output pixel format PixelFormat outputPixelFormat; // Scaling direction (<0 downscale, >0 upscale) int scalingDirection; // Validate and Prepare scaling if (!PrepareScaling(inputTexture, out scalingDirection, out outputPixelFormat)) { return; } // Make sure that we are using a clean Scaler. Scaler.Reset(); var nextSize = inputTexture.Size; nextSize.Depth = 1; var previousMipMap = inputTexture; int matchOutputCount = 0; while (matchOutputCount != outputTextures.Count) { nextSize = nextSize.Mip(scalingDirection); var mipmap = FindOutputMatchingSize(nextSize, scalingDirection); if (mipmap != null) { matchOutputCount++; // The size is now the intermediate texture nextSize = mipmap.Size; } else { mipmap = NewScopedRenderTarget2D(nextSize.Width, nextSize.Height, outputPixelFormat, 1); } // Down or UpScale Scaler.SetInput(previousMipMap); Scaler.SetOutput(mipmap); Scaler.Draw(context, name: scalingDirection < 0 ? "Down2" : "Up2"); previousMipMap = mipmap; } // Cleanup output textures so that we don't hold a reference outputTextures.Clear(); }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutations(RenderDrawContext context) { var skinningInfos = RootRenderFeature.RenderData.GetData(skinningInfoKey); var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; //foreach (var objectNodeReference in RootRenderFeature.ObjectNodeReferences) Dispatcher.ForEach(((RootEffectRenderFeature)RootRenderFeature).ObjectNodeReferences, objectNodeReference => { var objectNode = RootRenderFeature.GetObjectNode(objectNodeReference); var renderMesh = (RenderMesh)objectNode.RenderObject; var staticObjectNode = renderMesh.StaticObjectNode; var skinningInfo = skinningInfos[staticObjectNode]; var parameters = renderMesh.Mesh.Parameters; if (parameters != skinningInfo.Parameters || parameters.PermutationCounter != skinningInfo.PermutationCounter) { skinningInfo.Parameters = parameters; skinningInfo.PermutationCounter = parameters.PermutationCounter; skinningInfo.HasSkinningPosition = parameters.Get(MaterialKeys.HasSkinningPosition); skinningInfo.HasSkinningNormal = parameters.Get(MaterialKeys.HasSkinningNormal); skinningInfo.HasSkinningTangent = parameters.Get(MaterialKeys.HasSkinningTangent); skinningInfos[staticObjectNode] = skinningInfo; } for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) continue; if (renderMesh.Mesh.Skinning != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningPosition, skinningInfo.HasSkinningPosition); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningNormal, skinningInfo.HasSkinningNormal); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningTangent, skinningInfo.HasSkinningTangent); var skinningBones = Math.Max(MaxBones, renderMesh.Mesh.Skinning.Bones.Length); renderEffect.EffectValidator.ValidateParameter(MaterialKeys.SkinningMaxBones, skinningBones); } } }); }
/// <inheritdoc/> public override void PrepareEffectPermutationsImpl(RenderDrawContext context) { base.PrepareEffectPermutationsImpl(context); var renderEffects = RenderData.GetData(renderEffectKey); int effectSlotCount = EffectPermutationSlotCount; // Update existing materials foreach (var material in allMaterialInfos) { material.Key.Setup(RenderSystem.RenderContextOld); } foreach (var renderObject in RenderObjects) { var staticObjectNode = renderObject.StaticObjectNode; var renderParticleEmitter = (RenderParticleEmitter)renderObject; var material = renderParticleEmitter.ParticleEmitter.Material; var materialInfo = renderParticleEmitter.ParticleMaterialInfo; for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; // Skip effects not used during this frame if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem)) continue; if (materialInfo == null || materialInfo.Material != material) { // First time this material is initialized, let's create associated info if (!allMaterialInfos.TryGetValue(material, out materialInfo)) { materialInfo = new ParticleMaterialInfo(material); allMaterialInfos.Add(material, materialInfo); } renderParticleEmitter.ParticleMaterialInfo = materialInfo; // Update new materials material.Setup(RenderSystem.RenderContextOld); } // TODO: Iterate PermuatationParameters automatically? material.ValidateEffect(RenderSystem.RenderContextOld, ref renderEffect.EffectValidator); } } }
public SkyboxGeneratorContext(SkyboxAsset skybox) { if (skybox == null) throw new ArgumentNullException(nameof(skybox)); Skybox = skybox; Services = new ServiceRegistry(); Content = new ContentManager(Services); GraphicsDevice = GraphicsDevice.New(); GraphicsDeviceService = new GraphicsDeviceServiceLocal(Services, GraphicsDevice); EffectSystem = new EffectSystem(Services); EffectSystem.Initialize(); ((IContentable)EffectSystem).LoadContent(); ((EffectCompilerCache)EffectSystem.Compiler).CompileEffectAsynchronously = false; RenderContext = RenderContext.GetShared(Services); RenderDrawContext = new RenderDrawContext(Services, RenderContext, new GraphicsContext(new CommandList(GraphicsDevice), new ResourceGroupAllocator(GraphicsDevice))); }
protected override void Draw(GameTime gameTime) { var renderDrawContext = new RenderDrawContext(Services, RenderContext.GetShared(Services), GraphicsContext); GraphicsContext.CommandList.Clear(output, Color4.White); renderHammersley.ThreadGroupCounts = new Int3(samplesCount, 1, 1); renderHammersley.ThreadNumbers = new Int3(1); renderHammersley.Parameters.Set(HammersleyTestKeys.OutputTexture, output); renderHammersley.Parameters.Set(HammersleyTestKeys.SamplesCount, samplesCount); renderHammersley.Draw(renderDrawContext); GraphicsContext.DrawTexture(output); base.Draw(gameTime); }
protected override void Draw(GameTime gameTime) { var renderDrawContext = new RenderDrawContext(Services, RenderContext.GetShared(Services), GraphicsContext); computeShaderEffect.Parameters.Set(ComputeShaderTestParams.NbOfIterations, ReductionRatio); computeShaderEffect.Parameters.Set(ComputeShaderTestKeys.input, inputTexture); computeShaderEffect.Parameters.Set(ComputeShaderTestKeys.output, outputTexture); computeShaderEffect.Draw(renderDrawContext); if (displayedTexture == null || spriteBatch == null) return; GraphicsContext.DrawTexture(displayedTexture); base.Draw(gameTime); }
protected override void DrawCore(RenderDrawContext context) { var input = GetInput(0); var output = GetOutput(0); if (input == null || output == null) { return; } brightPassFilter.Parameters.Set(BrightFilterShaderKeys.BrightPassThreshold, Threshold); brightPassFilter.Parameters.Set(BrightFilterShaderKeys.ColorModulator, Color.ToColorSpace(GraphicsDevice.ColorSpace)); brightPassFilter.SetInput(input); brightPassFilter.SetOutput(output); ((RendererBase)brightPassFilter).Draw(context); }
protected override void DrawCore(RenderDrawContext context) { // Make sure we keep our uniform weights in synchronization with the number of taps if (tapWeights == null || tapWeights.Length != tapCount) { tapWeights = DoFUtil.GetUniformWeightBlurArray(tapCount); } if (!useOptimizedPath) { DrawCoreNaive(context); } else { DrawCoreOptimized(context); } }
public virtual void ApplyDrawParameters(RenderDrawContext context, ParameterCollection parameters, FastListStruct <LightDynamicEntry> currentLights, ref BoundingBoxExt boundingBox) { }
protected override void DrawCore(RenderDrawContext context) { if (lightShaftProcessor == null || lightShaftBoundingVolumeProcessor == null) { return; // Not collected } if (LightBufferDownsampleLevel < 1) { throw new ArgumentOutOfRangeException(nameof(LightBufferDownsampleLevel)); } if (BoundingVolumeBufferDownsampleLevel < 1) { throw new ArgumentOutOfRangeException(nameof(BoundingVolumeBufferDownsampleLevel)); } var lightShaftDatas = lightShaftProcessor.LightShafts; var depthInput = GetSafeInput(0); // Create a min/max buffer generated from scene bounding volumes var targetBoundingBoxBufferSize = new Size2(Math.Max(1, depthInput.Width / BoundingVolumeBufferDownsampleLevel), Math.Max(1, depthInput.Height / BoundingVolumeBufferDownsampleLevel)); var boundingBoxBuffer = NewScopedRenderTarget2D(targetBoundingBoxBufferSize.Width, targetBoundingBoxBufferSize.Height, PixelFormat.R32G32_Float); // Buffer that holds the minimum distance in case of being inside the bounding box var backSideRaycastBuffer = NewScopedRenderTarget2D(1, 1, PixelFormat.R32G32_Float); // Create a single channel light buffer PixelFormat lightBufferPixelFormat = needsColorLightBuffer ? PixelFormat.R16G16B16A16_Float : PixelFormat.R16_Float; var targetLightBufferSize = new Size2(Math.Max(1, depthInput.Width / LightBufferDownsampleLevel), Math.Max(1, depthInput.Height / LightBufferDownsampleLevel)); var lightBuffer = NewScopedRenderTarget2D(targetLightBufferSize.Width, targetLightBufferSize.Height, lightBufferPixelFormat); lightShaftsEffectShader.SetOutput(lightBuffer); var lightShaftsParameters = lightShaftsEffectShader.Parameters; lightShaftsParameters.Set(DepthBaseKeys.DepthStencil, depthInput); // Bind scene depth if (!Initialized) { Initialize(context.RenderContext); } var renderView = context.RenderContext.RenderView; var viewInverse = Matrix.Invert(renderView.View); lightShaftsParameters.Set(TransformationKeys.ViewInverse, viewInverse); lightShaftsParameters.Set(TransformationKeys.Eye, new Vector4(viewInverse.TranslationVector, 1)); // Setup parameters for Z reconstruction lightShaftsParameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(renderView.NearClipPlane, renderView.FarClipPlane)); Matrix projectionInverse; Matrix.Invert(ref renderView.Projection, out projectionInverse); lightShaftsParameters.Set(TransformationKeys.ProjectionInverse, projectionInverse); applyLightEffectShader.SetOutput(GetSafeOutput(0)); foreach (var lightShaft in lightShaftDatas) { if (lightShaft.LightComponent == null) { continue; // Skip entities without a light component } // Set sample count for this light lightShaftsParameters.Set(LightShaftsEffectKeys.SampleCount, lightShaft.SampleCount); // Setup the shader group used for sampling shadows var shadowMapTexture = shadowMapRenderer.FindShadowMap(renderView.LightingView ?? renderView, lightShaft.LightComponent); SetupLight(context, lightShaft, shadowMapTexture, lightShaftsParameters); var boundingVolumes = lightShaftBoundingVolumeProcessor.GetBoundingVolumesForComponent(lightShaft.Component); if (boundingVolumes == null) { continue; } // Check if we can pack bounding volumes together or need to draw them one by one var boundingVolumeLoop = lightShaft.SeparateBoundingVolumes ? boundingVolumes.Count : 1; var lightBufferUsed = false; for (int i = 0; i < boundingVolumeLoop; ++i) { // Generate list of bounding volume (either all or one by one depending on SeparateBoundingVolumes) var currentBoundingVolumes = (lightShaft.SeparateBoundingVolumes) ? singleBoundingVolume : boundingVolumes; if (lightShaft.SeparateBoundingVolumes) { singleBoundingVolume[0] = boundingVolumes[i]; } using (context.PushRenderTargetsAndRestore()) { // Clear bounding box buffer context.CommandList.Clear(boundingBoxBuffer, new Color4(1.0f, 0.0f, 0.0f, 0.0f)); context.CommandList.SetRenderTargetAndViewport(null, boundingBoxBuffer); // If nothing visible, skip second part if (!DrawBoundingVolumeMinMax(context, currentBoundingVolumes)) { continue; } context.CommandList.Clear(backSideRaycastBuffer, new Color4(1.0f, 0.0f, 0.0f, 0.0f)); context.CommandList.SetRenderTargetAndViewport(null, backSideRaycastBuffer); // If nothing visible, skip second part DrawBoundingVolumeBackside(context, currentBoundingVolumes); } if (!lightBufferUsed) { // First pass: replace (avoid a clear and blend state) lightShaftsEffectShader.BlendState = BlendStates.Opaque; lightBufferUsed = true; } else { // Then: add var desc = BlendStates.Additive; desc.RenderTarget0.ColorSourceBlend = Blend.One; // But without multiplying alpha lightShaftsEffectShader.BlendState = desc; } if (lightShaft.SampleCount < 1) { throw new ArgumentOutOfRangeException(nameof(lightShaft.SampleCount)); } // Set min/max input lightShaftsEffectShader.SetInput(0, boundingBoxBuffer); lightShaftsEffectShader.SetInput(1, backSideRaycastBuffer); // Light accumulation pass (on low resolution buffer) DrawLightShaft(context, lightShaft); } // Everything was outside, skip if (!lightBufferUsed) { continue; } if (LightBufferDownsampleLevel != 1) { // Blur the result blur.Radius = LightBufferDownsampleLevel; blur.SetInput(lightBuffer); blur.SetOutput(lightBuffer); blur.Draw(context); } // Additive blend pass Color3 lightColor = lightShaft.Light.ComputeColor(context.GraphicsDevice.ColorSpace, lightShaft.LightComponent.Intensity); applyLightEffectShader.Parameters.Set(AdditiveLightShaderKeys.LightColor, lightColor); applyLightEffectShader.Parameters.Set(AdditiveLightEffectKeys.Color, needsColorLightBuffer); applyLightEffectShader.SetInput(lightBuffer); applyLightEffectShader.Draw(context); } // Clean up unused render data unusedLights.Clear(); foreach (var data in renderData) { if (data.Value.UsageCounter != usageCounter) { unusedLights.Add(data.Key); } } foreach (var unusedLight in unusedLights) { renderData.Remove(unusedLight); } usageCounter++; }
public void Flush(RenderDrawContext context) { RenderViewsWithShadows.Clear(); }
/// <summary> /// Main drawing method for this renderer that must be implemented. /// </summary> /// <param name="context"></param> /// <param name="drawContext"></param> protected abstract void DrawCore(RenderContext context, RenderDrawContext drawContext);
protected override void DrawCore(RenderDrawContext context) { // Inputs: Texture colorBuffer = GetSafeInput(0); Texture depthBuffer = GetSafeInput(1); Texture normalsBuffer = GetSafeInput(2); Texture specularRoughnessBuffer = GetSafeInput(3); // Output: Texture outputBuffer = GetSafeOutput(0); // Prepare var temporalCache = Prepare(context, outputBuffer); FlushCache(context.RenderContext.Time.FrameCount); // Get temporary buffers var rayTraceBuffersSize = GetBufferResolution(outputBuffer, RayTracePassResolution); var resolveBuffersSize = GetBufferResolution(outputBuffer, ResolvePassResolution); Texture rayTraceBuffer = NewScopedRenderTarget2D(rayTraceBuffersSize.Width, rayTraceBuffersSize.Height, RayTraceTargetFormat, 1); Texture resolveBuffer = NewScopedRenderTarget2D(resolveBuffersSize.Width, resolveBuffersSize.Height, ReflectionsFormat, 1); // Check if resize depth Texture smallerDepthBuffer = depthBuffer; if (DepthResolution != ResolutionMode.Full) { // Smaller depth buffer improves ray tracing performance. var depthBuffersSize = GetBufferResolution(depthBuffer, DepthResolution); smallerDepthBuffer = NewScopedRenderTarget2D(depthBuffersSize.Width, depthBuffersSize.Height, PixelFormat.R32_Float, 1); depthPassShader.SetInput(0, depthBuffer); depthPassShader.SetOutput(smallerDepthBuffer); depthPassShader.Draw(context, "Downscale Depth"); } // Blur Pass Texture blurPassBuffer; if (UseColorBufferMips) { // Note: using color buffer mips maps helps with reducing artifacts // and improves resolve pass performance (faster color texture lookups, less cache misses) // Also for high surface roughness values it adds more blur to the reflection tail which looks more realistic. // Get temp targets var colorBuffersSize = new Size2(outputBuffer.Width / 2, outputBuffer.Height / 2); int colorBuffersMips = Texture.CalculateMipMapCount(MipMapCount.Auto, colorBuffersSize.Width, colorBuffersSize.Height); Texture colorBuffer0 = NewScopedRenderTarget2D(colorBuffersSize.Width, colorBuffersSize.Height, ReflectionsFormat, colorBuffersMips); Texture colorBuffer1 = NewScopedRenderTarget2D(colorBuffersSize.Width / 2, colorBuffersSize.Height / 2, ReflectionsFormat, colorBuffersMips - 1); int colorBuffer1MipOffset = 1; // For colorBuffer1 we could use one mip less (optimized) // Cache per color buffer mip views int colorBuffer0Mips = colorBuffer0.MipLevels; if (cachedColorBuffer0Mips == null || cachedColorBuffer0Mips.Length != colorBuffer0Mips || cachedColorBuffer0Mips[0].ParentTexture != colorBuffer0) { cachedColorBuffer0Mips?.ForEach(view => view?.Dispose()); cachedColorBuffer0Mips = new Texture[colorBuffer0Mips]; for (int mipIndex = 0; mipIndex < colorBuffer0Mips; mipIndex++) { cachedColorBuffer0Mips[mipIndex] = colorBuffer0.ToTextureView(ViewType.Single, 0, mipIndex); } } int colorBuffer1Mips = colorBuffer1.MipLevels; if (cachedColorBuffer1Mips == null || cachedColorBuffer1Mips.Length != colorBuffer1Mips || cachedColorBuffer1Mips[0].ParentTexture != colorBuffer1) { cachedColorBuffer1Mips?.ForEach(view => view?.Dispose()); cachedColorBuffer1Mips = new Texture[colorBuffer1Mips]; for (int mipIndex = 0; mipIndex < colorBuffer1Mips; mipIndex++) { cachedColorBuffer1Mips[mipIndex] = colorBuffer1.ToTextureView(ViewType.Single, 0, mipIndex); } } // Clone scene frame to mip 0 of colorBuffer0 Scaler.SetInput(0, colorBuffer); Scaler.SetOutput(cachedColorBuffer0Mips[0]); Scaler.Draw(context, "Copy frame"); // Downscale with gaussian blur for (int mipLevel = 1; mipLevel < colorBuffersMips; mipLevel++) { // Blur H var srcMip = cachedColorBuffer0Mips[mipLevel - 1]; var dstMip = cachedColorBuffer1Mips[mipLevel - colorBuffer1MipOffset]; blurPassShaderH.SetInput(0, srcMip); blurPassShaderH.SetOutput(dstMip); blurPassShaderH.Draw(context, "Blur H"); // Blur V srcMip = dstMip; dstMip = cachedColorBuffer0Mips[mipLevel]; blurPassShaderV.SetInput(0, srcMip); blurPassShaderV.SetOutput(dstMip); blurPassShaderV.Draw(context, "Blur V"); } blurPassBuffer = colorBuffer0; } else { // Don't use color buffer with mip maps blurPassBuffer = colorBuffer; cachedColorBuffer0Mips?.ForEach(view => view?.Dispose()); cachedColorBuffer1Mips?.ForEach(view => view?.Dispose()); } // Ray Trace Pass rayTracePassShader.SetInput(0, colorBuffer); rayTracePassShader.SetInput(1, smallerDepthBuffer); rayTracePassShader.SetInput(2, normalsBuffer); rayTracePassShader.SetInput(3, specularRoughnessBuffer); rayTracePassShader.SetOutput(rayTraceBuffer); rayTracePassShader.Draw(context, "Ray Trace"); // Resolve Pass resolvePassShader.SetInput(0, blurPassBuffer); resolvePassShader.SetInput(1, ResolvePassResolution == ResolutionMode.Full ? depthBuffer : smallerDepthBuffer); resolvePassShader.SetInput(2, normalsBuffer); resolvePassShader.SetInput(3, specularRoughnessBuffer); resolvePassShader.SetInput(4, rayTraceBuffer); resolvePassShader.SetOutput(resolveBuffer); resolvePassShader.Draw(context, "Resolve"); // Temporal Pass Texture reflectionsBuffer = resolveBuffer; if (TemporalEffect) { var temporalSize = outputBuffer.Size; temporalCache.Resize(GraphicsDevice, ref temporalSize); Texture temporalBuffer0 = NewScopedRenderTarget2D(temporalSize.Width, temporalSize.Height, ReflectionsFormat, 1); temporalPassShader.SetInput(0, resolveBuffer); temporalPassShader.SetInput(1, temporalCache.TemporalBuffer); temporalPassShader.SetInput(2, depthBuffer); temporalPassShader.SetOutput(temporalBuffer0); temporalPassShader.Draw(context, "Temporal"); context.CommandList.Copy(temporalBuffer0, temporalCache.TemporalBuffer); // TODO: use Texture.Swap from ContentStreaming branch to make it faster! reflectionsBuffer = temporalCache.TemporalBuffer; } // Combine Pass combinePassShader.SetInput(0, colorBuffer); combinePassShader.SetInput(1, depthBuffer); combinePassShader.SetInput(2, normalsBuffer); combinePassShader.SetInput(3, specularRoughnessBuffer); combinePassShader.SetInput(4, reflectionsBuffer); combinePassShader.SetOutput(outputBuffer); combinePassShader.Draw(context, "Combine"); #if SSLR_DEBUG if (DebugMode != DebugModes.None) { // Debug preview of temp targets switch (DebugMode) { case DebugModes.RayTrace: Scaler.SetInput(0, rayTraceBuffer); break; case DebugModes.Resolve: Scaler.SetInput(0, resolveBuffer); break; case DebugModes.Temporal: if (temporalCache != null) { Scaler.SetInput(0, temporalCache.TemporalBuffer); } break; } Scaler.SetOutput(outputBuffer); Scaler.Draw(context); } #endif }
public abstract void PostProcess(RenderDrawContext drawContext);
public unsafe void AllocateBuffers(RenderDrawContext renderDrawContext, int vertexBufferSize, int requiredIndexCount) { // Build the shared vertex buffer - every frame if (vertexBufferSize > 0) { { vertexBufferSize--; vertexBufferSize |= vertexBufferSize >> 1; vertexBufferSize |= vertexBufferSize >> 2; vertexBufferSize |= vertexBufferSize >> 3; vertexBufferSize |= vertexBufferSize >> 8; vertexBufferSize |= vertexBufferSize >> 16; vertexBufferSize++; } VertexBufferSize = vertexBufferSize; VertexBuffer = renderDrawContext.GraphicsContext.Allocator.GetTemporaryBuffer( new BufferDescription(VertexBufferSize, BufferFlags.VertexBuffer, GraphicsResourceUsage.Dynamic)); } // Build the shared index buffer - only when necessary var requiredIndexBufferSize = requiredIndexCount * IndexStride; if (requiredIndexBufferSize > IndexBufferSize) { if (IndexBuffer != null) { renderDrawContext.GraphicsContext.Allocator.ReleaseReference(IndexBuffer); IndexBuffer = null; } // We start allocating from 64K (allowing 32K indices to be written at once - this is most probably going to be sufficient in all cases) IndexBufferSize = requiredIndexBufferSize; if (IndexBufferSize < 64 * 1024) { IndexBufferSize = 64 * 1024; } { IndexBufferSize--; IndexBufferSize |= IndexBufferSize >> 1; IndexBufferSize |= IndexBufferSize >> 2; IndexBufferSize |= IndexBufferSize >> 3; IndexBufferSize |= IndexBufferSize >> 8; IndexBufferSize |= IndexBufferSize >> 16; IndexBufferSize++; } IndexBuffer = renderDrawContext.GraphicsContext.Allocator.GetTemporaryBuffer( new BufferDescription(IndexBufferSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic)); var indexCount = IndexBufferSize / IndexStride; indexCount = ((indexCount / 6) * 6); { var commandList = renderDrawContext.CommandList; var mappedIndices = commandList.MapSubresource(IndexBuffer, 0, MapMode.WriteNoOverwrite, false, 0, IndexBufferSize); var indexPointer = mappedIndices.DataBox.DataPointer; int indexStructSize = sizeof(short); int verticesPerQuad = 4; var k = 0; for (var i = 0; i < indexCount; k += verticesPerQuad) { *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 0); *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 1); *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 2); *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 0); *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 2); *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 3); } commandList.UnmapSubresource(mappedIndices); } } }
private bool DrawBoundingVolumes(RenderDrawContext context, IReadOnlyList <LightShaftBoundingVolumeProcessor.Data> boundingVolumes, Matrix viewProjection) { var commandList = context.CommandList; bool effectUpdated = minmaxVolumeEffectShader.UpdateEffect(GraphicsDevice); if (minmaxVolumeEffectShader.Effect == null) { return(false); } var needEffectUpdate = effectUpdated || previousMinmaxEffectBytecode != minmaxVolumeEffectShader.Effect.Bytecode; bool visibleMeshes = false; for (int pass = 0; pass < 2; ++pass) { var minmaxPipelineState = minmaxPipelineStates[pass]; bool pipelineDirty = false; if (needEffectUpdate) { // The EffectInstance might have been updated from outside previousMinmaxEffectBytecode = minmaxVolumeEffectShader.Effect.Bytecode; minmaxPipelineState.State.RootSignature = minmaxVolumeEffectShader.RootSignature; minmaxPipelineState.State.EffectBytecode = minmaxVolumeEffectShader.Effect.Bytecode; minmaxPipelineState.State.Output.RenderTargetCount = 1; minmaxPipelineState.State.Output.RenderTargetFormat0 = commandList.RenderTarget.Format; pipelineDirty = true; } MeshDraw currentDraw = null; var frustum = new BoundingFrustum(ref viewProjection); foreach (var volume in boundingVolumes) { if (volume.Model == null) { continue; } // Update parameters for the minmax shader Matrix worldViewProjection = Matrix.Multiply(volume.World, viewProjection); minmaxVolumeEffectShader.Parameters.Set(VolumeMinMaxShaderKeys.WorldViewProjection, worldViewProjection); foreach (var mesh in volume.Model.Meshes) { // Frustum culling BoundingBox meshBoundingBox; Matrix world = volume.World; BoundingBox.Transform(ref mesh.BoundingBox, ref world, out meshBoundingBox); var boundingBoxExt = new BoundingBoxExt(meshBoundingBox); if (boundingBoxExt.Extent != Vector3.Zero && !VisibilityGroup.FrustumContainsBox(ref frustum, ref boundingBoxExt, true)) { continue; } visibleMeshes = true; var draw = mesh.Draw; if (currentDraw != draw) { if (minmaxPipelineState.State.PrimitiveType != draw.PrimitiveType) { minmaxPipelineState.State.PrimitiveType = draw.PrimitiveType; pipelineDirty = true; } var inputElements = draw.VertexBuffers.CreateInputElements(); if (inputElements.ComputeHash() != minmaxPipelineState.State.InputElements.ComputeHash()) { minmaxPipelineState.State.InputElements = inputElements; pipelineDirty = true; } // Update mesh for (int i = 0; i < draw.VertexBuffers.Length; i++) { var vertexBuffer = draw.VertexBuffers[i]; commandList.SetVertexBuffer(i, vertexBuffer.Buffer, vertexBuffer.Offset, vertexBuffer.Stride); } if (draw.IndexBuffer != null) { commandList.SetIndexBuffer(draw.IndexBuffer.Buffer, draw.IndexBuffer.Offset, draw.IndexBuffer.Is32Bit); } currentDraw = draw; } if (pipelineDirty) { minmaxPipelineState.Update(); pipelineDirty = false; } context.CommandList.SetPipelineState(minmaxPipelineState.CurrentState); minmaxVolumeEffectShader.Apply(context.GraphicsContext); // Draw if (currentDraw.IndexBuffer == null) { commandList.Draw(currentDraw.DrawCount, currentDraw.StartLocation); } else { commandList.DrawIndexed(currentDraw.DrawCount, currentDraw.StartLocation); } } } } return(visibleMeshes); }
/// <inheritdoc/> public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { var commandList = context.CommandList; // TODO: PerView data Matrix viewInverse; Matrix.Invert(ref renderView.View, out viewInverse); var descriptorSets = new DescriptorSet[EffectDescriptorSetSlotCount]; for (var index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; var renderNode = GetRenderNode(renderNodeReference); var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; if (renderParticleEmitter.ParticleEmitter.VertexBuilder.ResourceContext == null) { continue; } // Generate vertices // TODO: Just just unmap/barrier here renderParticleEmitter.ParticleEmitter.BuildVertexBuffer(context.CommandList, ref viewInverse); // Get effect var renderEffect = renderNode.RenderEffect; if (renderEffect.Effect == null) { continue; } // TODO GRAPHICS REFACTOR: Extract data var particleSystemComponent = renderParticleEmitter.RenderParticleSystem.ParticleSystemComponent; var particleSystem = particleSystemComponent.ParticleSystem; var vertexBuilder = renderParticleEmitter.ParticleEmitter.VertexBuilder; // Bind VB var vertexBuffer = vertexBuilder.ResourceContext.VertexBuffer; var indexBuffer = vertexBuilder.ResourceContext.IndexBuffer; commandList.SetVertexBuffer(0, vertexBuffer.Buffer, vertexBuffer.Offset, vertexBuffer.Stride); commandList.SetIndexBuffer(indexBuffer.Buffer, indexBuffer.Offset, indexBuffer.Is32Bit); var resourceGroupOffset = ComputeResourceGroupOffset(renderNodeReference); // Update cbuffer renderEffect.Reflection.BufferUploader.Apply(context.CommandList, ResourceGroupPool, resourceGroupOffset); // Bind descriptor sets for (int i = 0; i < descriptorSets.Length; ++i) { var resourceGroup = ResourceGroupPool[resourceGroupOffset++]; if (resourceGroup != null) { descriptorSets[i] = resourceGroup.DescriptorSet; } } commandList.SetPipelineState(renderEffect.PipelineState); commandList.SetDescriptorSets(0, descriptorSets); commandList.DrawIndexed(vertexBuilder.LivingQuads * vertexBuilder.IndicesPerQuad, vertexBuilder.ResourceContext.IndexBufferPosition); } }
private bool DrawBoundingVolumeMinMax(RenderDrawContext context, IReadOnlyList <LightShaftBoundingVolumeProcessor.Data> boundingVolumes) { return(DrawBoundingVolumes(context, boundingVolumes, context.RenderContext.RenderView.ViewProjection)); }
private void DrawLightShaft(RenderDrawContext context, LightShaftProcessor.Data lightShaft) { lightShaftsEffectShader.Parameters.Set(LightShaftsShaderKeys.DensityFactor, lightShaft.DensityFactor); lightShaftsEffectShader.Draw(context, $"Light shaft [{lightShaft.LightComponent.Entity.Name}]"); }
protected override void DrawCore(RenderContext context, RenderDrawContext drawContext) { drawAction(drawContext); }
public virtual void ApplyViewParameters(RenderDrawContext context, ParameterCollection parameters, FastListStruct <LightDynamicEntry> currentLights) { }
/// <inheritdoc/> public override void Flush(RenderDrawContext context) { // Release the temporary vertex buffer particleBufferContext.ReleaseBuffers(context); }
protected virtual void SpecificDrawBeforeUI(RenderDrawContext context, RenderFrame renderFrame) { }
public override LightShaderGroupDynamic CreateLightShaderGroup(RenderDrawContext context, ILightShadowMapShaderGroupData shadowShaderGroupData) { return(new PointLightShaderGroup(context.RenderContext, shadowShaderGroupData)); }
/// <param name="context"></param> /// <inheritdoc/> public override void PrepareEffectPermutations(RenderDrawContext context) { var renderEffects = RootRenderFeature.RenderData.GetData(renderEffectKey); var tessellationStates = RootRenderFeature.RenderData.GetData(tessellationStateKey); int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount; Dispatcher.ForEach(RootRenderFeature.RenderObjects, renderObject => { var staticObjectNode = renderObject.StaticObjectNode; var renderMesh = (RenderMesh)renderObject; bool resetPipelineState = false; var material = renderMesh.MaterialPass; var materialInfo = renderMesh.MaterialInfo; // Material use first 16 bits var materialHashCode = material != null ? ((uint)material.GetHashCode() & 0x0FFF) | ((uint)material.PassIndex << 12) : 0; renderObject.StateSortKey = (renderObject.StateSortKey & 0x0000FFFF) | (materialHashCode << 16); ref var tessellationState = ref tessellationStates[staticObjectNode]; // Update draw data if tessellation is active if (material.TessellationMethod != XenkoTessellationMethod.None) { var tessellationMeshDraw = tessellationState.MeshDraw; if (tessellationState.Method != material.TessellationMethod) { tessellationState.Method = material.TessellationMethod; var oldMeshDraw = renderMesh.ActiveMeshDraw; tessellationMeshDraw = new MeshDraw { VertexBuffers = oldMeshDraw.VertexBuffers, IndexBuffer = oldMeshDraw.IndexBuffer, DrawCount = oldMeshDraw.DrawCount, StartLocation = oldMeshDraw.StartLocation, PrimitiveType = tessellationState.Method.GetPrimitiveType(), }; // adapt the primitive type and index buffer to the tessellation used if (tessellationState.Method.PerformsAdjacentEdgeAverage()) { renderMeshesToGenerateAEN.Add(renderMesh); } else { // Not using AEN tessellation anymore, dispose AEN indices if they were generated Utilities.Dispose(ref tessellationState.GeneratedIndicesAEN); } tessellationState.MeshDraw = tessellationMeshDraw; // Reset pipeline states resetPipelineState = true; } renderMesh.ActiveMeshDraw = tessellationState.MeshDraw; } else if (tessellationState.GeneratedIndicesAEN != null) { // Not using tessellation anymore, dispose AEN indices if they were generated Utilities.Dispose(ref tessellationState.GeneratedIndicesAEN); } // Rebuild rasterizer state if culling mode changed // TODO GRAPHICS REFACTOR: Negative scaling belongs into TransformationRenderFeature if (materialInfo != null && (materialInfo.CullMode != material.CullMode || renderMesh.IsScalingNegative != renderMesh.IsPreviousScalingNegative)) { materialInfo.CullMode = material.CullMode; renderMesh.IsPreviousScalingNegative = renderMesh.IsScalingNegative; resetPipelineState = true; } for (int i = 0; i < effectSlotCount; ++i) { var staticEffectObjectNode = staticObjectNode * effectSlotCount + i; var renderEffect = renderEffects[staticEffectObjectNode]; if (renderEffect == null) { continue; } // If any pipeline state changed, rebuild it for all effect slots if (resetPipelineState) { renderEffect.PipelineState = null; } // Skip effects not used during this frame if (!renderEffect.IsUsedDuringThisFrame(RenderSystem)) { continue; } if (materialInfo == null || materialInfo.MaterialPass != material) { // First time this material is initialized, let's create associated info lock (allMaterialInfos) { if (!allMaterialInfos.TryGetValue(material, out materialInfo)) { materialInfo = new MaterialInfo(material); allMaterialInfos.Add(material, materialInfo); } } renderMesh.MaterialInfo = materialInfo; } if (materialInfo.MaterialParameters != material.Parameters || materialInfo.PermutationCounter != material.Parameters.PermutationCounter) { lock (materialInfo) { var isMaterialParametersChanged = materialInfo.MaterialParameters != material.Parameters; if (isMaterialParametersChanged || // parameter fast reload? materialInfo.PermutationCounter != material.Parameters.PermutationCounter) { materialInfo.VertexStageSurfaceShaders = material.Parameters.Get(MaterialKeys.VertexStageSurfaceShaders); materialInfo.VertexStageStreamInitializer = material.Parameters.Get(MaterialKeys.VertexStageStreamInitializer); materialInfo.DomainStageSurfaceShaders = material.Parameters.Get(MaterialKeys.DomainStageSurfaceShaders); materialInfo.DomainStageStreamInitializer = material.Parameters.Get(MaterialKeys.DomainStageStreamInitializer); materialInfo.TessellationShader = material.Parameters.Get(MaterialKeys.TessellationShader); materialInfo.PixelStageSurfaceShaders = material.Parameters.Get(MaterialKeys.PixelStageSurfaceShaders); materialInfo.PixelStageStreamInitializer = material.Parameters.Get(MaterialKeys.PixelStageStreamInitializer); materialInfo.HasNormalMap = material.Parameters.Get(MaterialKeys.HasNormalMap); materialInfo.UsePixelShaderWithDepthPass = material.Parameters.Get(MaterialKeys.UsePixelShaderWithDepthPass); materialInfo.MaterialParameters = material.Parameters; materialInfo.ParametersChanged = isMaterialParametersChanged; materialInfo.PermutationCounter = material.Parameters.PermutationCounter; } } } // VS if (materialInfo.VertexStageSurfaceShaders != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.VertexStageSurfaceShaders, materialInfo.VertexStageSurfaceShaders); } if (materialInfo.VertexStageStreamInitializer != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.VertexStageStreamInitializer, materialInfo.VertexStageStreamInitializer); } // DS if (materialInfo.DomainStageSurfaceShaders != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.DomainStageSurfaceShaders, materialInfo.DomainStageSurfaceShaders); } if (materialInfo.DomainStageStreamInitializer != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.DomainStageStreamInitializer, materialInfo.DomainStageStreamInitializer); } // Tessellation if (materialInfo.TessellationShader != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.TessellationShader, materialInfo.TessellationShader); } // PS if (materialInfo.PixelStageSurfaceShaders != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.PixelStageSurfaceShaders, materialInfo.PixelStageSurfaceShaders); } if (materialInfo.PixelStageStreamInitializer != null) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.PixelStageStreamInitializer, materialInfo.PixelStageStreamInitializer); } if (materialInfo.HasNormalMap) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasNormalMap, materialInfo.HasNormalMap); } if (materialInfo.UsePixelShaderWithDepthPass) { renderEffect.EffectValidator.ValidateParameter(MaterialKeys.UsePixelShaderWithDepthPass, materialInfo.UsePixelShaderWithDepthPass); } } });
/// <inheritdoc/> public override unsafe void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { var commandList = context.CommandList; // register all texture usage foreach (var renderObject in RenderObjects) { var renderParticleEmitter = (RenderParticleEmitter)renderObject; Context.StreamingManager?.StreamResources(renderParticleEmitter.ParticleEmitter.Material.Parameters); } // Per view - this code was moved here from Prepare(...) so that we can apply the correct Viewport { var view = renderView; var viewFeature = view.Features[Index]; Matrix.Multiply(ref view.View, ref view.Projection, out view.ViewProjection); // Copy ViewProjection to PerFrame cbuffer foreach (var viewLayout in viewFeature.Layouts) { var resourceGroup = viewLayout.Entries[view.Index].Resources; var mappedCB = resourceGroup.ConstantBuffer.Data; // PerView constant buffer var perViewOffset = viewLayout.GetConstantBufferOffset(this.perViewCBufferOffset); if (perViewOffset != -1) { var perView = (ParticleUtilitiesPerView *)((byte *)mappedCB + perViewOffset); perView->ViewMatrix = view.View; perView->ProjectionMatrix = view.Projection; perView->ViewProjectionMatrix = view.ViewProjection; perView->ViewFrustum = new Vector4(view.ViewSize.X, view.ViewSize.Y, view.NearClipPlane, view.FarClipPlane); perView->Viewport = new Vector4(0, 0, ((float)context.CommandList.Viewport.Width) / ((float)context.CommandList.RenderTarget.Width), ((float)context.CommandList.Viewport.Height) / ((float)context.CommandList.RenderTarget.Height)); } } } var renderParticleNodeData = RenderData.GetData(renderParticleNodeKey); // TODO: stackalloc? var descriptorSetsLocal = descriptorSets.Value; if (descriptorSetsLocal == null || descriptorSetsLocal.Length < EffectDescriptorSetSlotCount) { descriptorSetsLocal = descriptorSets.Value = new DescriptorSet[EffectDescriptorSetSlotCount]; } for (var index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; // Get effect var renderEffect = GetRenderNode(renderNodeReference).RenderEffect; if (renderEffect.Effect == null) { continue; } // Get the extra node data var nodeData = renderParticleNodeData[renderNodeReference]; if (nodeData.IndexCount <= 0) { continue; } var resourceGroupOffset = ComputeResourceGroupOffset(renderNodeReference); // Update cbuffer renderEffect.Reflection.BufferUploader.Apply(commandList, ResourceGroupPool, resourceGroupOffset); // Bind descriptor sets for (int i = 0; i < descriptorSetsLocal.Length; ++i) { var resourceGroup = ResourceGroupPool[resourceGroupOffset++]; if (resourceGroup != null) { descriptorSetsLocal[i] = resourceGroup.DescriptorSet; } } commandList.SetPipelineState(renderEffect.PipelineState); commandList.SetDescriptorSets(0, descriptorSetsLocal); // Bind the buffers and draw commandList.SetVertexBuffer(0, nodeData.VertexBuffer, nodeData.VertexBufferOffset, nodeData.VertexBufferStride); commandList.SetIndexBuffer(nodeData.IndexBuffer, nodeData.IndexBufferOffset, ParticleBufferContext.IndexStride != sizeof(short)); commandList.DrawIndexed(nodeData.IndexCount, 0); } }
private TemporalFrameCache Prepare(RenderDrawContext context, Texture outputBuffer) { TemporalFrameCache cache = null; var renderView = context.RenderContext.RenderView; Matrix viewMatrix = renderView.View; Matrix projectionMatrix = renderView.Projection; Matrix viewProjectionMatrix = renderView.ViewProjection; Matrix inverseViewMatrix = Matrix.Invert(viewMatrix); Matrix inverseViewProjectionMatrix = Matrix.Invert(viewProjectionMatrix); Vector4 eye = inverseViewMatrix.Row4; float nearclip = renderView.NearClipPlane; float farclip = renderView.FarClipPlane; Vector4 viewInfo = new Vector4(1.0f / projectionMatrix.M11, 1.0f / projectionMatrix.M22, farclip / (farclip - nearclip), (-farclip * nearclip) / (farclip - nearclip) / farclip); Vector3 cameraPos = new Vector3(eye.X, eye.Y, eye.Z); float temporalTime = 0; if (TemporalEffect) { var gameTime = context.RenderContext.Time; double time = gameTime.Total.TotalSeconds; // Keep time in smaller range to prevent temporal noise errors const double scale = 10; double integral = Math.Round(time / scale) * scale; time -= integral; temporalTime = (float)time; cache = GetFrameCache(gameTime.FrameCount, renderView); } var traceBufferSize = GetBufferResolution(outputBuffer, RayTracePassResolution); var roughnessFade = 1 - MathUtil.Clamp(GlossinessThreshold, 0.0f, 1.0f); var maxTraceSamples = MathUtil.Clamp(MaxSteps, 1, 128); // ViewInfo : x-1/Projection[0,0] y-1/Projection[1,1] z-(Far / (Far - Near) w-(-Far * Near) / (Far - Near) / Far) rayTracePassShader.Parameters.Set(SSLRCommonKeys.ViewFarPlane, farclip); rayTracePassShader.Parameters.Set(SSLRCommonKeys.RoughnessFade, roughnessFade); rayTracePassShader.Parameters.Set(SSLRCommonKeys.MaxTraceSamples, maxTraceSamples); rayTracePassShader.Parameters.Set(SSLRCommonKeys.WorldAntiSelfOcclusionBias, WorldAntiSelfOcclusionBias); rayTracePassShader.Parameters.Set(SSLRCommonKeys.BRDFBias, BRDFBias); rayTracePassShader.Parameters.Set(SSLRCommonKeys.TemporalTime, temporalTime); rayTracePassShader.Parameters.Set(SSLRCommonKeys.CameraPosWS, ref cameraPos); rayTracePassShader.Parameters.Set(SSLRCommonKeys.ViewInfo, ref viewInfo); rayTracePassShader.Parameters.Set(SSLRCommonKeys.V, ref viewMatrix); rayTracePassShader.Parameters.Set(SSLRCommonKeys.IVP, ref inverseViewProjectionMatrix); rayTracePassShader.Parameters.Set(SSLRRayTracePassKeys.VP, ref viewProjectionMatrix); rayTracePassShader.Parameters.Set(SSLRRayTracePassKeys.EdgeFadeFactor, EdgeFadeFactor); resolvePassShader.Parameters.Set(SSLRCommonKeys.MaxColorMiplevel, Texture.CalculateMipMapCount(0, outputBuffer.Width, outputBuffer.Height) - 1); resolvePassShader.Parameters.Set(SSLRCommonKeys.TraceSizeMax, Math.Max(traceBufferSize.Width, traceBufferSize.Height) / 2.0f); resolvePassShader.Parameters.Set(SSLRCommonKeys.ViewFarPlane, farclip); resolvePassShader.Parameters.Set(SSLRCommonKeys.RoughnessFade, roughnessFade); resolvePassShader.Parameters.Set(SSLRCommonKeys.TemporalTime, temporalTime); resolvePassShader.Parameters.Set(SSLRCommonKeys.BRDFBias, BRDFBias); resolvePassShader.Parameters.Set(SSLRCommonKeys.CameraPosWS, ref cameraPos); resolvePassShader.Parameters.Set(SSLRCommonKeys.ViewInfo, ref viewInfo); resolvePassShader.Parameters.Set(SSLRCommonKeys.V, ref viewMatrix); resolvePassShader.Parameters.Set(SSLRCommonKeys.IVP, ref inverseViewProjectionMatrix); resolvePassShader.Parameters.Set(SSLRKeys.ResolveSamples, MathUtil.Clamp(ResolveSamples, 1, 8)); resolvePassShader.Parameters.Set(SSLRKeys.ReduceHighlights, ReduceHighlights); if (TemporalEffect) { temporalPassShader.Parameters.Set(SSLRTemporalPassKeys.IVP, ref inverseViewProjectionMatrix); temporalPassShader.Parameters.Set(SSLRTemporalPassKeys.TemporalResponse, TemporalResponse); temporalPassShader.Parameters.Set(SSLRTemporalPassKeys.TemporalScale, TemporalScale); if (cache != null) { temporalPassShader.Parameters.Set(SSLRTemporalPassKeys.prevVP, ref cache.PrevViewProjection); cache.PrevViewProjection = viewProjectionMatrix; } } combinePassShader.Parameters.Set(SSLRCommonKeys.ViewFarPlane, farclip); combinePassShader.Parameters.Set(SSLRCommonKeys.CameraPosWS, ref cameraPos); combinePassShader.Parameters.Set(SSLRCommonKeys.ViewInfo, ref viewInfo); combinePassShader.Parameters.Set(SSLRCommonKeys.V, ref viewMatrix); combinePassShader.Parameters.Set(SSLRCommonKeys.IVP, ref inverseViewProjectionMatrix); return(cache); }
public override LightShaderGroupDynamic CreateLightShaderGroup(RenderDrawContext context, ILightShadowMapShaderGroupData shadowGroup) { return(new SpotLightShaderGroup(shadowGroup)); }
protected virtual void DrawView(RenderContext context, RenderDrawContext drawContext) { var renderSystem = context.RenderSystem; // Z-Prepass var lightProbes = LightProbes && GBufferRenderStage != null; if (lightProbes) { // NOTE: Baking light probes before GBuffer prepass because we are updating some cbuffer parameters needed by Opaque pass that GBuffer pass might upload early PrepareLightprobeConstantBuffer(context); // TODO: Temporarily using ShadowMap shader using (drawContext.QueryManager.BeginProfile(Color.Green, CompositingProfilingKeys.GBuffer)) using (drawContext.PushRenderTargetsAndRestore()) { drawContext.CommandList.Clear(drawContext.CommandList.DepthStencilBuffer, DepthStencilClearOptions.DepthBuffer); drawContext.CommandList.SetRenderTarget(drawContext.CommandList.DepthStencilBuffer, null); // Draw [Main view | Z-Prepass stage] renderSystem.Draw(drawContext, context.RenderView, GBufferRenderStage); } // Bake lightprobes against Z-buffer BakeLightProbes(context, drawContext); } using (drawContext.PushRenderTargetsAndRestore()) { // Draw [Main view | Main stage] if (OpaqueRenderStage != null) { using (drawContext.QueryManager.BeginProfile(Color.Green, CompositingProfilingKeys.Opaque)) { renderSystem.Draw(drawContext, context.RenderView, OpaqueRenderStage); } } Texture depthStencilSRV = null; // Draw [Main view | SubSurface Scattering Post-process] if (SubsurfaceScatteringBlurEffect != null) { var materialIndex = OpaqueRenderStage?.OutputValidator.Find <MaterialIndexTargetSemantic>() ?? -1; if (materialIndex != -1) { using (drawContext.PushRenderTargetsAndRestore()) { depthStencilSRV = ResolveDepthAsSRV(drawContext); var renderTarget = drawContext.CommandList.RenderTargets[0]; var materialIndexRenderTarget = drawContext.CommandList.RenderTargets[materialIndex]; SubsurfaceScatteringBlurEffect.Draw(drawContext, renderTarget, materialIndexRenderTarget, depthStencilSRV, renderTarget); } } } // Draw [Main view | Transparent stage] if (TransparentRenderStage != null) { // Some transparent shaders will require the depth as a shader resource - resolve it only once and set it here using (drawContext.QueryManager.BeginProfile(Color.Green, CompositingProfilingKeys.Transparent)) using (drawContext.PushRenderTargetsAndRestore()) { if (depthStencilSRV is null) { depthStencilSRV = ResolveDepthAsSRV(drawContext); } renderSystem.Draw(drawContext, context.RenderView, TransparentRenderStage); } } var colorTargetIndex = OpaqueRenderStage?.OutputValidator.Find(typeof(ColorTargetSemantic)) ?? -1; if (colorTargetIndex == -1) { return; } // Resolve MSAA targets var renderTargets = currentRenderTargets; var depthStencil = currentDepthStencil; if (actualMultisampleCount != MultisampleCount.None) { using (drawContext.QueryManager.BeginProfile(Color.Green, CompositingProfilingKeys.MsaaResolve)) { ResolveMSAA(drawContext); } renderTargets = currentRenderTargetsNonMSAA; depthStencil = currentDepthStencilNonMSAA; } // Draw [Main view | Light Shafts] if (LightShafts != null) { using (drawContext.QueryManager.BeginProfile(Color.Green, CompositingProfilingKeys.LightShafts)) { LightShafts.Draw(drawContext, depthStencil, renderTargets[colorTargetIndex]); } } // Draw Post-Processing effects if (PostEffects != null) { // NOTE: OpaqueRenderStage can't be null otherwise colorTargetIndex would be -1 PostEffects.Draw(drawContext, OpaqueRenderStage.OutputValidator, renderTargets.Items, depthStencil, viewOutputTarget); } else { if (actualMultisampleCount != MultisampleCount.None) { using (drawContext.QueryManager.BeginProfile(Color.Green, CompositingProfilingKeys.MsaaResolve)) { drawContext.CommandList.Copy(renderTargets[colorTargetIndex], viewOutputTarget); } } } // Free the depth texture since we won't need it anymore if (depthStencilSRV != null) { drawContext.Resolver.ReleaseDepthStenctilAsShaderResource(depthStencilSRV); } } }
public static Texture GenerateCubemap(IServiceRegistry services, RenderDrawContext renderDrawContext, Texture input, int outputSize) { var pixelFormat = input.Format.IsHDR() ? PixelFormat.R16G16B16A16_Float : input.Format.IsSRgb() ? PixelFormat.R8G8B8A8_UNorm_SRgb : PixelFormat.R8G8B8A8_UNorm; return(GenerateCubemap(new CubemapFromTextureRenderer(services, renderDrawContext, input, outputSize, pixelFormat), Vector3.Zero)); }
public override unsafe void ApplyViewParameters(RenderDrawContext context, int viewIndex, ParameterCollection parameters) { // Note: no need to fill CurrentLights since we have no shadow maps base.ApplyViewParameters(context, viewIndex, parameters); var renderView = renderViews[viewIndex]; var viewSize = renderView.ViewSize; var clusterCountX = ((int)viewSize.X + ClusterSize - 1) / ClusterSize; var clusterCountY = ((int)viewSize.Y + ClusterSize - 1) / ClusterSize; // TODO: Additional culling on x/y (to remove corner clusters) // Prepare planes for culling //var viewProjection = renderView.ViewProjection; //Array.Resize(ref zPlanes, ClusterSlices + 1); //for (int z = 0; z <= ClusterSlices; ++z) //{ // var zFactor = (float)z / (float)ClusterSlices; // // // Build planes between nearplane and -farplane (see BoundingFrustum code) // zPlanes[z] = new Plane( // viewProjection.M13 - zFactor * viewProjection.M14, // viewProjection.M23 - zFactor * viewProjection.M24, // viewProjection.M33 - zFactor * viewProjection.M34, // viewProjection.M43 - zFactor * viewProjection.M44); // // zPlanes[z].Normalize(); //} if (pointGroupRenderer.lightClusters == null || lightClustersValues.Length != clusterCountX * clusterCountY * ClusterSlices) { // First time? pointGroupRenderer.lightClusters?.Dispose(); pointGroupRenderer.lightClusters = Texture.New3D(context.GraphicsDevice, clusterCountX, clusterCountY, 8, PixelFormat.R32G32_UInt); lightClustersValues = new Int2[clusterCountX * clusterCountY * ClusterSlices]; } // Initialize cluster with no light (-1) for (int i = 0; i < clusterCountX * clusterCountY * ClusterSlices; ++i) { lightNodes.Add(new LightClusterLinkedNode(LightType.Point, -1, -1)); } // List of clusters moved by this light var movedClusters = new Dictionary <LightClusterLinkedNode, int>(); // Try to use SpecialNearPlane to not waste too much slices in very small depth // Make sure we don't go to more than 10% of max depth var nearPlane = Math.Max(Math.Min(SpecialNearPlane, renderView.FarClipPlane * 0.1f), renderView.NearClipPlane); //var sliceBias = ((renderView.NearClipPlane * renderView.Projection.M33) + renderView.Projection.M43) / (renderView.NearClipPlane * renderView.Projection.M34); // Compute scale and bias so that near_plane..special_near fits in slice 0, then grow exponentionally // log2(specialNear * scale + bias) == 1.0 // log2(far * scale + bias) == ClusterSlices // as a result: clusterDepthScale = (float)(Math.Pow(2.0f, ClusterSlices) - 2.0f) / (renderView.FarClipPlane - nearPlane); clusterDepthBias = 2.0f - clusterDepthScale * nearPlane; //---------------- SPOT LIGHTS ------------------- var lightRange = pointGroupRenderer.spotGroup.LightRanges[viewIndex]; for (int i = lightRange.Start; i < lightRange.End; ++i) { var light = pointGroupRenderer.spotGroup.Lights[i].Light; var spotLight = (LightSpot)light.Type; // Create spot light data var spotLightData = new SpotLightData { PositionWS = light.Position, DirectionWS = light.Direction, AngleOffsetAndInvSquareRadius = new Vector3(spotLight.LightAngleScale, spotLight.LightAngleOffset, spotLight.InvSquareRange), Color = light.Color, }; // Fill list of spot lights spotLights.Add(spotLightData); movedClusters.Clear(); var radius = (float)Math.Sqrt(1.0f / spotLightData.AngleOffsetAndInvSquareRadius.Z); Vector3 positionVS; Vector3.TransformCoordinate(ref spotLightData.PositionWS, ref renderView.View, out positionVS); // TODO: culling (first do it on PointLight, then backport it to SpotLight and improve for SpotLight case) // Find x/y ranges Vector2 clipMin, clipMax; ComputeClipRegion(positionVS, radius, ref renderView.Projection, out clipMin, out clipMax); var tileStartX = MathUtil.Clamp((int)((clipMin.X * 0.5f + 0.5f) * viewSize.X / ClusterSize), 0, clusterCountX); var tileEndX = MathUtil.Clamp((int)((clipMax.X * 0.5f + 0.5f) * viewSize.X / ClusterSize) + 1, 0, clusterCountX); var tileStartY = MathUtil.Clamp((int)((-clipMax.Y * 0.5f + 0.5f) * viewSize.Y / ClusterSize), 0, clusterCountY); var tileEndY = MathUtil.Clamp((int)((-clipMin.Y * 0.5f + 0.5f) * viewSize.Y / ClusterSize) + 1, 0, clusterCountY); // Find z range (project using Projection matrix) var startZ = -positionVS.Z - radius; var endZ = -positionVS.Z + radius; var tileStartZ = MathUtil.Clamp((int)Math.Log(startZ * clusterDepthScale + clusterDepthBias, 2.0f), 0, ClusterSlices); var tileEndZ = MathUtil.Clamp((int)Math.Log(endZ * clusterDepthScale + clusterDepthBias, 2.0f) + 1, 0, ClusterSlices); for (int z = tileStartZ; z < tileEndZ; ++z) { for (int y = tileStartY; y < tileEndY; ++y) { for (int x = tileStartX; x < tileEndX; ++x) { AddLightToCluster(movedClusters, LightType.Spot, i - lightRange.Start, x + (y + z * clusterCountY) * clusterCountX); } } } } //---------------- POINT LIGHTS ------------------- lightRange = LightRanges[viewIndex]; for (int i = lightRange.Start; i < lightRange.End; ++i) { var light = Lights[i].Light; var pointLight = (LightPoint)light.Type; // Create point light data var pointLightData = new PointLightData { PositionWS = light.Position, InvSquareRadius = pointLight.InvSquareRadius, Color = light.Color, }; // Fill list of point lights pointLights.Add(pointLightData); movedClusters.Clear(); var radius = (float)Math.Sqrt(1.0f / pointLightData.InvSquareRadius); Vector3 positionVS; Vector3.TransformCoordinate(ref pointLightData.PositionWS, ref renderView.View, out positionVS); //Vector3 positionScreen; //Vector3.TransformCoordinate(ref pointLightData.PositionWS, ref renderView.ViewProjection, out positionScreen); // Find x/y ranges Vector2 clipMin, clipMax; ComputeClipRegion(positionVS, radius, ref renderView.Projection, out clipMin, out clipMax); var tileStartX = MathUtil.Clamp((int)((clipMin.X * 0.5f + 0.5f) * viewSize.X / ClusterSize), 0, clusterCountX); var tileEndX = MathUtil.Clamp((int)((clipMax.X * 0.5f + 0.5f) * viewSize.X / ClusterSize) + 1, 0, clusterCountX); var tileStartY = MathUtil.Clamp((int)((-clipMax.Y * 0.5f + 0.5f) * viewSize.Y / ClusterSize), 0, clusterCountY); var tileEndY = MathUtil.Clamp((int)((-clipMin.Y * 0.5f + 0.5f) * viewSize.Y / ClusterSize) + 1, 0, clusterCountY); // Find z range (project using Projection matrix) var startZ = -positionVS.Z - radius; var endZ = -positionVS.Z + radius; //var centerZ = (int)(positionVS.Z * ClusterDepthScale + ClusterDepthBias); var tileStartZ = MathUtil.Clamp((int)Math.Log(startZ * clusterDepthScale + clusterDepthBias, 2.0f), 0, ClusterSlices); var tileEndZ = MathUtil.Clamp((int)Math.Log(endZ * clusterDepthScale + clusterDepthBias, 2.0f) + 1, 0, ClusterSlices); for (int z = tileStartZ; z < tileEndZ; ++z) { // TODO: Additional culling on x/y (to remove corner clusters) // See "Practical Clustered Shading" for details //if (z != centerZ) //{ // var plane = z < centerZ ? zPlanes[z + 1] : -zPlanes[z]; // // positionScreen = Plane.DotCoordinate(ref plane, ref positionScreen, out ) //} for (int y = tileStartY; y < tileEndY; ++y) { for (int x = tileStartX; x < tileEndX; ++x) { AddLightToCluster(movedClusters, LightType.Point, i - lightRange.Start, x + (y + z * clusterCountY) * clusterCountX); } } } } // Finish clusters by making their last element unique and building clusterInfos movedClusters.Clear(); for (int i = 0; i < clusterCountX * clusterCountY * ClusterSlices; ++i) { FinishCluster(movedClusters, i); } // Prepare light clusters for (int i = 0; i < clusterCountX * clusterCountY * ClusterSlices; ++i) { var clusterId = lightNodes[i].NextNode; lightClustersValues[i] = clusterId != -1 ? clusterInfos[clusterId] : new Int2(0, 0); } // Upload data to texture using (context.LockCommandList()) { fixed(Int2 *dataPtr = lightClustersValues) context.CommandList.UpdateSubresource(pointGroupRenderer.lightClusters, 0, new DataBox((IntPtr)dataPtr, sizeof(Int2) * clusterCountX, sizeof(Int2) * clusterCountX * clusterCountY)); // PointLights: Ensure size and update if (pointLights.Count > 0) { if (pointGroupRenderer.pointLightsBuffer == null || pointGroupRenderer.pointLightsBuffer.SizeInBytes < pointLights.Count * sizeof(PointLightData)) { pointGroupRenderer.pointLightsBuffer?.Dispose(); pointGroupRenderer.pointLightsBuffer = Buffer.New(context.GraphicsDevice, MathUtil.NextPowerOfTwo(pointLights.Count * sizeof(PointLightData)), 0, BufferFlags.ShaderResource, PixelFormat.R32G32B32A32_Float); } fixed(PointLightData *pointLightsPtr = pointLights.Items) context.CommandList.UpdateSubresource(pointGroupRenderer.pointLightsBuffer, 0, new DataBox((IntPtr)pointLightsPtr, 0, 0), new ResourceRegion(0, 0, 0, pointLights.Count * sizeof(PointLightData), 1, 1)); } // SpotLights: Ensure size and update if (spotLights.Count > 0) { if (pointGroupRenderer.spotLightsBuffer == null || pointGroupRenderer.spotLightsBuffer.SizeInBytes < spotLights.Count * sizeof(SpotLightData)) { pointGroupRenderer.spotLightsBuffer?.Dispose(); pointGroupRenderer.spotLightsBuffer = Buffer.New(context.GraphicsDevice, MathUtil.NextPowerOfTwo(spotLights.Count * sizeof(SpotLightData)), 0, BufferFlags.ShaderResource, PixelFormat.R32G32B32A32_Float); } fixed(SpotLightData *spotLightsPtr = spotLights.Items) context.CommandList.UpdateSubresource(pointGroupRenderer.spotLightsBuffer, 0, new DataBox((IntPtr)spotLightsPtr, 0, 0), new ResourceRegion(0, 0, 0, spotLights.Count * sizeof(SpotLightData), 1, 1)); } // LightIndices: Ensure size and update if (lightIndices.Count > 0) { if (pointGroupRenderer.lightIndicesBuffer == null || pointGroupRenderer.lightIndicesBuffer.SizeInBytes < lightIndices.Count * sizeof(int)) { pointGroupRenderer.lightIndicesBuffer?.Dispose(); pointGroupRenderer.lightIndicesBuffer = Buffer.New(context.GraphicsDevice, MathUtil.NextPowerOfTwo(lightIndices.Count * sizeof(int)), 0, BufferFlags.ShaderResource, PixelFormat.R32_UInt); } fixed(int *lightIndicesPtr = lightIndices.Items) context.CommandList.UpdateSubresource(pointGroupRenderer.lightIndicesBuffer, 0, new DataBox((IntPtr)lightIndicesPtr, 0, 0), new ResourceRegion(0, 0, 0, lightIndices.Count * sizeof(int), 1, 1)); } } // Clear data pointLights.Clear(); spotLights.Clear(); lightIndices.Clear(); lightNodes.Clear(); clusterInfos.Clear(); // Set resources parameters.Set(LightClusteredPointGroupKeys.PointLights, pointGroupRenderer.pointLightsBuffer); parameters.Set(LightClusteredSpotGroupKeys.SpotLights, pointGroupRenderer.spotLightsBuffer); parameters.Set(LightClusteredKeys.LightIndices, pointGroupRenderer.lightIndicesBuffer); parameters.Set(LightClusteredKeys.LightClusters, pointGroupRenderer.lightClusters); parameters.Set(LightClusteredKeys.ClusterDepthScale, clusterDepthScale); parameters.Set(LightClusteredKeys.ClusterDepthBias, clusterDepthBias); }
// Naive approach: 6 passes protected void DrawCoreNaive(RenderDrawContext context) { var originalTexture = GetSafeInput(0); var outputTexture = GetSafeOutput(0); if (rhombiTapOffsetsDirty) { calculateRhombiOffsets(); } var tapNumber = 2 * tapCount - 1; directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurKeys.Count, tapCount); directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurKeys.TotalTap, tapNumber); directionalBlurEffect.EffectInstance.UpdateEffect(context.GraphicsDevice); directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Radius, Radius); directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.TapWeights, tapWeights); directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.CoCReference, CoCStrength); // Vertical blur var blurAngle = MathUtil.PiOverTwo + Phase; directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle))); var verticalBlurTexture = NewScopedRenderTarget2D(originalTexture.Description); directionalBlurEffect.SetInput(0, originalTexture); directionalBlurEffect.SetOutput(verticalBlurTexture); directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiABVertical_tap{0}_radius{1}", tapNumber, (int)Radius); // Rhombi A (top left) blurAngle = 7f * MathUtil.Pi / 6f + Phase; directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle))); var rhombiA = NewScopedRenderTarget2D(originalTexture.Description); directionalBlurEffect.SetInput(0, verticalBlurTexture); directionalBlurEffect.SetOutput(rhombiA); directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiA_tap{0}_radius{1}", tapNumber, (int)Radius); // Rhombi B (top right) blurAngle = -MathUtil.Pi / 6f + Phase; directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle))); var rhombiB = NewScopedRenderTarget2D(originalTexture.Description); directionalBlurEffect.SetInput(0, verticalBlurTexture); directionalBlurEffect.SetOutput(rhombiB); directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiB_tap{0}_radius{1}", tapNumber, (int)Radius); //Rhombi C (bottom) blurAngle = 7f * MathUtil.Pi / 6f + Phase; directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle))); var rhombiCTmp = NewScopedRenderTarget2D(originalTexture.Description); directionalBlurEffect.SetInput(0, originalTexture); directionalBlurEffect.SetOutput(rhombiCTmp); directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiCTmp_tap{0}_radius{1}", tapNumber, (int)Radius); blurAngle = -MathUtil.Pi / 6f + Phase; directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle))); var rhombiC = NewScopedRenderTarget2D(originalTexture.Description); directionalBlurEffect.SetInput(0, rhombiCTmp); directionalBlurEffect.SetOutput(rhombiC); directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiC_tap{0}_radius{1}", tapNumber, (int)Radius); // Final pass outputting the average of the 3 blurs finalCombineEffect.SetInput(0, rhombiA); finalCombineEffect.SetInput(1, rhombiB); finalCombineEffect.SetInput(2, rhombiC); finalCombineEffect.SetOutput(outputTexture); finalCombineEffect.Parameters.Set(TripleRhombiCombineShaderKeys.RhombiTapOffsets, rhombiTapOffsets); finalCombineEffect.Draw(context, name: "TripleRhombiBokehCombine"); }
public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { base.Draw(context, renderView, renderViewStage, startIndex, endIndex); var currentRenderFrame = context.RenderContext.Tags.Get(RenderFrame.Current); var uiProcessor = renderView.SceneInstance.GetProcessor <UIRenderProcessor>(); if (uiProcessor == null) { return; } //foreach (var uiRoot in uiProcessor.UIRoots) //{ // // Perform culling on group and accept // if (!renderView.SceneCameraRenderer.CullingMask.Contains(uiRoot.UIComponent.Entity.Group)) // continue; // // skips empty UI elements // if (uiRoot.UIComponent.RootElement == null) // continue; // // Project the position // // TODO: This code is duplicated from SpriteComponent -> unify it at higher level? // var worldPosition = new Vector4(uiRoot.TransformComponent.WorldMatrix.TranslationVector, 1.0f); // float projectedZ; // if (uiRoot.UIComponent.IsFullScreen) // { // projectedZ = -uiRoot.TransformComponent.WorldMatrix.M43; // } // else // { // Vector4 projectedPosition; // var cameraComponent = renderView.Camera; // if (cameraComponent == null) // continue; // Vector4.Transform(ref worldPosition, ref cameraComponent.ViewProjectionMatrix, out projectedPosition); // projectedZ = projectedPosition.Z / projectedPosition.W; // } // transparentList.Add(new RenderItem(this, uiRoot, projectedZ)); //} // build the list of the UI elements to render uiElementStates.Clear(); for (var index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; var renderNode = GetRenderNode(renderNodeReference); var renderElement = (RenderUIElement)renderNode.RenderObject; uiElementStates.Add(renderElement); } // evaluate the current draw time (game instance is null for thumbnails) var drawTime = game != null ? game.DrawTime : new GameTime(); // update the rendering context renderingContext.GraphicsContext = context.GraphicsContext; renderingContext.Time = drawTime; renderingContext.RenderTarget = currentRenderFrame.RenderTargets[0]; // TODO: avoid hardcoded index 0 var viewport = context.CommandList.Viewport; // cache the ratio between viewport and target. var viewportSize = viewport.Size; viewportTargetRatio = new Vector2(viewportSize.X / renderingContext.RenderTarget.Width, viewportSize.Y / renderingContext.RenderTarget.Height); viewportOffset = new Vector2(viewport.X / viewport.Width, viewport.Y / viewport.Height); // compact all the pointer events that happened since last frame to avoid performing useless hit tests. CompactPointerEvents(); // allocate temporary graphics resources if needed Texture scopedDepthBuffer = null; foreach (var uiElement in uiElementStates) { if (uiElement.UIComponent.IsFullScreen) { var renderTarget = renderingContext.RenderTarget; var description = TextureDescription.New2D(renderTarget.Width, renderTarget.Height, PixelFormat.D24_UNorm_S8_UInt, TextureFlags.DepthStencil); scopedDepthBuffer = context.RenderContext.Allocator.GetTemporaryTexture(description); break; } } // render the UI elements of all the entities foreach (var uiElementState in uiElementStates) { var uiComponent = uiElementState.UIComponent; var rootElement = uiComponent.RootElement; if (rootElement == null) { continue; } var updatableRootElement = (IUIElementUpdate)rootElement; // calculate the size of the virtual resolution depending on target size (UI canvas) var virtualResolution = uiComponent.Resolution; if (uiComponent.IsFullScreen) { //var targetSize = viewportSize; var targetSize = new Vector2(renderingContext.RenderTarget.Width, renderingContext.RenderTarget.Height); // update the virtual resolution of the renderer if (uiComponent.ResolutionStretch == ResolutionStretch.FixedWidthAdaptableHeight) { virtualResolution.Y = virtualResolution.X * targetSize.Y / targetSize.X; } if (uiComponent.ResolutionStretch == ResolutionStretch.FixedHeightAdaptableWidth) { virtualResolution.X = virtualResolution.Y * targetSize.X / targetSize.Y; } viewParameters.Update(uiComponent.Entity, virtualResolution); } else { var cameraComponent = context.RenderContext.Tags.Get(CameraComponentRendererExtensions.Current); if (cameraComponent != null) { viewParameters.Update(uiComponent.Entity, cameraComponent); } } // Analyze the input and trigger the UI element touch and key events // Note: this is done before measuring/arranging/drawing the element in order to avoid one frame latency on clicks. // But by doing so the world matrices taken for hit test are the ones calculated during last frame. using (Profiler.Begin(UIProfilerKeys.TouchEventsUpdate)) { foreach (var uiState in uiElementStates) { if (uiState.UIComponent.RootElement == null) { continue; } UpdateMouseOver(uiState); UpdateTouchEvents(uiState, drawTime); } } // update the rendering context values specific to this element renderingContext.Resolution = virtualResolution; renderingContext.ViewMatrix = viewParameters.ViewMatrix; renderingContext.ProjectionMatrix = viewParameters.ProjectionMatrix; renderingContext.ViewProjectionMatrix = viewParameters.ViewProjectionMatrix; renderingContext.DepthStencilBuffer = uiComponent.IsFullScreen ? scopedDepthBuffer : currentRenderFrame.DepthStencil; renderingContext.ShouldSnapText = uiComponent.SnapText; // calculate an estimate of the UI real size by projecting the element virtual resolution on the screen var virtualOrigin = viewParameters.ViewProjectionMatrix.Row4; var virtualWidth = new Vector4(virtualResolution.X / 2, 0, 0, 1); var virtualHeight = new Vector4(0, virtualResolution.Y / 2, 0, 1); var transformedVirtualWidth = Vector4.Zero; var transformedVirtualHeight = Vector4.Zero; for (var i = 0; i < 4; i++) { transformedVirtualWidth[i] = virtualWidth[0] * viewParameters.ViewProjectionMatrix[0 + i] + viewParameters.ViewProjectionMatrix[12 + i]; transformedVirtualHeight[i] = virtualHeight[1] * viewParameters.ViewProjectionMatrix[4 + i] + viewParameters.ViewProjectionMatrix[12 + i]; } var projectedOrigin = virtualOrigin.XY() / virtualOrigin.W; var projectedVirtualWidth = viewportSize * (transformedVirtualWidth.XY() / transformedVirtualWidth.W - projectedOrigin); var projectedVirtualHeight = viewportSize * (transformedVirtualHeight.XY() / transformedVirtualHeight.W - projectedOrigin); // Set default services rootElement.UIElementServices = new UIElementServices { Services = RenderSystem.Services }; // set default resource dictionary rootElement.ResourceDictionary = uiSystem.DefaultResourceDictionary; // update layouting context. layoutingContext.VirtualResolution = virtualResolution; layoutingContext.RealResolution = viewportSize; layoutingContext.RealVirtualResolutionRatio = new Vector2(projectedVirtualWidth.Length() / virtualResolution.X, projectedVirtualHeight.Length() / virtualResolution.Y); rootElement.LayoutingContext = layoutingContext; // perform the time-based updates of the UI element updatableRootElement.Update(drawTime); // update the UI element disposition rootElement.Measure(virtualResolution); rootElement.Arrange(virtualResolution, false); // update the UI element hierarchical properties var rootMatrix = Matrix.Translation(-virtualResolution / 2); // UI world is rotated of 180degrees along Ox updatableRootElement.UpdateWorldMatrix(ref rootMatrix, rootMatrix != uiElementState.LastRootMatrix); updatableRootElement.UpdateElementState(0); uiElementState.LastRootMatrix = rootMatrix; // clear and set the Depth buffer as required if (uiComponent.IsFullScreen) { context.CommandList.Clear(renderingContext.DepthStencilBuffer, DepthStencilClearOptions.DepthBuffer | DepthStencilClearOptions.Stencil); } context.CommandList.SetRenderTarget(renderingContext.DepthStencilBuffer, renderingContext.RenderTarget); // start the image draw session renderingContext.StencilTestReferenceValue = 0; batch.Begin(context.GraphicsContext, ref viewParameters.ViewProjectionMatrix, BlendStates.AlphaBlend, uiSystem.KeepStencilValueState, renderingContext.StencilTestReferenceValue); // Render the UI elements in the final render target ReccursiveDrawWithClipping(context, rootElement); // end the image draw session batch.End(); } // clear the list of compacted pointer events of time frame ClearPointerEvents(); // revert the depth stencil buffer to the default value context.CommandList.SetRenderTargets(currentRenderFrame.DepthStencil, currentRenderFrame.RenderTargets); // Release scroped texture if (scopedDepthBuffer != null) { context.RenderContext.Allocator.ReleaseReference(scopedDepthBuffer); } }
protected override void DrawCore(RenderDrawContext context) { var originalColorBuffer = GetSafeInput(0); var originalDepthBuffer = GetSafeInput(1); var outputTexture = GetSafeOutput(0); var camera = context.RenderContext.GetCurrentCamera(); //--------------------------------- // Ambient Occlusion //--------------------------------- var tempWidth = (originalColorBuffer.Width * (int)TempSize) / (int)TemporaryBufferSize.SizeFull; var tempHeight = (originalColorBuffer.Height * (int)TempSize) / (int)TemporaryBufferSize.SizeFull; var aoTexture1 = NewScopedRenderTarget2D(tempWidth, tempHeight, PixelFormat.R8_UNorm, 1); var aoTexture2 = NewScopedRenderTarget2D(tempWidth, tempHeight, PixelFormat.R8_UNorm, 1); aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOKeys.Count, NumberOfSamples > 0 ? NumberOfSamples : 9); if (camera != null) { // Set Near/Far pre-calculated factors to speed up the linear depth reconstruction aoRawImageEffect.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(camera.NearClipPlane, camera.FarClipPlane)); Vector4 ScreenSize = new Vector4(originalColorBuffer.Width, originalColorBuffer.Height, 0, 0); ScreenSize.Z = ScreenSize.X / ScreenSize.Y; aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ScreenInfo, ScreenSize); // Projection infor used to reconstruct the View space position from linear depth var p00 = camera.ProjectionMatrix.M11; var p11 = camera.ProjectionMatrix.M22; var p02 = camera.ProjectionMatrix.M13; var p12 = camera.ProjectionMatrix.M23; Vector4 projInfo = new Vector4(-2.0f / (ScreenSize.X * p00), -2.0f / (ScreenSize.Y * p11), (1.0f - p02) / p00, (1.0f + p12) / p11); aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ProjInfo, projInfo); //********************************** // User parameters aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamProjScale, ParamProjScale); aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamIntensity, ParamIntensity); aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamBias, ParamBias); aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamRadius, ParamRadius); aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamRadiusSquared, ParamRadius * ParamRadius); } aoRawImageEffect.SetInput(0, originalDepthBuffer); aoRawImageEffect.SetOutput(aoTexture1); aoRawImageEffect.Draw(context, "AmbientOcclusionRawAO"); for (int bounces = 0; bounces < NumberOfBounces; bounces++) { if (offsetsWeights == null) { offsetsWeights = new [] // { 0.356642f, 0.239400f, 0.072410f, 0.009869f }; // { 0.398943f, 0.241971f, 0.053991f, 0.004432f, 0.000134f }; // stddev = 1.0 { 0.153170f, 0.144893f, 0.122649f, 0.092902f, 0.062970f }; // stddev = 2.0 // { 0.111220f, 0.107798f, 0.098151f, 0.083953f, 0.067458f, 0.050920f, 0.036108f }; // stddev = 3.0 nameGaussianBlurH = string.Format("AmbientOcclusionBlurH{0}x{0}", offsetsWeights.Length); nameGaussianBlurV = string.Format("AmbientOcclusionBlurV{0}x{0}", offsetsWeights.Length); } if (camera != null) { // Set Near/Far pre-calculated factors to speed up the linear depth reconstruction blurH.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(camera.NearClipPlane, camera.FarClipPlane)); blurV.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(camera.NearClipPlane, camera.FarClipPlane)); } // Update permutation parameters blurH.Parameters.Set(AmbientOcclusionBlurKeys.Count, offsetsWeights.Length); blurH.Parameters.Set(AmbientOcclusionBlurKeys.BlurScale, BlurScale); blurH.Parameters.Set(AmbientOcclusionBlurKeys.EdgeSharpness, EdgeSharpness); blurH.EffectInstance.UpdateEffect(context.GraphicsDevice); blurV.Parameters.Set(AmbientOcclusionBlurKeys.Count, offsetsWeights.Length); blurV.Parameters.Set(AmbientOcclusionBlurKeys.BlurScale, BlurScale); blurV.Parameters.Set(AmbientOcclusionBlurKeys.EdgeSharpness, EdgeSharpness); blurV.EffectInstance.UpdateEffect(context.GraphicsDevice); // Update parameters blurH.Parameters.Set(AmbientOcclusionBlurShaderKeys.Weights, offsetsWeights); blurV.Parameters.Set(AmbientOcclusionBlurShaderKeys.Weights, offsetsWeights); // Horizontal pass blurH.SetInput(0, aoTexture1); blurH.SetInput(1, originalDepthBuffer); blurH.SetOutput(aoTexture2); blurH.Draw(context, nameGaussianBlurH); // Vertical pass blurV.SetInput(0, aoTexture2); blurV.SetInput(1, originalDepthBuffer); blurV.SetOutput(aoTexture1); blurV.Draw(context, nameGaussianBlurV); } aoApplyImageEffect.SetInput(0, originalColorBuffer); aoApplyImageEffect.SetInput(1, aoTexture1); aoApplyImageEffect.SetOutput(outputTexture); aoApplyImageEffect.Draw(context, "AmbientOcclusionApply"); }
public override void Prepare(RenderDrawContext context) { renderVoxelVolumeData = Context.VisibilityGroup.Tags.Get(CurrentProcessedVoxelVolumes); if (renderVoxelVolumeData is null) { return; } foreach (var processedVolumeKeyValue in renderVoxelVolumeData) { var processedVolume = processedVolumeKeyValue.Value; foreach (VoxelizationPass pass in processedVolume.passList.passes) { var viewFeature = pass.view.Features[RootRenderFeature.Index]; // Find a PerView layout from an effect in normal state ViewResourceGroupLayout firstViewLayout = null; foreach (var viewLayout in viewFeature.Layouts) { // Only process view layouts in normal state if (viewLayout.State != RenderEffectState.Normal) { continue; } var viewLighting = viewLayout.GetLogicalGroup(VoxelizerStorerCasterKey); if (viewLighting.Hash != ObjectId.Empty) { firstViewLayout = viewLayout; break; } } // Nothing found for this view (no effects in normal state) if (firstViewLayout is null) { continue; } var viewParameters = new ParameterCollection(); var firstViewLighting = firstViewLayout.GetLogicalGroup(VoxelizerStorerCasterKey); // Prepare layout (should be similar for all PerView) { // Generate layout var viewParameterLayout = new ParameterCollectionLayout(); viewParameterLayout.ProcessLogicalGroup(firstViewLayout, ref firstViewLighting); viewParameters.UpdateLayout(viewParameterLayout); } ParameterCollection VSViewParameters = viewParameters; pass.storer.ApplyVoxelizationParameters(VSViewParameters); foreach (var attr in processedVolume.Attributes) { attr.Attribute.ApplyVoxelizationParameters(VSViewParameters); } foreach (var viewLayout in viewFeature.Layouts) { if (viewLayout.State != RenderEffectState.Normal) { continue; } var voxelizerStorer = viewLayout.GetLogicalGroup(VoxelizerStorerCasterKey); if (voxelizerStorer.Hash == ObjectId.Empty) { continue; } if (voxelizerStorer.Hash != firstViewLighting.Hash) { throw new InvalidOperationException("PerView VoxelizerStorer layout differs between different RenderObject in the same RenderView."); } var resourceGroup = viewLayout.Entries[pass.view.Index].Resources; resourceGroup.UpdateLogicalGroup(ref voxelizerStorer, VSViewParameters); } } } }
/// <inheritdoc/> public override unsafe void Prepare(RenderDrawContext context) { // Inspect each RenderObject (= ParticleEmitter) to determine if its required vertex buffer size has changed foreach (var renderObject in RenderObjects) { var renderParticleEmitter = (RenderParticleEmitter)renderObject; renderParticleEmitter.ParticleEmitter.PrepareForDraw(out renderParticleEmitter.HasVertexBufferChanged, out renderParticleEmitter.VertexSize, out renderParticleEmitter.VertexCount); // TODO: ParticleMaterial should set this up var materialInfo = (ParticleMaterialInfo)renderParticleEmitter.ParticleMaterialInfo; var colorShade = renderParticleEmitter.Color.ToColorSpace(context.GraphicsDevice.ColorSpace); materialInfo?.Material.Parameters.Set(ParticleBaseKeys.ColorScale, colorShade); } // Calculate the total vertex buffer size required int totalVertexBufferSize = 0; int highestIndexCount = 0; var renderParticleNodeData = RenderData.GetData(renderParticleNodeKey); // Reset pipeline states if necessary for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; if (renderParticleEmitter.HasVertexBufferChanged) { // Reset pipeline state, so input layout is regenerated if (renderNode.RenderEffect != null) { renderNode.RenderEffect.PipelineState = null; } } // Write some attributes back which we will need for rendering later var vertexBuilder = renderParticleEmitter.ParticleEmitter.VertexBuilder; var newNodeData = new RenderAttributesPerNode { VertexBufferOffset = totalVertexBufferSize, VertexBufferSize = renderParticleEmitter.VertexSize * renderParticleEmitter.VertexCount, VertexBufferStride = renderParticleEmitter.VertexSize, IndexCount = vertexBuilder.LivingQuads * vertexBuilder.IndicesPerQuad, }; renderParticleNodeData[new RenderNodeReference(renderNodeIndex)] = newNodeData; totalVertexBufferSize += newNodeData.VertexBufferSize; if (newNodeData.IndexCount > highestIndexCount) { highestIndexCount = newNodeData.IndexCount; } } base.Prepare(context); // Assign descriptor sets to each render node var resourceGroupPool = ResourceGroupPool; for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; // Ignore fallback effects if (renderNode.RenderEffect.State != RenderEffectState.Normal) { continue; } // Collect materials and create associated MaterialInfo (includes reflection) first time // TODO: We assume same material will generate same ResourceGroup (i.e. same resources declared in same order) // Need to offer some protection if this invariant is violated (or support it if it can actually happen in real scenario) var material = renderParticleEmitter.ParticleEmitter.Material; var materialInfo = renderParticleEmitter.ParticleMaterialInfo; var materialParameters = material.Parameters; if (!MaterialRenderFeature.UpdateMaterial(RenderSystem, context, materialInfo, perMaterialDescriptorSetSlot.Index, renderNode.RenderEffect, materialParameters)) { continue; } var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference); resourceGroupPool[descriptorSetPoolOffset + perMaterialDescriptorSetSlot.Index] = materialInfo.Resources; } particleBufferContext.AllocateBuffers(context, totalVertexBufferSize, highestIndexCount); BuildParticleBuffers(context); }
public void Draw(RenderDrawContext drawContext, Texture inputDepthStencil, Texture output) { SetInput(0, inputDepthStencil); SetOutput(output); Draw(drawContext); }
public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex) { base.Draw(context, renderView, renderViewStage, startIndex, endIndex); var isMultisample = RenderSystem.RenderStages[renderViewStage.Index].Output.MultisampleCount != MultisampleCount.None; var batchContext = threadContext.Value; Matrix viewInverse; Matrix.Invert(ref renderView.View, out viewInverse); uint previousBatchState = uint.MaxValue; //TODO string comparison ...? var isPicking = RenderSystem.RenderStages[renderViewStage.Index].Name == "Picking"; bool hasBegin = false; for (var index = startIndex; index < endIndex; index++) { var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode; var renderNode = GetRenderNode(renderNodeReference); var renderSprite = (RenderSprite)renderNode.RenderObject; var sprite = renderSprite.Sprite; if (sprite == null) { continue; } // TODO: this should probably be moved to Prepare() // Project the position // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object var worldPosition = new Vector4(renderSprite.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref renderView.ViewProjection, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; BlendModes blendMode; EffectInstance currentEffect = null; if (isPicking) { blendMode = BlendModes.Default; currentEffect = batchContext.GetOrCreatePickingSpriteEffect(RenderSystem.EffectSystem); } else { var spriteBlend = renderSprite.BlendMode; if (spriteBlend == SpriteBlend.Auto) { spriteBlend = sprite.IsTransparent ? SpriteBlend.AlphaBlend : SpriteBlend.None; } if (spriteBlend == SpriteBlend.AlphaBlend) { blendMode = renderSprite.PremultipliedAlpha ? BlendModes.Alpha : BlendModes.NonPremultiplied; } else { blendMode = spriteBlendToBlendMode[spriteBlend]; } } // Check if the current blend state has changed in any way, if not // Note! It doesn't really matter in what order we build the bitmask, the result is not preserved anywhere except in this method var currentBatchState = (uint)blendMode; currentBatchState = (currentBatchState << 1) + (renderSprite.IgnoreDepth ? 1U : 0U); currentBatchState = (currentBatchState << 1) + (renderSprite.IsAlphaCutoff ? 1U : 0U); currentBatchState = (currentBatchState << 2) + ((uint)renderSprite.Sampler); if (previousBatchState != currentBatchState) { var blendState = blendModeToDescription[blendMode]; if (renderSprite.IsAlphaCutoff) { currentEffect = batchContext.GetOrCreateAlphaCutoffSpriteEffect(RenderSystem.EffectSystem); } var depthStencilState = renderSprite.IgnoreDepth ? DepthStencilStates.None : DepthStencilStates.Default; var samplerState = context.GraphicsDevice.SamplerStates.LinearClamp; if (renderSprite.Sampler != SpriteSampler.LinearClamp) { switch (renderSprite.Sampler) { case SpriteSampler.PointClamp: samplerState = context.GraphicsDevice.SamplerStates.PointClamp; break; case SpriteSampler.AnisotropicClamp: samplerState = context.GraphicsDevice.SamplerStates.AnisotropicClamp; break; } } if (hasBegin) { lock (batchEndLocker) { batchContext.SpriteBatch.End(); } } var rasterizerState = RasterizerStates.CullNone; if (isMultisample) { rasterizerState.MultisampleCount = RenderSystem.RenderStages[renderViewStage.Index].Output.MultisampleCount; rasterizerState.MultisampleAntiAliasLine = true; } batchContext.SpriteBatch.Begin(context.GraphicsContext, renderView.ViewProjection, SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, rasterizerState, currentEffect); hasBegin = true; } previousBatchState = currentBatchState; var sourceRegion = sprite.Region; var texture = sprite.Texture; var color = renderSprite.Color; if (isPicking) // TODO move this code corresponding to picking out of the runtime code. { var compId = RuntimeIdHelper.ToRuntimeId(renderSprite.Source); color = new Color4(compId, 0.0f, 0.0f, 0.0f); } // skip the sprite if no texture is set. if (texture == null) { continue; } // determine the element world matrix depending on the type of sprite var worldMatrix = renderSprite.WorldMatrix; if (renderSprite.SpriteType == SpriteType.Billboard) { worldMatrix = viewInverse; var worldMatrixRow1 = worldMatrix.Row1; var worldMatrixRow2 = worldMatrix.Row2; // remove scale of the camera worldMatrixRow1 /= ((Vector3)viewInverse.Row1).Length(); worldMatrixRow2 /= ((Vector3)viewInverse.Row2).Length(); // set the scale of the object worldMatrixRow1 *= ((Vector3)renderSprite.WorldMatrix.Row1).Length(); worldMatrixRow2 *= ((Vector3)renderSprite.WorldMatrix.Row2).Length(); worldMatrix.Row1 = worldMatrixRow1; worldMatrix.Row2 = worldMatrixRow2; // set the position worldMatrix.TranslationVector = renderSprite.WorldMatrix.TranslationVector; // set the rotation var localRotationZ = renderSprite.RotationEulerZ; if (localRotationZ != 0) { worldMatrix = Matrix.RotationZ(localRotationZ) * worldMatrix; } } // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image) var normalizedCenter = new Vector2(sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - sprite.Center.Y / sourceRegion.Height); if (sprite.Orientation == ImageOrientation.Rotated90) { var oldCenterX = normalizedCenter.X; normalizedCenter.X = -normalizedCenter.Y; normalizedCenter.Y = oldCenterX; } // apply the offset due to the center of the sprite var centerOffset = Vector2.Modulate(normalizedCenter, sprite.SizeInternal); worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21; worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22; worldMatrix.M43 -= centerOffset.X * worldMatrix.M13 + centerOffset.Y * worldMatrix.M23; // adapt the source region to match what is expected at full resolution if (texture.ViewType == ViewType.Full && texture.ViewWidth != texture.FullQualitySize.Width) { var fullQualitySize = texture.FullQualitySize; var horizontalRatio = texture.ViewWidth / (float)fullQualitySize.Width; var verticalRatio = texture.ViewHeight / (float)fullQualitySize.Height; sourceRegion.X *= horizontalRatio; sourceRegion.Width *= horizontalRatio; sourceRegion.Y *= verticalRatio; sourceRegion.Height *= verticalRatio; } // register resource usage. Context.StreamingManager?.StreamResources(texture); // draw the sprite batchContext.SpriteBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref sprite.SizeInternal, ref color, sprite.Orientation, renderSprite.Swizzle, projectedZ); } if (hasBegin) { lock (batchEndLocker) { batchContext.SpriteBatch.End(); } } }