Skip to content

Commit

Permalink
[2D] - Restored displacement effect to be a batched/post hybrid and r…
Browse files Browse the repository at this point in the history
…emoved the compositor compatibility. It did not play nice with the compositor due to the nature of the effect.
  • Loading branch information
Tape-Worm committed Aug 17, 2021
1 parent e9d45e8 commit 02a1d7e
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 76 deletions.
41 changes: 26 additions & 15 deletions Examples/Gorgon.Renderers.2D/Effects/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ static class Program
/// <returns><b>true</b> to continue processing, <b>false</b> to stop.</returns>
private static bool Idle()
{
_postTarget1.Clear(GorgonColor.Black);
_postTarget1.Clear(GorgonColor.BlackTransparent);
_postTarget2.Clear(GorgonColor.BlackTransparent);

Vector2 textureSize = _background.Texture.ToTexel(new Vector2(_postTarget1.Width, _postTarget1.Height));
Expand All @@ -125,25 +125,36 @@ private static bool Idle()
{
_shipSprite.Color = GorgonColor.White;

_graphics.SetRenderTarget(_postTarget2);
_renderer.Begin();
_displacement.BeginDisplacementBatch();
_renderer.DrawSprite(_shipSprite);
_renderer.End();
_displacement.EndDisplacementBatch();

_displacement.Strength = strength;
_displacement.ChromaticAberrationScale = new Vector2(_shipSprite.Angle.ToRadians().Cos() * 0.5f + 1.0f, _shipSprite.Angle.ToRadians().Sin() * 0.5f + 1.0f);
_displacement.Render(_postView2, _postTarget1);
}
_displacement.Render(_postView1, _postTarget2);

// Send the undisplaced image to the 2nd post process target.
_graphics.SetRenderTarget(_postTarget2);
// Send the undisplaced image to the 2nd post process target.
_graphics.SetRenderTarget(_postTarget1);

_renderer.Begin();
_renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, _postTarget1.Width, _postTarget1.Height),
GorgonColor.White,
_postView1,
new DX.RectangleF(0, 0, 1, 1));
_renderer.End();
_renderer.Begin();
_renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, _postTarget1.Width, _postTarget1.Height),
GorgonColor.White,
_postView2,
new DX.RectangleF(0, 0, 1, 1));
_renderer.End();
}
else
{
// Send the undisplaced image to the 2nd post process target.
_graphics.SetRenderTarget(_postTarget2);

_renderer.Begin();
_renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, _postTarget1.Width, _postTarget1.Height),
GorgonColor.White,
_postView1,
new DX.RectangleF(0, 0, 1, 1));
_renderer.End();
}

// Smooth our results.
int blurRadiusUpdate = GorgonRandom.RandomInt32(0, 1000000);
Expand All @@ -159,7 +170,7 @@ private static bool Idle()
// If we didn't blur (radius = 0), then just use the original view.
if (_gaussBlur.BlurRadius > 0)
{
_gaussBlur.Render(_postView2, _postTarget2);
_gaussBlur.Render(_postView1, _postTarget2);
}

// Render as an old film effect.
Expand Down
140 changes: 84 additions & 56 deletions Gorgon/Gorgon.Renderers/Gorgon2D/Effects/Gorgon2DDisplacementEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
//
#endregion

using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand All @@ -42,7 +41,7 @@ namespace Gorgon.Renderers
/// An effect that displaces the pixels on an image using the pixels from another image for weighting.
/// </summary>
public class Gorgon2DDisplacementEffect
: Gorgon2DEffect, IGorgon2DCompositorEffect
: Gorgon2DEffect
{
#region Value Type.
/// <summary>
Expand Down Expand Up @@ -87,10 +86,8 @@ private struct GpuData
private GorgonTexture2DInfo _targetInfo;
// The displacement render targets.
private GorgonRenderTarget2DView _displacementTarget;
private GorgonRenderTarget2DView _workerTarget;
// The displacement texture view.
private GorgonTexture2DView _displacementView;
private GorgonTexture2DView _workerView;
// The constant buffer for displacement settings.
private GorgonConstantBufferView _displacementSettingsBuffer;
// Flag to indicate that the parameters have been updated.
Expand All @@ -103,6 +100,10 @@ private struct GpuData
private bool _chromatic = true;
// The scale of the chromatic aberration color channel separation.
private Vector2 _chromaAbScale = new(0.5f, 0);
// The currently active render target view.
private GorgonRenderTargetView _currentRtv;
// The current pass.
private int _currentPass = -1;
#endregion

#region Properties.
Expand Down Expand Up @@ -233,9 +234,6 @@ private void UpdateDisplacementMap(GorgonRenderTargetView output, bool isSizeCha
_displacementTarget = Graphics.TemporaryTargets.Rent(_targetInfo, "Effect.Displacement.RT");
_displacementView = _displacementTarget.GetShaderResourceView();

_workerTarget = Graphics.TemporaryTargets.Rent(_displacementTarget, "Effect.Displacement.Worker");
_workerView = _workerTarget.GetShaderResourceView();

_isUpdated = true;
}

Expand Down Expand Up @@ -268,15 +266,8 @@ public void FreeResources()
Graphics.TemporaryTargets.Return(_displacementTarget);
}

if (_workerTarget is not null)
{
Graphics.TemporaryTargets.Return(_workerTarget);
}

_displacementState = null;
_batchState = null;
_workerTarget = _displacementTarget = null;
_workerView = _displacementView = null;
}

/// <summary>
Expand All @@ -292,6 +283,11 @@ public void FreeResources()
/// </remarks>
protected override void OnBeforeRender(GorgonRenderTargetView output, bool sizeChanged)
{
if (output is null)
{
return;
}

UpdateDisplacementMap(output, sizeChanged);

if (!_isUpdated)
Expand All @@ -311,6 +307,20 @@ protected override void OnBeforeRender(GorgonRenderTargetView output, bool sizeC
_isUpdated = false;
}

/// <summary>Function called after rendering is complete.</summary>
/// <param name="output">The final render target that will receive the rendering from the effect.</param>
/// <remarks>
/// This method is called after all passes are finished and the effect is ready to complete its rendering. Developers should override this method to finalize any custom rendering. For example
/// an effect author can use this method to render the final output of an effect to the final render target.
/// </remarks>
protected override void OnAfterRender(GorgonRenderTargetView output)
{
_currentPass = -1;
_currentRtv = null;

FreeResources();
}

/// <summary>
/// Function called prior to rendering a pass.
/// </summary>
Expand All @@ -328,31 +338,15 @@ protected override PassContinuationState OnBeforeRenderPass(int passIndex, Gorgo
{
if (passIndex == 0)
{
_workerTarget.Clear(GorgonColor.BlackTransparent);
_displacementTarget.Clear(GorgonColor.BlackTransparent);
output.Clear(GorgonColor.BlackTransparent);
}

Graphics.SetRenderTarget(output, Graphics.DepthStencilView);

_currentPass = passIndex;
return PassContinuationState.Continue;
}


/// <summary>Function called after rendering is complete.</summary>
/// <param name="output">The final render target that will receive the rendering from the effect.</param>
/// <remarks>
/// This method is called after all passes are finished and the effect is ready to complete its rendering. Developers should override this method to finalize any custom rendering. For example
/// an effect author can use this method to render the final output of an effect to the final render target.
/// </remarks>
protected override void OnAfterRender(GorgonRenderTargetView output)
{
Renderer.Begin(Gorgon2DBatchState.PremultipliedBlend);
Renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, output.Width, output.Height), GorgonColor.White, _workerView);
Renderer.End();

FreeResources();
}

/// <summary>
/// Function called to build a new (or return an existing) 2D batch state.
/// </summary>
Expand All @@ -375,8 +369,7 @@ protected override Gorgon2DBatchState OnGetBatchState(int passIndex, IGorgon2DEf
}

_batchState = builders.BatchBuilder.Clear()
.PixelShaderState(_displacementState)
.BlendState(GorgonBlendState.Premultiplied)
.PixelShaderState(_displacementState)
.Build(BatchStateAllocator);
}

Expand All @@ -401,43 +394,78 @@ protected override void Dispose(bool disposing)

displacementBuffer?.Dispose();
shader?.Dispose();
}

/// <summary>
/// Function to begin a batch for rendering the objects used to displace the target.
/// </summary>
/// <param name="blendState">[Optional] A user defined blend state to apply when rendering.</param>
/// <param name="depthStencilState">[Optional] A user defined depth/stencil state to apply when rendering.</param>
/// <param name="rasterState">[Optional] A user defined rasterizer state to apply when rendering.</param>
/// <param name="camera">[Optional] The camera to use when rendering.</param>
/// <returns><b>true</b> if the pass can continue, <b>false</b> if not.</returns>
/// <remarks>
/// <para>
/// This is the first pass in the effect. It will receive rendering using objects like sprites, primitives, etc... that will be used to displace the pixels on an image in the next pass.
/// </para>
/// <para>
/// When this method is called, the <see cref="EndDisplacementBatch"/> method <b>must</b> be called prior to moving to the next pass. If this is not done, an exception will be thrown. If this method
/// returns <b>false</b>, the <see cref="EndDisplacementBatch"/> still must be called.
/// </para>
/// </remarks>
public bool BeginDisplacementBatch(GorgonBlendState blendState = null, GorgonDepthStencilState depthStencilState = null, GorgonRasterState rasterState = null, GorgonCameraCommon camera = null)
{
// Get the current render target, this will receive output.
_currentPass = -1;
_currentRtv = Graphics.RenderTargets[0];

BeginRender(_currentRtv, blendState, depthStencilState, rasterState);

if (BeginPass(0, _displacementTarget, camera) != PassContinuationState.Continue)
{
EndRender(_currentRtv);
return false;
}

return true;
}

/// <summary>
/// Function to render the specified texture as a displacement for the target texture data.
/// Function to end the batch.
/// </summary>
/// <remarks>
/// <para>
/// This method must be called when <see cref="BeginDisplacementBatch"/> is called. The will mark the beginning of the next pass, <see cref="Render"/>, which will render the actual displacement.
/// </para>
/// </remarks>
public void EndDisplacementBatch() => EndPass(0, _displacementTarget);

/// <summary>
/// Function to render the displacement effect.
/// </summary>
/// <param name="texture">The texture to use as a displacement for the specified render target.</param>
/// <param name="target">The target whos image will be displaced by the texture.</param>
/// <exception cref="ArgumentException">Thrown when the <paramref name="target"/> cannot be bound as a shader resource.</exception>
/// <param name="backgroundTexture">The texture to displace.</param>
/// <param name="target">The render target that will receive the effect rendering.</param>
/// <exception cref="GorgonException">Thrown if the current pass is not the second pass.</exception>
/// <remarks>
/// <para>
/// The <paramref name="target"/> must be created with a binding of <see cref="TextureBinding.ShaderResource"/>, otherwise this method will throw an exception.
/// This method must be called after <see cref="EndDisplacementBatch"/>
/// </para>
/// </remarks>
public void Render(GorgonTexture2DView texture, GorgonRenderTarget2DView target)
public void Render(GorgonTexture2DView backgroundTexture, GorgonRenderTargetView target)
{
if ((target.Binding & TextureBinding.ShaderResource) != TextureBinding.ShaderResource)
if (_currentPass != 0)
{
throw new ArgumentException(Resources.GOR2D_ERR_INVALID_TARGET, nameof(target));
throw new GorgonException(GorgonResult.CannotWrite, string.Format(Resources.GOR2D_ERR_INCORRECT_DISPLACEMENT_PASS, _currentPass, 1));
}


BeginPass(1, target);
Renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, target.Width, target.Height), GorgonColor.White, backgroundTexture, new DX.RectangleF(0, 0, 1, 1));
EndPass(1, target);

BeginRender(target, GorgonBlendState.Premultiplied);
BeginPass(0, _displacementTarget);
Renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, target.Width, target.Height), GorgonColor.White, texture, new DX.RectangleF(0, 0, 1, 1));
EndPass(0, _displacementTarget);
EndRender(_currentRtv);

BeginPass(1, _workerTarget);
Renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, target.Width, target.Height), GorgonColor.White, target.GetShaderResourceView(), new DX.RectangleF(0, 0, 1, 1), textureSampler: DisplacementSampler);
EndPass(1, _workerTarget);
EndRender(target);
_currentPass = -1;
}

/// <summary>Function to render an effect under the <see cref="Gorgon2DCompositor" />.</summary>
/// <param name="texture">The texture to render into the next target.</param>
/// <param name="output">The render target that will receive the final output.</param>
void IGorgon2DCompositorEffect.Render(GorgonTexture2DView texture, GorgonRenderTargetView output) => Render(texture, (GorgonRenderTarget2DView)output);
#endregion

#region Constructor/Destructor.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,9 @@ public DX.Size2 BlurRenderTargetsSize
_needOffsetUpdate = true;
}
}
#endregion
#endregion

#region Methods.
#region Methods.
/// <summary>
/// Function to update the render target.
/// </summary>
Expand Down Expand Up @@ -628,9 +628,9 @@ public void Render(GorgonTexture2DView texture, GorgonRenderTargetView output)

EndRender(output);
}
#endregion
#endregion

#region Constructor/Finalizer.
#region Constructor/Finalizer.
/// <summary>
/// Initializes a new instance of the <see cref="Gorgon2DGaussBlurEffect"/> class.
/// </summary>
Expand Down Expand Up @@ -674,6 +674,6 @@ public Gorgon2DGaussBlurEffect(Gorgon2D renderer, int kernelSize = 7)
Macros.Add(new GorgonShaderMacro("GAUSS_BLUR_EFFECT"));
Macros.Add(new GorgonShaderMacro("MAX_KERNEL_SIZE", KernelSize.ToString(CultureInfo.InvariantCulture)));
}
#endregion
#endregion
}
}
18 changes: 18 additions & 0 deletions Gorgon/Gorgon.Renderers/Gorgon2D/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Gorgon/Gorgon.Renderers/Gorgon2D/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@
<data name="GOR2D_ERR_CBUFFER_SLOT_INVALID" xml:space="preserve">
<value>The constant buffer slot must be 0 or less than {0}.</value>
</data>
<data name="GOR2D_ERR_DISPLACEMENT_PASS_ALREADY_CALLED" xml:space="preserve">
<value>The pass is already started. Please call the associated End method.</value>
</data>
<data name="GOR2D_ERR_EFFECT_BEGIN_RENDER_CALLED" xml:space="preserve">
<value>The BeginRender method has already been called on the '{0}' effect.</value>
</data>
Expand All @@ -256,6 +259,9 @@
<data name="GOR2D_ERR_EFFECT_PASS_RENDER_CALLED" xml:space="preserve">
<value>The BeginPass method has already been called for pass #{0} on effect '{1}'.</value>
</data>
<data name="GOR2D_ERR_INCORRECT_DISPLACEMENT_PASS" xml:space="preserve">
<value>The current pass is #{0}, but the call is for pass #{1}.</value>
</data>
<data name="GOR2D_ERR_INVALID_SAMPLER_INDEX" xml:space="preserve">
<value>The sampler index must be 0 or less than {1}.</value>
</data>
Expand Down

0 comments on commit 02a1d7e

Please sign in to comment.