Skip to content

Commit

Permalink
[2D] - Added a world position buffer to the GBuffer and updated light…
Browse files Browse the repository at this point in the history
…ing to use it in order to calculate lighting range.
  • Loading branch information
Tape-Worm committed Jan 26, 2022
1 parent c9f8385 commit ac0074e
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ namespace Gorgon.Renderers.Techniques
/// </summary>
public interface IGorgonGBuffer
{
/// <summary>
/// Property to return the position texture for the gbuffer.
/// </summary>
GorgonTexture2DView Position
{
get;
}

/// <summary>
/// Property to return the position render target for the gbuffer.
/// </summary>
GorgonRenderTarget2DView PositionTarget
{
get;
}

/// <summary>
/// Property to return the diffuse texture for the gbuffer.
/// </summary>
Expand Down
21 changes: 17 additions & 4 deletions Gorgon/Gorgon.Renderers/Gorgon2D/Effects/Gorgon2DGBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ public class Gorgon2DGBuffer
// The texture that holds the GBuffer data.
private GorgonTexture2D _gbuffer;
// The render targets for the gbuffer.
private readonly GorgonRenderTarget2DView[] _target = new GorgonRenderTarget2DView[3];
private readonly GorgonRenderTarget2DView[] _target = new GorgonRenderTarget2DView[4];
// Flag to indicate that array indices should be used to render.
private bool _useArray;
// Parameters for the gbuffer shader.
private GorgonConstantBufferView _params;
// The current normal/specular map textures when using separate textures.
// The current normal/specular/position map textures when using separate textures.
private GorgonTexture2DView _normalTexture;
private GorgonTexture2DView _specularTexture;
// The original render target view.
Expand Down Expand Up @@ -125,6 +125,16 @@ public GorgonTexture2DView Normal
/// Property to return the normal map render target for the gbuffer.
/// </summary>
public GorgonRenderTarget2DView NormalTarget => _target[1];

/// <summary>Property to return the position texture for the gbuffer.</summary>
public GorgonTexture2DView Position
{
get;
private set;
}

/// <summary>Property to return the position render target for the gbuffer.</summary>
public GorgonRenderTarget2DView PositionTarget => _target[3];
#endregion

#region Methods.
Expand All @@ -134,6 +144,7 @@ public GorgonTexture2DView Normal
private void UnloadGBuffer()
{
Diffuse?.Dispose();
Position?.Dispose();
Normal?.Dispose();
Specular?.Dispose();
GBufferTexture?.Dispose();
Expand All @@ -143,7 +154,7 @@ private void UnloadGBuffer()
_target[i]?.Dispose();
}

GBufferTexture = Specular = Normal = Diffuse = null;
GBufferTexture = Specular = Normal = Diffuse = Position = null;
Array.Clear(_target, 0, _target.Length);

_gbuffer?.Dispose();
Expand Down Expand Up @@ -308,6 +319,7 @@ public void ClearGBuffer()
_target[0].Clear(GorgonColor.BlackTransparent);
_target[1].Clear(new GorgonColor(normChanValue, normChanValue, 1.0f, 0.0f));
_target[2].Clear(GorgonColor.BlackTransparent);
_target[3].Clear(GorgonColor.Black);
}

/// <summary>
Expand All @@ -325,7 +337,7 @@ public void Resize(int width, int height)

UnloadGBuffer();

GorgonTexture2DInfo mainInfo = new(width, height, BufferFormat.R8G8B8A8_UNorm)
GorgonTexture2DInfo mainInfo = new(width, height, BufferFormat.R16G16B16A16_Float)
{
Name = "GBuffer",
ArrayCount = _target.Length,
Expand All @@ -344,6 +356,7 @@ public void Resize(int width, int height)
Diffuse = _gbuffer.GetShaderResourceView(arrayIndex: 0, arrayCount: 1);
Normal = _gbuffer.GetShaderResourceView(arrayIndex: 1, arrayCount: 1);
Specular = _gbuffer.GetShaderResourceView(arrayIndex: 2, arrayCount: 1);
Position = _gbuffer.GetShaderResourceView(arrayIndex: 3, arrayCount: 1);
}

/// <summary>
Expand Down
31 changes: 19 additions & 12 deletions Gorgon/Gorgon.Renderers/Gorgon2D/Effects/Gorgon2DLightingEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,17 @@ namespace Gorgon.Renderers
/// <description>The normal map layer for the sprite - This is the texture array index that provides normals for the lighting calculations. This layer must have data in it or else no lighting will
/// be applied. Gorgon does not generate normal map for your texture, however there are a multitude of tools available online to help with this (e.g. CrazyBump, SpriteIlluminator, etc...).</description>
/// </item>
/// <item>
/// <description>The position buffer for the sprite - This is the texture array index that world position data for the lighting calculations. This layer may be omitted by passing -1 to a position
/// index parameter. The <see cref="Gorgon2DGBuffer"/> will use always positional data and will generate world position data based on whatever you render.</description>
/// </item>
/// </list>
/// </para>
/// <para>
/// The user must also supply at least a single light source to effectively view the lighting on the 2D object.
/// </para>
/// </remarks>
/// <seealso cref="Gorgon2DGBuffer"/>
public class Gorgon2DLightingEffect
: Gorgon2DEffect
{
Expand Down Expand Up @@ -114,7 +119,7 @@ private struct GlobalEffectData
/// <summary>
/// The maximum number of lights that can be used at one time.
/// </summary>
public const int MaxLightCount = 256;
public const int MaxLightCount = 1024;
#endregion

#region Variables.
Expand Down Expand Up @@ -150,7 +155,7 @@ private struct GlobalEffectData
// The currently active render target view.
private GorgonRenderTargetView _currentRtv;
// The currently active array indices.
private (int normalIndex, int specIndex) _currentIndices;
private (int normalIndex, int specIndex, int posIndex) _currentIndices;
// Flag to indicate that normals on the normal map should rotate.
private bool _rotateNormals;
// Flag to indicate that a gbuffer is in use.
Expand Down Expand Up @@ -370,7 +375,7 @@ protected override void Dispose(bool disposing)
return;
}

_currentIndices = (-1, -1);
_currentIndices = (-1, -1, -1);

GorgonConstantBufferView lightData = Interlocked.Exchange(ref _lightBuffer, null);
GorgonConstantBufferView globalData = Interlocked.Exchange(ref _globalBuffer, null);
Expand Down Expand Up @@ -565,6 +570,7 @@ public void Begin(GorgonTexture2DView normal = null, GorgonTexture2DView specula
/// </summary>
/// <param name="normalMapIndex">The array index of the texture being rendered that contains the normal map.</param>
/// <param name="specularMapIndex">The array index of the texture being rendered that contains the specular map.</param>
/// <param name="positionIndex">[Optional] The array index of the texture begin rendered that contains the position buffer.</param>
/// <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>
Expand All @@ -574,7 +580,7 @@ public void Begin(GorgonTexture2DView normal = null, GorgonTexture2DView specula
/// This method takes the texture of whatever is currently being rendered and uses an array index to index into the texture and retrieve the normal and specular map values.
/// </para>
/// </remarks>
public void Begin(int normalMapIndex, int specularMapIndex, GorgonBlendState blendState = null, GorgonDepthStencilState depthStencilState = null, GorgonRasterState rasterState = null, GorgonCameraCommon camera = null)
public void Begin(int normalMapIndex, int specularMapIndex, int positionIndex = -1, GorgonBlendState blendState = null, GorgonDepthStencilState depthStencilState = null, GorgonRasterState rasterState = null, GorgonCameraCommon camera = null)
{
UseGBuffer = false;
UseArray = true;
Expand All @@ -583,8 +589,8 @@ public void Begin(int normalMapIndex, int specularMapIndex, GorgonBlendState ble

if ((_currentIndices.normalIndex != normalMapIndex) || (_currentIndices.specIndex != specularMapIndex))
{
_effectData.ArrayIndices = new Vector4(normalMapIndex, specularMapIndex, 0, 0);
_currentIndices = (normalMapIndex, specularMapIndex);
_effectData.ArrayIndices = new Vector4(normalMapIndex, specularMapIndex, positionIndex, 0);
_currentIndices = (normalMapIndex, specularMapIndex, positionIndex);
}

OnBeginRender(blendState, depthStencilState, rasterState, camera);
Expand Down Expand Up @@ -615,10 +621,10 @@ public void Render(IGorgonGBuffer gbuffer, GorgonRenderTargetView output, Gorgon

_currentRtv = output;

if ((_currentIndices.normalIndex != 1) || (_currentIndices.specIndex != 2))
if ((_currentIndices.normalIndex != 1) || (_currentIndices.specIndex != 2) || (_currentIndices.posIndex != 3))
{
_effectData.ArrayIndices = new Vector4(1, 2, 0, 0);
_currentIndices = (1, 2);
_effectData.ArrayIndices = new Vector4(1, 2, 3, 0);
_currentIndices = (1, 2, 3);
}

OnRender(gbuffer.GBufferTexture, output, camera);
Expand All @@ -632,9 +638,10 @@ public void Render(IGorgonGBuffer gbuffer, GorgonRenderTargetView output, Gorgon
/// <param name="output">The final output target for the effect.</param>
/// <param name="normalMapIndex">The array index of the diffuse texture that contains the normal map.</param>
/// <param name="specularMapIndex">The array index of the diffuse texture that contains the specular map.</param>
/// <param name="positionIndex">[Optional] The array index of the texture begin rendered that contains the position buffer.</param>
/// <param name="camera">[Optional] The camera used to transform the lights to camera space.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="diffuse"/>, or the <paramref name="output"/> parameter is <b>null</b>.</exception>
public void Render(GorgonTexture2DView diffuse, GorgonRenderTargetView output, int normalMapIndex, int specularMapIndex, GorgonCameraCommon camera = null)
public void Render(GorgonTexture2DView diffuse, GorgonRenderTargetView output, int normalMapIndex, int specularMapIndex, int positionIndex = -1, GorgonCameraCommon camera = null)
{
UseArray = true;
UseGBuffer = false;
Expand All @@ -647,8 +654,8 @@ public void Render(GorgonTexture2DView diffuse, GorgonRenderTargetView output, i
if ((normalMapIndex != _currentIndices.normalIndex) || (specularMapIndex != _currentIndices.specIndex))
{
_effectData.ArrayIndices = new Vector4(normalMapIndex.Max(0).Min(diffuse.ArrayCount - 1),
specularMapIndex.Max(0).Min(diffuse.ArrayCount - 1), 0, 0);
_currentIndices = (normalMapIndex.Max(0).Min(diffuse.ArrayCount - 1), specularMapIndex.Max(0).Min(diffuse.ArrayCount - 1));
specularMapIndex.Max(0).Min(diffuse.ArrayCount - 1), positionIndex, 0);
_currentIndices = (normalMapIndex.Max(0).Min(diffuse.ArrayCount - 1), specularMapIndex.Max(0).Min(diffuse.ArrayCount - 1), positionIndex);
}

OnRender(diffuse, output, camera);
Expand Down
7 changes: 7 additions & 0 deletions Gorgon/Gorgon.Renderers/Gorgon2D/Resources/GBuffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ cbuffer EffectParams : register(b1)
struct GorgonLitVertex
{
float4 position : SV_POSITION;
float4 worldPos : WORLDPOS;
float4 color : COLOR;
float4 uv : TEXCOORD;
float3 tangent : TANGENT;
Expand All @@ -26,19 +27,24 @@ struct GorgonGBufferOutput
float4 Normal : SV_Target1;
// The specular map texel.
float4 Specular : SV_Target2;
// The position buffer.
float4 Position : SV_Target3;
};

// Normal and specular map.
Texture2D _normalTexture : register(t1);
SamplerState _normalSampler : register(s1);
Texture2D _specularTexture : register(t2);
SamplerState _specularSampler : register(s2);
Texture2D _positionTexture : register(t3);
SamplerState _positionSampler : register(s3);

// Updated vertex shader that will perform tangent and bitangent transforms.
GorgonLitVertex GorgonVertexShaderGBuffer(GorgonSpriteVertex vertex)
{
GorgonLitVertex output;

output.worldPos = vertex.position;
output.position = mul(ViewProjection, vertex.position);
output.uv = vertex.uv;
output.color = vertex.color;
Expand All @@ -60,6 +66,7 @@ GorgonGBufferOutput GorgonPixelShaderGBuffer(GorgonLitVertex vertex) : SV_Target

float3 texCoords = float3(vertex.uv.xy / vertex.uv.w, vertex.uv.z);

result.Position = float4(vertex.worldPos.rgb, 1.0f);
result.Diffuse = _gorgonTexture.Sample(_gorgonSampler, texCoords) * vertex.color;

REJECT_ALPHA(result.Diffuse.a);
Expand Down
7 changes: 6 additions & 1 deletion Gorgon/Gorgon.Renderers/Gorgon2D/Resources/Lighting.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ float3 PointLight(float3 color, float3 normal, GorgonSpriteLitVertex vertex, flo
int specularEnabled = int(light.Attributes.w);
float specularIntensity = light.Attributes.z;
float3 result;
float3 lightRange = light.Position.xyz - vertex.worldPos;
#ifdef USE_ARRAY
float3 worldPos = _arrayIndices.z < 0 ? vertex.worldPos : _gorgonTexture.Sample(_normalSampler, float3(uv, _arrayIndices.z)).rgb;
#else
float3 worldPos = vertex.worldPos;
#endif
float3 lightRange = light.Position.xyz - worldPos;
float distance = length(lightRange);

if ((distance >= light.Attenuation.w) || ((light.Attenuation.x == 0) && (light.Attenuation.y == 0) && (light.Attenuation.z == 0)))
Expand Down

0 comments on commit ac0074e

Please sign in to comment.