/// <summary> /// Creates the configuration controls of this asset. /// </summary> public static void AddControls(HorizonBasedAmbientOcclusion asset, Window owner, ComboBox comboBoxResource) { GroupBox groupGeneral = CommonControls.Group("General", owner); #region Quality var quality = CommonControls.ComboBox("Quality", groupGeneral); // Add textures name quality.Items.Add("Low"); quality.Items.Add("Middle"); quality.Items.Add("High"); // Events quality.ItemIndexChanged += delegate { switch (quality.ItemIndex) { case 0: asset.Quality = HorizonBasedAmbientOcclusion.QualityType.LowQuality; break; case 1: asset.Quality = HorizonBasedAmbientOcclusion.QualityType.MiddleQuality; break; case 2: asset.Quality = HorizonBasedAmbientOcclusion.QualityType.HighQuality; break; } }; quality.Draw += delegate { if (quality.ListBoxVisible) return; switch (asset.Quality) { case HorizonBasedAmbientOcclusion.QualityType.LowQuality : quality.ItemIndex = 0; break; case HorizonBasedAmbientOcclusion.QualityType.MiddleQuality : quality.ItemIndex = 1; break; case HorizonBasedAmbientOcclusion.QualityType.HighQuality : quality.ItemIndex = 2; break; } }; #endregion var numberSteps = CommonControls.SliderNumericInt("Number Steps", groupGeneral, asset.NumberSteps, false, true, 0, 36, asset, "NumberSteps"); var numberDirections = CommonControls.SliderNumericInt("Number Directions", groupGeneral, asset.NumberDirections, false, true, 0, 36, asset, "NumberDirections"); var contrast = CommonControls.SliderNumericFloat("Contrast", groupGeneral, asset.Contrast, true, true, 0, 2, asset, "Contrast"); var lineAttenuation = CommonControls.SliderNumericFloat("LineAttenuation", groupGeneral, asset.LineAttenuation, false, false, 0, 2, asset, "LineAttenuation"); var radius = CommonControls.SliderNumericFloat("Radius", groupGeneral, asset.Radius, false, false, 0, 0.5f, asset, "Radius"); var angleBias = CommonControls.SliderNumericFloat("AngleBias", groupGeneral, asset.AngleBias, false, false, 0, 90, asset, "AngleBias"); groupGeneral.AdjustHeightFromChildren(); } // AddControls
} // GetParameters #endregion #region Render /// <summary> /// Generate ambient occlusion texture. /// </summary> internal RenderTarget Render(RenderTarget depthTexture, RenderTarget normalTexture, HorizonBasedAmbientOcclusion hbao, float fieldOfView, Size destinationSize, RenderTarget fullscreenDepthTexture) { try { // I decided to work with Color format for a number of reasons. // First, this format is very used so chances are that I can reuse it latter in another shader. // Second, GPUs tend to work faster in non-floating point render targets. // Third, I can blur it with linear sampling. // Last, I could need to return a color if I use directional occlusion. // The main disadvantage is that I am wasting three channels (or just one in SSDO). // A single 8 bit channel render target is not available in XNA 4.0 and I have two options for 16 bits render targets. // First, the compressed 4 channels formats, the compression is visible and the results are not satisfactory. // Last we have the half single format, it is a good option but I prefer to have linear sampling. // Alternatively, I can pack several shadows result in only one texture and blurred fourth results at the same time. // But I will do it only for shadows. I want to leave this shader simple. At least until a heavy optimization task needs to be performed. RenderTarget ambientOcclusionTexture = RenderTarget.Fetch(depthTexture.Size, SurfaceFormat.Color, DepthFormat.None, RenderTarget.AntialiasingType.NoAntialiasing); // Set shader atributes SetNormalTexture(normalTexture); SetDepthTexture(depthTexture); // It works a the depth texture resolution. Use a downsampled version of the G-Buffer. SetResolution(new Vector2(depthTexture.Width, depthTexture.Height)); SetInverseResolution(new Vector2(1 / (float)depthTexture.Width, 1 / (float)depthTexture.Height)); SetNumberSteps(hbao.NumberSteps); SetNumberDirections(hbao.NumberDirections); SetContrast(hbao.Contrast / (1.0f - (float)Math.Sin(hbao.AngleBias * (float)Math.PI / 180f))); SetLineAttenuation(hbao.LineAttenuation); SetRadius(hbao.Radius); SetSquareRadius(hbao.Radius * hbao.Radius); SetInverseRadius(1 / hbao.Radius); SetHalfPixel(new Vector2(-0.5f / (ambientOcclusionTexture.Width / 2), 0.5f / (ambientOcclusionTexture.Height / 2))); Vector2 focalLen = new Vector2 { X = 1.0f / (float)Math.Tan(fieldOfView * (Math.PI / 180) * 0.5f) * (float)ambientOcclusionTexture.Height / (float)ambientOcclusionTexture.Width, Y = 1.0f / (float)Math.Tan(fieldOfView * (Math.PI / 180) * 0.5f) }; SetFocalLength(focalLen); SetInverseFocalLength(new Vector2(1 / focalLen.X, 1 / focalLen.Y)); SetAngleBias(hbao.AngleBias * (float)Math.PI / 180f); SetTanAngleBias((float)Math.Tan(hbao.AngleBias * (float)Math.PI / 180f)); switch (hbao.Quality) { case HorizonBasedAmbientOcclusion.QualityType.LowQuality: Resource.CurrentTechnique = Resource.Techniques["LowQuality"]; break; case HorizonBasedAmbientOcclusion.QualityType.MiddleQuality: Resource.CurrentTechnique = Resource.Techniques["MiddleQuality"]; break; case HorizonBasedAmbientOcclusion.QualityType.HighQuality: Resource.CurrentTechnique = Resource.Techniques["HighQuality"]; break; } // Set Render States. EngineManager.Device.BlendState = BlendState.Opaque; EngineManager.Device.DepthStencilState = DepthStencilState.None; EngineManager.Device.RasterizerState = RasterizerState.CullCounterClockwise; EngineManager.Device.SamplerStates[3] = SamplerState.PointWrap; // Render ambientOcclusionTexture.EnableRenderTarget(); ambientOcclusionTexture.Clear(Color.White); Resource.CurrentTechnique.Passes[0].Apply(); RenderScreenPlane(); ambientOcclusionTexture.DisableRenderTarget(); // The blured texture has fullscreen size to improve the quality. // This pass is a lot cheaper than the ambient occlusion pass so the performance penalty is acceptable. RenderTarget bluredAmbientOcclusionTexture = RenderTarget.Fetch(destinationSize, ambientOcclusionTexture.SurfaceFormat, DepthFormat.None, RenderTarget.AntialiasingType.NoAntialiasing); BilateralBlurShader.Instance.Filter(ambientOcclusionTexture, bluredAmbientOcclusionTexture, depthTexture, 10, 10); RenderTarget.Release(ambientOcclusionTexture); return(bluredAmbientOcclusionTexture); } catch (Exception e) { throw new InvalidOperationException("Horizon Based Ambient Occlusion Shader: Unable to render.", e); } } // Render