Cleaned up new Depth of Field, ready for PR
Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com>
This commit is contained in:
@@ -23,9 +23,5 @@ struct NewDepthOfFieldConstants
|
||||
float4 samplePositions[60]; // XY are sample positions (normalized so max lenght is 1)
|
||||
// Z is the length of XY (0 - 1)
|
||||
// W is unused
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
+56
-20
@@ -51,33 +51,69 @@ PSOutput MainPS(VSOutput IN)
|
||||
float focusDistance = ViewSrg::m_dof.m_cameraParameters.z;
|
||||
float coc = ConvertDofFactor(InvertDepth(depth), far, near, focusDistance);
|
||||
|
||||
// Calculate Alpha
|
||||
float cocRadius = abs(coc) * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f;
|
||||
float maxPixelDist = max(PassSrg::m_halfResDimensions.z, PassSrg::m_halfResDimensions.w);
|
||||
float alpha = saturate(cocRadius / maxPixelDist);
|
||||
// --- Weights based on CoC similarity ---
|
||||
|
||||
// Gather CoCs
|
||||
float4 cocGather = PassSrg::m_halfResColorAndCoc.GatherAlpha(PassSrg::LinearSampler, halfResUV);
|
||||
|
||||
// Calculate differences
|
||||
float4 diff = saturate(cocGather - coc);
|
||||
|
||||
// Sample half res color and CoC
|
||||
float4 colorAndCoC = PassSrg::m_halfResColorAndCoc.Sample(PassSrg::LinearSampler, halfResUV);
|
||||
// Slide differences such that small difference (i.e. most similar CoC) will become 0
|
||||
// (which then gets inverted in the next step)
|
||||
float minDiff = min4(diff);
|
||||
diff -= minDiff;
|
||||
|
||||
// Invert the differences with a slope multiplier of 2
|
||||
float4 cocDiffWeights = saturate(1 - (2 * diff));
|
||||
|
||||
// --- Weights based on pixel proximity ---
|
||||
|
||||
// Based on which pixel we're shading, we'll be closer/further to half res pixels
|
||||
// Here are the pre-caculated weights, arranged to match the Gather pattern
|
||||
//
|
||||
// W Z
|
||||
// X Y
|
||||
//
|
||||
// Note: These weights come down to the same contributions as if we did a linear sample
|
||||
int2 pixel = int2(fullResPixelPos);
|
||||
float4 weights = (pixel.x & 1)
|
||||
? ( (pixel.y & 1) ? float4(0.1875f, 0.0625f, 0.1875f, 0.5625f)
|
||||
: float4(0.5625f, 0.1875f, 0.0625f, 0.1875f) )
|
||||
: ( (pixel.y & 1) ? float4(0.0625f, 0.1875f, 0.5625f, 0.1875f)
|
||||
: float4(0.1875f, 0.5625f, 0.1875f, 0.0625f) );
|
||||
|
||||
// Combine and normalize weights
|
||||
weights *= cocDiffWeights;
|
||||
weights /= (weights.x + weights.y + weights.z + weights.w);
|
||||
|
||||
// --- Color ---
|
||||
|
||||
// For each color channel, do a gather and multiply the samples by the weights calculated above
|
||||
float3 color;
|
||||
float4 red = PassSrg::m_halfResColorAndCoc.GatherRed(PassSrg::LinearSampler, halfResUV);
|
||||
color.r = dot(red, weights);
|
||||
float4 blue = PassSrg::m_halfResColorAndCoc.GatherBlue(PassSrg::LinearSampler, halfResUV);
|
||||
color.b = dot(blue, weights);
|
||||
float4 green = PassSrg::m_halfResColorAndCoc.GatherGreen(PassSrg::LinearSampler, halfResUV);
|
||||
color.g = dot(green, weights);
|
||||
|
||||
|
||||
if(false)
|
||||
{
|
||||
// Make out of focus foreground increasingly blue
|
||||
float multiplier = saturate(1.0f + coc);
|
||||
colorAndCoC.r *= multiplier;
|
||||
colorAndCoC.g *= multiplier;
|
||||
// --- Alpha ---
|
||||
|
||||
// Make out of focus background increasingly red
|
||||
multiplier = saturate(1.0f - coc);
|
||||
colorAndCoC.b *= multiplier;
|
||||
colorAndCoC.g *= multiplier;
|
||||
}
|
||||
// Calculate alpha such that we fully take the half res texture value if the CoC of the full
|
||||
// resolution pixel is greater than the size of a half resolution pixel
|
||||
float cocRadius = abs(coc) * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f;
|
||||
float alpha = saturate(cocRadius / PassSrg::m_halfResDimensions.w);
|
||||
|
||||
// We may have objects in focus (CoC = 0) but that receive contribution from background bokeh
|
||||
// (which have a negative CoC that we calculated in the large filter). Take the max here.
|
||||
float minCoc = min4(cocGather);
|
||||
alpha = max(alpha, -minCoc);
|
||||
|
||||
// Output
|
||||
PSOutput OUT;
|
||||
OUT.m_color.rgb = colorAndCoC.rgb;
|
||||
OUT.m_color.rgb = color.rgb;
|
||||
OUT.m_color.a = alpha;
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
|
||||
+32
-12
@@ -18,6 +18,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass
|
||||
Texture2D<float4> m_colorAndCoc;
|
||||
Texture2D<float2> m_minMaxCocTile;
|
||||
|
||||
// Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height
|
||||
float4 m_textureDimensions;
|
||||
|
||||
NewDepthOfFieldConstants m_dofConstants;
|
||||
@@ -43,10 +44,10 @@ ShaderResourceGroup PassSrg : SRG_PerPass
|
||||
};
|
||||
}
|
||||
|
||||
float3 GetOffsetUV(uint index, float2 offsetMultiplier)
|
||||
float3 GetOffset(uint index, float2 offsetUVMultiplier)
|
||||
{
|
||||
float3 offset = PassSrg::m_dofConstants.samplePositions[index].xyz;
|
||||
offset.xy *= offsetMultiplier;
|
||||
offset.xy *= offsetUVMultiplier;
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -55,14 +56,19 @@ float CaclulateWeight(float offsetRadius, float samplingRadius, float sampleCoc,
|
||||
// The maximum distance for which samples are valid is the min of the sample CoC and the center CoC
|
||||
float maxRadius = abs(min(sampleCoc, centerCoc));
|
||||
|
||||
// Easy human readable calculations:
|
||||
// radius = samplingRadius * offsetRadius;
|
||||
// falloff = maxRadius - radius;
|
||||
// weight = 1 + (4 * falloff)
|
||||
// weight = 1 + (4 * falloff)
|
||||
//
|
||||
// The same thing in mad form:
|
||||
float falloff = mad(-samplingRadius, offsetRadius, maxRadius);
|
||||
float weight = saturate(mad(4, falloff, 1));
|
||||
return weight;
|
||||
return saturate(mad(4, falloff, 1));
|
||||
}
|
||||
|
||||
// This shader blurs by sampling 48 pixels in a circle around the center pixel
|
||||
// See http://advances.realtimerendering.com/s2013/Sousa_Graphics_Gems_CryENGINE3.pptx
|
||||
// for a detailed explanation.
|
||||
PSOutput MainPS(VSOutput IN)
|
||||
{
|
||||
// Get center sample
|
||||
@@ -70,10 +76,12 @@ PSOutput MainPS(VSOutput IN)
|
||||
float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV).rgba;
|
||||
float centerCoc = color.a;
|
||||
|
||||
// Get tile min and max
|
||||
// Get tile min CoC
|
||||
int2 tile = int2(IN.m_position.xy) / 16;
|
||||
float minCoc = PassSrg::m_minMaxCocTile[tile].x;
|
||||
|
||||
// Aspect ratio is needed because sample offsets are calculated in a perfect circle, but
|
||||
// UV space is stretched due to normalized device coordinates. Correct this with aspect ratio
|
||||
// Aspect ratio = texture.x / texture.y = dimensions.x * dimensions.w
|
||||
float aspectRatio = PassSrg::m_textureDimensions.x * PassSrg::m_textureDimensions.w;
|
||||
|
||||
@@ -82,15 +90,20 @@ PSOutput MainPS(VSOutput IN)
|
||||
float screenRadius = cocRadius * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f;
|
||||
float2 offsetMultiplier = float2(screenRadius / aspectRatio, screenRadius);
|
||||
|
||||
|
||||
// Background samples are samples behind the current pixel. Because of how depth of field works,
|
||||
// these pixels can contribute to the center pixel even if they are out of range of the center pixel's CoC
|
||||
// We accumulate them seperately and calculate a new estimated alpha value based on the ratio of samples
|
||||
// that were background pixels.
|
||||
float4 backgroundColor = float4(0, 0, 0, 0);
|
||||
|
||||
// If there are only positive CoCs in our region, we don't need to consider background blur
|
||||
// Do the faster and nicer approach
|
||||
if(minCoc >= 0)
|
||||
{
|
||||
for(uint i = 0; i < SAMPLES_LOOP_TOTAL; ++i)
|
||||
{
|
||||
// Calculate sample offset
|
||||
float3 offset = GetOffsetUV(i, offsetMultiplier);
|
||||
float3 offset = GetOffset(i, offsetMultiplier);
|
||||
|
||||
// Get sample
|
||||
float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::LinearSampler, pixelUV + offset.xy).rgba;
|
||||
@@ -102,18 +115,22 @@ PSOutput MainPS(VSOutput IN)
|
||||
color += weight * sampleColorCoc;
|
||||
}
|
||||
}
|
||||
else
|
||||
else // Some CoCs in the region are negative, need to consider possible background bokeh contribution
|
||||
{
|
||||
// Distance behind which samples are considered background samples
|
||||
float backgroundMin = min(0, centerCoc);
|
||||
|
||||
// Linear sampling colors pre-multiplied with CoC yields artefacts when combined with this background technique
|
||||
// We therefore do point sampling and unpack the original color value per sample
|
||||
color.rgb /= abs(color.a);
|
||||
color.a = 1;
|
||||
|
||||
for(uint i = 0; i < SAMPLES_LOOP_TOTAL; ++i)
|
||||
{
|
||||
// Calculate sample offset
|
||||
float3 offset = GetOffsetUV(i, offsetMultiplier);
|
||||
float3 offset = GetOffset(i, offsetMultiplier);
|
||||
|
||||
// Get sample
|
||||
// Get sample + unpack
|
||||
float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba;
|
||||
sampleColorCoc.rgb /= abs(sampleColorCoc.a);
|
||||
|
||||
@@ -131,16 +148,19 @@ PSOutput MainPS(VSOutput IN)
|
||||
color += !isBackground * sampleColorCoc;
|
||||
}
|
||||
|
||||
// Average background samples
|
||||
backgroundColor.rgb /= max(backgroundColor.a, COC_EPSILON);
|
||||
}
|
||||
|
||||
// Calculate background ratio. If greater than the current CoC, replace the current CoC with
|
||||
// background ratio. This is so background bokeh effects will still render on in-focus objects
|
||||
float backgroundRatio = saturate( backgroundColor.a / float(SAMPLES_LOOP_TOTAL) );
|
||||
float alpha = backgroundRatio > abs(centerCoc) ? -backgroundRatio : centerCoc;
|
||||
|
||||
// Average accumulated color samples and combine with background samples
|
||||
color.rgb /= max(color.a, COC_EPSILON);
|
||||
color = lerp(color, backgroundColor, backgroundRatio);
|
||||
|
||||
|
||||
PSOutput OUT = (PSOutput)0;
|
||||
OUT.m_color.rgb = color.rgb;
|
||||
OUT.m_color.a = alpha;
|
||||
|
||||
+44
-21
@@ -18,6 +18,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass
|
||||
Texture2D<float4> m_colorAndCoc;
|
||||
Texture2D<float2> m_minMaxCocTile;
|
||||
|
||||
// Texture dimensions. XY channels are width and height and ZW channels are 1 / width and 1 / height
|
||||
float4 m_textureDimensions;
|
||||
|
||||
NewDepthOfFieldConstants m_dofConstants;
|
||||
@@ -43,55 +44,77 @@ ShaderResourceGroup PassSrg : SRG_PerPass
|
||||
};
|
||||
}
|
||||
|
||||
float2 GetOffsetUV(uint index, float2 offsetMultiplier)
|
||||
float3 GetOffset(uint index, float2 offsetUVMultiplier)
|
||||
{
|
||||
return PassSrg::m_dofConstants.samplePositions[index].xy * offsetMultiplier;
|
||||
float3 offset = PassSrg::m_dofConstants.samplePositions[index].xyz;
|
||||
offset.xy *= offsetUVMultiplier;
|
||||
return offset;
|
||||
}
|
||||
|
||||
float CaclulateWeight(float offsetRadius, float samplingRadius, float sampleCoc, float centerCoc)
|
||||
{
|
||||
// The maximum distance for which samples are valid is the min of the sample CoC and the center CoC
|
||||
float maxRadius = abs(min(sampleCoc, centerCoc));
|
||||
|
||||
// Easy human readable calculations:
|
||||
// radius = samplingRadius * offsetRadius;
|
||||
// falloff = maxRadius - radius;
|
||||
// weight = 1 + (4 * falloff)
|
||||
//
|
||||
// The same thing in mad form:
|
||||
float falloff = mad(-samplingRadius, offsetRadius, maxRadius);
|
||||
return saturate(mad(4, falloff, 1));
|
||||
}
|
||||
|
||||
// This shader attempts to fill the gaps left by the large filter by sampling 8 pixels around the center pixel
|
||||
// See http://advances.realtimerendering.com/s2013/Sousa_Graphics_Gems_CryENGINE3.pptx
|
||||
// for a detailed overview of the technique
|
||||
PSOutput MainPS(VSOutput IN)
|
||||
{
|
||||
// UV of pixel being shaded
|
||||
// Get center sample
|
||||
float2 pixelUV = IN.m_texCoord.xy;
|
||||
float4 color = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV).rgba;
|
||||
float centerCoc = color.a;
|
||||
|
||||
// Sample pixel being shaded
|
||||
float4 centerSample = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV).rgba;
|
||||
float centerCoc = centerSample.a;
|
||||
// Get tile min CoC
|
||||
int2 tile = int2(IN.m_position.xy) / 16;
|
||||
float minCoc = PassSrg::m_minMaxCocTile[tile].x;
|
||||
|
||||
// Aspect ratio is needed because sample offsets are calculated in a perfect circle, but
|
||||
// UV space is stretched due to normalized device coordinates. Correct this with aspect ratio
|
||||
// Aspect ratio = texture.x / texture.y = dimensions.x * dimensions.w
|
||||
float aspectRatio = PassSrg::m_textureDimensions.x * PassSrg::m_textureDimensions.w;
|
||||
|
||||
// Sampling radius
|
||||
float cocRadius = abs(centerCoc) * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f;
|
||||
cocRadius *= 0.5f; // This is the small filter, half the sampling radius
|
||||
float2 offsetMultiplier = float2(cocRadius / aspectRatio, cocRadius);
|
||||
float cocRadius = max( abs(centerCoc), -minCoc) * 0.5f; // Small filter pass so half the radius
|
||||
float screenRadius = cocRadius * ViewSrg::m_dof.m_cocToScreenRatio * 0.5f;
|
||||
float2 offsetMultiplier = float2(screenRadius / aspectRatio, screenRadius);
|
||||
|
||||
// Color and weight accumulation
|
||||
float3 color = centerSample.rgb;
|
||||
// Weight accumulation. Start with 1 for center pixel.
|
||||
float totalWeight = 1;
|
||||
|
||||
for(uint i = 0; i < 8; ++i)
|
||||
for(uint i = 0; i < SAMPLES_LOOP_1; ++i)
|
||||
{
|
||||
// Calculate sample offset
|
||||
float2 offsetUV = GetOffsetUV(i, offsetMultiplier);
|
||||
float3 offset = GetOffset(i, offsetMultiplier);
|
||||
|
||||
// Get sample
|
||||
float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offsetUV).rgba;
|
||||
float4 sampleColorCoc = PassSrg::m_colorAndCoc.Sample(PassSrg::PointSampler, pixelUV + offset.xy).rgba;
|
||||
|
||||
// Calculate weight
|
||||
float cocDiff = sampleColorCoc.a - centerCoc;
|
||||
float weight = saturate( 2 - (20 * cocDiff));
|
||||
float weight = CaclulateWeight(offset.z, cocRadius, sampleColorCoc.a, centerCoc);
|
||||
|
||||
// Accumulate sample and weight
|
||||
color += sampleColorCoc.rgb * weight;
|
||||
color.rgb += sampleColorCoc.rgb * weight;
|
||||
totalWeight += weight;
|
||||
}
|
||||
|
||||
// Normalize accumulated sample
|
||||
color /= totalWeight;
|
||||
|
||||
// Output
|
||||
// Normalize accumulated sample
|
||||
color.rgb /= totalWeight;
|
||||
|
||||
PSOutput OUT;
|
||||
OUT.m_color.rgb = color;
|
||||
OUT.m_color.rgb = color.rgb;
|
||||
OUT.m_color.a = centerCoc;
|
||||
return OUT;
|
||||
}
|
||||
|
||||
@@ -33,13 +33,14 @@ struct PSOutput
|
||||
float2 m_color : SV_Target0;
|
||||
};
|
||||
|
||||
// Expands the min and max tiles so each tile contains the min and max of it's 3x3 neighborhood
|
||||
PSOutput MainPS(VSOutput IN)
|
||||
{
|
||||
// We want the min/max in a 3x3 region. Start sampling up left.
|
||||
float2 startPixelPos = IN.m_position.xy - float2(1, 1);
|
||||
|
||||
float2 stepSize = PassSrg::m_textureDimensions.zw;
|
||||
float2 startUV = startPixelPos * stepSize;
|
||||
float2 pixelSizeInUV = PassSrg::m_textureDimensions.zw;
|
||||
float2 startUV = startPixelPos * pixelSizeInUV;
|
||||
|
||||
float cocMin = 1.0f;
|
||||
float cocMax = -1.0f;
|
||||
@@ -51,7 +52,7 @@ PSOutput MainPS(VSOutput IN)
|
||||
[unroll]
|
||||
for(float X = 0.0f; X < 3.0f; X += 1.0f)
|
||||
{
|
||||
float2 sampleUV = mad(float2(X, Y), stepSize, startUV);
|
||||
float2 sampleUV = mad(float2(X, Y), pixelSizeInUV, startUV);
|
||||
float2 minMax = PassSrg::m_minMaxSource.SampleLevel(PassSrg::PointSampler, sampleUV, 0).xy;
|
||||
|
||||
cocMin = min(cocMin, minMax.x);
|
||||
|
||||
@@ -36,6 +36,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass
|
||||
groupshared uint LDS_MIN_COC[8];
|
||||
groupshared uint LDS_MAX_COC[8];
|
||||
|
||||
// Calculates the min and max CoC (Circle of Confusion) for 16x16 pixel tiles
|
||||
[numthreads(8, 8, 1)]
|
||||
void MainCS(uint3 group_thread_id : SV_GroupThreadID, uint3 group_id : SV_GroupID, uint3 dispatch_id: SV_DispatchThreadID, uint linear_id : SV_GroupIndex)
|
||||
{
|
||||
@@ -68,9 +69,11 @@ void MainCS(uint3 group_thread_id : SV_GroupThreadID, uint3 group_id : SV_GroupI
|
||||
return;
|
||||
}
|
||||
|
||||
// Min the mins and max the maxs
|
||||
InterlockedMin( LDS_MIN_COC[0], LDS_MIN_COC[group_thread_id.x] );
|
||||
InterlockedMax( LDS_MAX_COC[0], LDS_MAX_COC[group_thread_id.x] );
|
||||
|
||||
// Each group write to just one pixel. If we're the last thread in the group, write out
|
||||
if(group_thread_id.x == 0)
|
||||
{
|
||||
// Unpack uints
|
||||
|
||||
@@ -443,6 +443,7 @@ set(FILES
|
||||
Shaders/PostProcessing/MSAAResolveCustom.shader
|
||||
Shaders/PostProcessing/MSAAResolveDepth.azsl
|
||||
Shaders/PostProcessing/MSAAResolveDepth.shader
|
||||
Shaders/PostProcessing/NewDepthOfFieldCommon.azsli
|
||||
Shaders/PostProcessing/NewDepthOfFieldComposite.azsl
|
||||
Shaders/PostProcessing/NewDepthOfFieldComposite.shader
|
||||
Shaders/PostProcessing/NewDepthOfFieldDownsample.azsl
|
||||
|
||||
@@ -252,10 +252,6 @@ namespace AZ
|
||||
passSystem->AddPassCreator(Name("NewDepthOfFieldParentPass"), &NewDepthOfFieldParentPass::Create);
|
||||
passSystem->AddPassCreator(Name("NewDepthOfFieldTileReducePass"), &NewDepthOfFieldTileReducePass::Create);
|
||||
passSystem->AddPassCreator(Name("NewDepthOfFieldFilterPass"), &NewDepthOfFieldFilterPass::Create);
|
||||
passSystem->AddPassCreator(Name("NewDepthOfFieldCompositePass"), &NewDepthOfFieldCompositePass::Create);
|
||||
|
||||
|
||||
|
||||
|
||||
// Add FastDepthAwareBlur passes
|
||||
passSystem->AddPassCreator(Name("FastDepthAwareBlurHorPass"), &FastDepthAwareBlurHorPass::Create);
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace AZ
|
||||
// W is unused
|
||||
};
|
||||
|
||||
|
||||
// --- Depth of Field Parent Pass ---
|
||||
|
||||
RPI::Ptr<NewDepthOfFieldParentPass> NewDepthOfFieldParentPass::Create(const RPI::PassDescriptor& descriptor)
|
||||
@@ -103,8 +102,8 @@ namespace AZ
|
||||
NewDepthOfFieldTileReducePass::NewDepthOfFieldTileReducePass(const RPI::PassDescriptor& descriptor)
|
||||
: RPI::ComputePass(descriptor)
|
||||
{
|
||||
// Though this is a fullscreen pass, the algorithm used makes each thread output 3 blurred pixels, so
|
||||
// it's not a 1-to-1 ratio and requires custom calculation of target thread counts
|
||||
// Though this is a fullscreen pass, the shader computes 16x16 tiles with groups of 8x8 threads,
|
||||
// each thread outputting to a single pixel in the tiled min/max texture
|
||||
m_isFullscreenPass = false;
|
||||
}
|
||||
|
||||
@@ -124,8 +123,6 @@ namespace AZ
|
||||
RPI::ComputePass::FrameBeginInternal(params);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- Filter Pass ---
|
||||
|
||||
RPI::Ptr<NewDepthOfFieldFilterPass> NewDepthOfFieldFilterPass::Create(const RPI::PassDescriptor& descriptor)
|
||||
@@ -144,22 +141,19 @@ namespace AZ
|
||||
|
||||
uint32_t sampleIndex = 0;
|
||||
|
||||
// Calculate all the offset positions
|
||||
for (uint32_t loop = 0; loop < NewDepthOfFieldConstants::numberOfLoops; ++loop)
|
||||
{
|
||||
float radius = (loop + 1.0f) / float(NewDepthOfFieldConstants::numberOfLoops);
|
||||
float loopCount = NewDepthOfFieldConstants::loopCounts[loop];
|
||||
|
||||
float angleOffset = 0;
|
||||
float angleStep = Constants::TwoPi / loopCount;
|
||||
|
||||
// Every other loop slightly rotate sample ring so they don't line up
|
||||
if (loop & 1)
|
||||
{
|
||||
angleOffset = Constants::TwoPi * 0.5f / loopCount;
|
||||
}
|
||||
float angle = (loop & 1) ? (angleStep * 0.5f) : 0;
|
||||
|
||||
for (float i = 0.0f; i < loopCount; ++i)
|
||||
{
|
||||
float angle = Constants::TwoPi * i / loopCount;
|
||||
Vector2 pos = Vector2::CreateFromAngle(angle);
|
||||
pos = pos * radius;
|
||||
|
||||
@@ -167,38 +161,16 @@ namespace AZ
|
||||
dofConstants.m_samplePositions[sampleIndex][1] = pos.GetY();
|
||||
dofConstants.m_samplePositions[sampleIndex][2] = radius;
|
||||
dofConstants.m_samplePositions[sampleIndex][3] = 0.0f;
|
||||
++sampleIndex;
|
||||
}
|
||||
|
||||
++sampleIndex;
|
||||
angle += angleStep;
|
||||
}
|
||||
}
|
||||
|
||||
m_shaderResourceGroup->SetConstant(m_constantsIndex, dofConstants);
|
||||
|
||||
// TODO HERE
|
||||
RPI::FullscreenTrianglePass::FrameBeginInternal(params);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- Composite Pass ---
|
||||
|
||||
RPI::Ptr<NewDepthOfFieldCompositePass> NewDepthOfFieldCompositePass::Create(const RPI::PassDescriptor& descriptor)
|
||||
{
|
||||
RPI::Ptr<NewDepthOfFieldCompositePass> pass = aznew NewDepthOfFieldCompositePass(descriptor);
|
||||
return AZStd::move(pass);
|
||||
}
|
||||
|
||||
NewDepthOfFieldCompositePass::NewDepthOfFieldCompositePass(const RPI::PassDescriptor& descriptor)
|
||||
: RPI::ComputePass(descriptor)
|
||||
{ }
|
||||
|
||||
void NewDepthOfFieldCompositePass::FrameBeginInternal(FramePrepareParams params)
|
||||
{
|
||||
// TODO HERE
|
||||
RPI::ComputePass::FrameBeginInternal(params);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -17,7 +17,9 @@ namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
//!
|
||||
//! Parent pass for the new depth of field technique
|
||||
//! Main updates the view srg via the depth of field settings
|
||||
//! And enables/disables all depth of field passes based on component activation
|
||||
class NewDepthOfFieldParentPass final
|
||||
: public RPI::ParentPass
|
||||
{
|
||||
@@ -41,8 +43,7 @@ namespace AZ
|
||||
};
|
||||
|
||||
|
||||
|
||||
//!
|
||||
//! Need a class for the tile reduce pass because it dispatches a non-trivial number of threads
|
||||
class NewDepthOfFieldTileReducePass final
|
||||
: public RPI::ComputePass
|
||||
{
|
||||
@@ -64,8 +65,9 @@ namespace AZ
|
||||
};
|
||||
|
||||
|
||||
|
||||
//!
|
||||
//! Filter pass used to render the bokeh blur effect on downsampled image buffer
|
||||
//! This class is used for both the large filter and the small filter
|
||||
//! It's main purpose is calculating the sample positions and setting srg constants
|
||||
class NewDepthOfFieldFilterPass final
|
||||
: public RPI::FullscreenTrianglePass
|
||||
{
|
||||
@@ -90,28 +92,5 @@ namespace AZ
|
||||
};
|
||||
|
||||
|
||||
|
||||
//!
|
||||
class NewDepthOfFieldCompositePass final
|
||||
: public RPI::ComputePass
|
||||
{
|
||||
AZ_RPI_PASS(NewDepthOfFieldCompositePass);
|
||||
|
||||
public:
|
||||
AZ_RTTI(AZ::Render::NewDepthOfFieldCompositePass, "{63270A3A-EAE5-4C0C-98AA-43CA55279613}", AZ::RPI::ComputePass);
|
||||
AZ_CLASS_ALLOCATOR(NewDepthOfFieldCompositePass, SystemAllocator, 0);
|
||||
virtual ~NewDepthOfFieldCompositePass() = default;
|
||||
|
||||
static RPI::Ptr<NewDepthOfFieldCompositePass> Create(const RPI::PassDescriptor& descriptor);
|
||||
|
||||
protected:
|
||||
// Behavior functions override...
|
||||
void FrameBeginInternal(FramePrepareParams params) override;
|
||||
|
||||
private:
|
||||
NewDepthOfFieldCompositePass(const RPI::PassDescriptor& descriptor);
|
||||
};
|
||||
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
Reference in New Issue
Block a user