FidelityFX-FSR2/src/GpuParticleShaders/ParticleRender.hlsl

264 lines
8.7 KiB
HLSL

//
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
// Shader code for rendering particles as simple quads using rasterization
//
#include "ParticleStructs.h"
#include "ParticleHelpers.h"
#include "fp16util.h"
struct PS_INPUT
{
nointerpolation float4 ViewSpaceCentreAndRadius : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
float3 ViewPos : TEXCOORD2;
nointerpolation float3 VelocityXYEmitterNdotL : TEXCOORD3;
nointerpolation float3 Extrusion : TEXCOORD4;
nointerpolation float2 EllipsoidRadius : TEXCOORD5;
nointerpolation float4 Color : COLOR0;
float4 Position : SV_POSITION;
};
// The particle buffer data. Note this is only one half of the particle data - the data that is relevant to rendering as opposed to simulation
[[vk::binding( 0, 0 )]] StructuredBuffer<GPUParticlePartA> g_ParticleBufferA : register( t0 );
// A buffer containing the pre-computed view space positions of the particles
[[vk::binding( 1, 0 )]] StructuredBuffer<uint2> g_PackedViewSpacePositions : register( t1 );
// The number of sorted particles
[[vk::binding( 2, 0 )]] StructuredBuffer<int> g_NumParticlesBuffer : register( t2 );
// The sorted index list of particles
[[vk::binding( 3, 0 )]] StructuredBuffer<int> g_SortedIndexBuffer : register( t3 );
// The texture atlas for the particles
[[vk::binding( 4, 0 )]] Texture2D g_ParticleTexture : register( t4 );
// The opaque scene depth buffer read as a texture
[[vk::binding( 5, 0 )]] Texture2D<float> g_DepthTexture : register( t5 );
[[vk::binding( 6, 0 )]] cbuffer RenderingConstantBuffer : register( b0 )
{
matrix g_mProjection;
matrix g_mProjectionInv;
float4 g_SunColor;
float4 g_AmbientColor;
float4 g_SunDirectionVS;
uint g_ScreenWidth;
uint g_ScreenHeight;
uint g_pads0;
uint g_pads1;
};
[[vk::binding( 7, 0 )]] SamplerState g_samClampLinear : register( s0 );
// Vertex shader only path
PS_INPUT VS_StructuredBuffer( uint VertexId : SV_VertexID )
{
PS_INPUT Output = (PS_INPUT)0;
// Particle index
uint particleIndex = VertexId / 4;
// Per-particle corner index
uint cornerIndex = VertexId % 4;
float xOffset = 0;
const float2 offsets[ 4 ] =
{
float2( -1, 1 ),
float2( 1, 1 ),
float2( -1, -1 ),
float2( 1, -1 ),
};
int NumParticles = g_NumParticlesBuffer[ 0 ];
int index = g_SortedIndexBuffer[ NumParticles - particleIndex - 1 ];
GPUParticlePartA pa = g_ParticleBufferA[ index ];
float4 ViewSpaceCentreAndRadius = UnpackFloat16( g_PackedViewSpacePositions[ index ] );
float4 VelocityXYEmitterNdotLRotation = UnpackFloat16( pa.m_PackedVelocityXYEmitterNDotLAndRotation );
uint emitterProperties = pa.m_StreakLengthAndEmitterProperties;
bool streaks = IsStreakEmitter( emitterProperties );
float2 offset = offsets[ cornerIndex ];
float2 uv = (offset+1)*float2( 0.25, 0.5 );
uv.x += GetTextureOffset( emitterProperties );
float radius = ViewSpaceCentreAndRadius.w;
float3 cameraFacingPos;
#if defined (STREAKS)
if ( streaks )
{
float2 viewSpaceVelocity = VelocityXYEmitterNdotLRotation.xy;
float2 ellipsoidRadius = float2( radius, UnpackFloat16( pa.m_StreakLengthAndEmitterProperties ).x );
float2 extrusionVector = viewSpaceVelocity;
float2 tangentVector = float2( extrusionVector.y, -extrusionVector.x );
float2x2 transform = float2x2( tangentVector, extrusionVector );
Output.Extrusion.xy = extrusionVector;
Output.Extrusion.z = 1.0;
Output.EllipsoidRadius = ellipsoidRadius;
cameraFacingPos = ViewSpaceCentreAndRadius.xyz;
cameraFacingPos.xy += mul( offset * ellipsoidRadius, transform );
}
else
#endif
{
float s, c;
sincos( VelocityXYEmitterNdotLRotation.w, s, c );
float2x2 rotation = { float2( c, -s ), float2( s, c ) };
offset = mul( offset, rotation );
cameraFacingPos = ViewSpaceCentreAndRadius.xyz;
cameraFacingPos.xy += radius * offset;
}
Output.Position = mul( g_mProjection, float4( cameraFacingPos, 1 ) );
Output.TexCoord = uv;
Output.Color = UnpackFloat16( pa.m_PackedTintAndAlpha );
Output.ViewSpaceCentreAndRadius = ViewSpaceCentreAndRadius;
Output.VelocityXYEmitterNdotL = VelocityXYEmitterNdotLRotation.xyz;
Output.ViewPos = cameraFacingPos;
return Output;
}
struct PS_OUTPUT
{
float4 color : SV_TARGET0;
#if defined (REACTIVE)
float reactiveMask : SV_TARGET2;
#endif
};
// Ratserization path's pixel shader
PS_OUTPUT PS_Billboard( PS_INPUT In )
{
PS_OUTPUT output = (PS_OUTPUT)0;
// Retrieve the particle data
float3 particleViewSpacePos = In.ViewSpaceCentreAndRadius.xyz;
float particleRadius = In.ViewSpaceCentreAndRadius.w;
// Get the depth at this point in screen space
float depth = g_DepthTexture.Load( uint3( In.Position.x, In.Position.y, 0 ) ).x;
// Get viewspace position by generating a point in screen space at the depth of the depth buffer
float4 viewSpacePos;
viewSpacePos.x = In.Position.x / (float)g_ScreenWidth;
viewSpacePos.y = 1 - ( In.Position.y / (float)g_ScreenHeight );
viewSpacePos.xy = (2*viewSpacePos.xy) - 1;
viewSpacePos.z = depth;
viewSpacePos.w = 1;
// ...then transform it into view space using the inverse projection matrix and a divide by W
viewSpacePos = mul( g_mProjectionInv, viewSpacePos );
viewSpacePos.xyz /= viewSpacePos.w;
// Calculate the depth fade factor
float depthFade = saturate( ( particleViewSpacePos.z - viewSpacePos.z ) / particleRadius );
float4 albedo = 1;
albedo.a = depthFade;
// Read the texture atlas
albedo *= g_ParticleTexture.SampleLevel( g_samClampLinear, In.TexCoord, 0 ); // 2d
// Multiply in the particle color
output.color = albedo * In.Color;
// Calculate the UV based the screen space position
float3 n = 0;
float2 uv;
#if defined (STREAKS)
if ( In.Extrusion.z > 0.0 )
{
float2 ellipsoidRadius = In.EllipsoidRadius;
float2 extrusionVector = In.Extrusion.xy;
float2 tangentVector = float2( extrusionVector.y, -extrusionVector.x );
float2x2 transform = float2x2( tangentVector, extrusionVector );
float2 vecToCentre = In.ViewPos.xy - particleViewSpacePos.xy;
vecToCentre = mul( transform, vecToCentre );
uv = vecToCentre / ellipsoidRadius;
}
else
#endif
{
uv = (In.ViewPos.xy - particleViewSpacePos.xy ) / particleRadius;
}
// Scale and bias
uv = (1+uv)*0.5;
float pi = 3.1415926535897932384626433832795;
n.x = -cos( pi * uv.x );
n.y = -cos( pi * uv.y );
n.z = sin( pi * length( uv ) );
n = normalize( n );
float ndotl = saturate( dot( g_SunDirectionVS.xyz, n ) );
// Fetch the emitter's lighting term
float emitterNdotL = In.VelocityXYEmitterNdotL.z;
// Mix the particle lighting term with the emitter lighting
ndotl = lerp( ndotl, emitterNdotL, 0.5 );
// Ambient lighting plus directional lighting
float3 lighting = g_AmbientColor.rgb + ndotl * g_SunColor.rgb;
// Multiply lighting term in
output.color.rgb *= lighting;
#if defined (REACTIVE)
output.reactiveMask = max( output.color.r, max( output.color.g, output.color.b ) ) * albedo.a;
#endif
return output;
}