Files
UnrealEngineUWP/Engine/Shaders/ScreenSpaceRayCast.usf
Gil Gribb 2614787137 Copying //UE4/Dev-Rendering to //UE4/Dev-Main (Source: //UE4/Dev-Rendering @ 2981742)
#lockdown nick.penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 2967522 on 2016/05/05 by Martin.Mittring

	fixed UE-30208 Ensure taking high resolution screenshot
	renamed cvar from r.SaveUncompressedEXRFrame to r.SaveEXR.CompressionQuality and change meaning

Change 2967541 on 2016/05/05 by Martin.Mittring

	added cvar help entry to the editor menu

Change 2967544 on 2016/05/05 by Martin.Mittring

	* added ensures to track down UE-22073 [CrashReport] Crash when changing Editor Window Size - FDeferredShadingSceneRenderer::ClearTranslucentVolumeLighting()
	* fixed typo
	* improved r.DisplayInternals

Change 2967685 on 2016/05/05 by Rolando.Caloca

	DR - Fix 2013 compile
	#jira UE-30369

Change 2967883 on 2016/05/05 by Olaf.Piesche

	Making inherit rotation work for mesh particles
	#jira UE-30153

Change 2967948 on 2016/05/05 by Daniel.Wright

	MaterialParameterCollections now create default resources (uniform buffers) which are used when no valid FScene is present (eg DrawTile while exporting materials to lightmass)

Change 2967954 on 2016/05/05 by Daniel.Wright

	New refraction mode 'Pixel Normal Offset', which uses the difference between the per-pixel normal and the per-vertex normal to compute the refraction offset.  This is useful for refraction from large water surfaces without reading outside of screen bounds as much.

Change 2967970 on 2016/05/05 by Olaf.Piesche

	Improvement for depth buffer collision; reduce tunneling by sampling midpoint instead of predicted position.

	#jira UE-27297

Change 2968125 on 2016/05/05 by Daniel.Wright

	Hopeful fix for mac compile error with enum

Change 2968126 on 2016/05/05 by Daniel.Wright

	Forward declare to fix compile error

Change 2969070 on 2016/05/06 by Martin.Mittring

	fixed Clang Compile error

Change 2969224 on 2016/05/06 by Martin.Mittring

	fixed Clang

Change 2969275 on 2016/05/06 by Rolando.Caloca

	DR - Fix for simulation time from BP not matching material editor expression time
	#jira UE-26431

Change 2969413 on 2016/05/06 by Daniel.Wright

	Simple forward shading path
	* Support for a directional light in the base pass, which can be shadowed either by distance field shadowmaps or a single shadow factor from the Indirect Lighting Cache
	* Binding and outputting to GBuffers is disabled when using simple forward shading, along with dependencies of the GBuffers
	* Specular, normal maps and the 3rd SH band of skylighting are all hardcoded off.  Materials are forced fully rough.
	* Enabled with 'r.SimpleForwardShading 1', which can be changed at runtime
	* Added r.SupportSimpleForwardShading, which determines if the necessary shaders are compiled
	* Removed r.SimpleDynamicLighting, whose functionality (unshadowed directional light in the base pass) is a subset of simple forward shading, and was unused

Change 2969414 on 2016/05/06 by Daniel.Wright

	Added cvar 'r.Fog' for scalability

Change 2969415 on 2016/05/06 by Daniel.Wright

	Low end scalability setup for Paragon

Change 2969583 on 2016/05/06 by Daniel.Wright

	Effectively disabled the WRITES_PRECSHADOWFACTOR_TO_GBUFFER optimization, as all combinations use the GBuffer target
	* This fixes bSingleSampleShadowFromStationaryLights which was broken in cl 2863775 when selective GBuffer outputs was enabled

Change 2969597 on 2016/05/06 by Olaf.Piesche

	Adding emitter tick times to Cascade viewport overlays

	#jira UE-25172

Change 2969599 on 2016/05/06 by Daniel.Wright

	Added r.Shadow.ForceSingleSampleShadowingFromStationary for scalability

Change 2969795 on 2016/05/06 by Daniel.Wright

	Made r.SimpleForwardShading a scalability cvar

Change 2969796 on 2016/05/06 by Daniel.Wright

	Enabled simple forward shading for the lowest shadow quality in Paragon
	* Moved Orion.Character.NonLocalHeroPreshadows to be under shadow quality
	* Enabling r.Shadow.ForceSingleSampleShadowingFromStationary when shadows are disabled through r.ShadowQuality

Change 2972338 on 2016/05/10 by Martin.Mittring

	Added ImageValidator V0.11 to Perforce (for automated screenshot comparison)

Change 2972450 on 2016/05/10 by Martin.Mittring

	fixed sorting issues, added column sort

Change 2972564 on 2016/05/10 by Martin.Mittring

	fixed PixelCountToFail

Change 2972572 on 2016/05/10 by Martin.Mittring

	added color

Change 2972667 on 2016/05/10 by Daniel.Wright

	Capsule shadows support an off-center projection - fixes stereo rendering
	Indirect lighting cache is updated for primitives with a visible indirect capsule shadow - fixes indirect shadows disappearing when the caster is off-screen in the Static skylight case

Change 2972687 on 2016/05/10 by Martin.Mittring

	split data from view

Change 2972713 on 2016/05/10 by Martin.Mittring

	background validation

Change 2972742 on 2016/05/10 by Martin.Mittring

	do not lock files in folder

Change 2972837 on 2016/05/10 by Daniel.Wright

	Comment for tiled reflection culling edge failure case

Change 2972891 on 2016/05/10 by Daniel.Wright

	Simple forward shading only supported on PC now

Change 2972927 on 2016/05/10 by Martin.Mittring

	fixed comparison, added directory watcher

Change 2972952 on 2016/05/10 by Martin.Mittring

	tooltips

Change 2972965 on 2016/05/10 by Martin.Mittring

	readme

Change 2972986 on 2016/05/10 by Martin.Mittring

	polish

Change 2973015 on 2016/05/10 by Zabir.Hoque

	Clamp max cubemap resolutions for reflection capture component.

Change 2973067 on 2016/05/10 by Uriel.Doyon

	Removed temporary streaming data from ULevel. Now the data goes directly in FStreamingManagerTexture.
	Removed deprecated classes and structures associated with old data.
	Uniformized dynamic primitives and static primitives streaming logic.
	Static primitive instances are now bound to level component and have visibility information.
	MeshTexCoordSize Debug now shows live update when tweaking "StreamingDistanceMultiplier"

Change 2973129 on 2016/05/10 by Martin.Mittring

	fixed crash (uninit var)

Change 2973167 on 2016/05/10 by Olaf.Piesche

	Fixing mac compiler warnings; removed beam tangent from particle source and target, as it's treated separately anyway.

Change 2973654 on 2016/05/11 by Gil.Gribb

	FIxed bad resolve from main merge

Change 2973787 on 2016/05/11 by Simon.Tovey

	PR #2080: Added 7 additional blueprint nodes and assoicated functions to Particle System Compoenent (Contributed by alwintom)

	#2080

Change 2973794 on 2016/05/11 by Simon.Tovey

	GitHub 1646 : Increase Wireframe Linear Color Value for Particles in Cascade Preview viewport

	#1646

Change 2973814 on 2016/05/11 by Chris.Bunner

	Fixed D3D warning.

Change 2973868 on 2016/05/11 by Martin.Mittring

	fixed compiler warning

Change 2974104 on 2016/05/11 by Uriel.Doyon

	Optimized TextureStreaming ASync task by improving cache efficency.
	Removed ForcedFullyLoad texture sets and merged them with the other entries (to prevent checking in two data structures).

Change 2974163 on 2016/05/11 by Uriel.Doyon

	Fixed Editor Build

Change 2974263 on 2016/05/11 by Olaf.Piesche

	Fix for particle beam source/target selection

Change 2974313 on 2016/05/11 by Martin.Mittring

	nicer icon

Change 2974632 on 2016/05/11 by Martin.Mittring

	zoom (mouse wheel) and pan support

Change 2974651 on 2016/05/11 by Martin.Mittring

	UE-30565 Blend Radius does not override Priority for blendable post process material array
	#test:PC

Change 2974994 on 2016/05/12 by Uriel.Doyon

	Fixed uninitialized members in texture streaming when updating dynamic primitives.
	#jira UE-30632

Change 2975514 on 2016/05/12 by Olaf.Piesche

	Getting mesh particle transform down to pixel shader, making available in TransformVector/TransformPosition nodes

	#udn 288158, and requests from several artists

Change 2975970 on 2016/05/12 by Zabir.Hoque

	Enable setting high precision normals/tangets as a part of static mesh import.

Change 2976134 on 2016/05/12 by Daniel.Wright

	Moved RHI prefix out of command list macros so you can find callers in a Find in Files for RHIBlendState, etc

Change 2976135 on 2016/05/12 by Daniel.Wright

	Added material property bAllowNegativeEmissiveColor which is useful when rendering to an offscreen render target

Change 2976139 on 2016/05/12 by Daniel.Wright

	Blueprint can now be used to draw to a TextureRenderTarget2D  with DrawMaterialToRenderTarget
	Canvas can now draw to a TextureRenderTarget2D in a Blueprint with BeginDrawCanvasToRenderTarget / EndDrawCanvasToRenderTarget

Change 2976199 on 2016/05/12 by Brian.Karis

	Improved screen space ray cast intersection heuristic.

Change 2976203 on 2016/05/12 by Brian.Karis

	Fixed hair NaNs

Change 2976214 on 2016/05/12 by Zabir.Hoque

	Fix compiler error on Clang

Change 2976239 on 2016/05/12 by Brian.Karis

	Improved hair shadows

Change 2976240 on 2016/05/12 by Brian.Karis

	Made recompileshaders specific file work again. Kind of hacky but better than nothing

Change 2976290 on 2016/05/12 by Zabir.Hoque

	Few more clang compiler fixes.

	#jira UE-30713

Change 2976517 on 2016/05/13 by Zabir.Hoque

	Final set of fixes for compile breaks.

Change 2976535 on 2016/05/13 by Zabir.Hoque

	Fix mono builds

Change 2977270 on 2016/05/13 by Zabir.Hoque

	Incorrectly used 7 as max texcoords. Corrected to #define MAX_TEX_COORDS

	#lockdown gil.gribb

Change 2980140 on 2016/05/17 by Gil.Gribb

	Merging //UE4/Dev-Main@2980127 to Dev-Rendering (//UE4/Dev-Rendering)
	#lockdown nick.penwarden

Change 2980211 on 2016/05/17 by Ben.Marsh

	EC: Build DDC in Dev-Rendering every 3 hours.

	#lockdown Gil.Gribb

Change 2980876 on 2016/05/17 by Michael.Trepka

	Metal shader compile fix

	#lockdown gil.gribb

[CL 2981788 by Gil Gribb in Main branch]
2016-05-18 09:31:59 -04:00

539 lines
19 KiB
Plaintext

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Common.usf"
// 0:reference (slower, potentially higher quality) 1:use mips of the HZB depth (better performance)
#define USE_HZB 1
#define SCALAR_BRANCHLESS 0
#define VECTORIZED_BRANCHLESS 0
#define VECTORIZED_EARLY_OUT 1
#if USE_HZB
#define HZB_LEVEL_OFFSET 1.0
#else
#define HZB_LEVEL_OFFSET 0.0
#endif
float4 HZBUvFactorAndInvFactor;
float4 SampleDepthTexture( Texture2D Texture, SamplerState Sampler, float Level, float4 SampleUV0, float4 SampleUV1 )
{
float4 SampleDepth;
#if USE_HZB
// SampleUV{0,1}.{xy,zw} should already be in the HZB UV frame using HZBUvFactorAndInvFactor.xy
SampleDepth.x = Texture2DSampleLevel( Texture, Sampler, SampleUV0.xy, Level ).r;
SampleDepth.y = Texture2DSampleLevel( Texture, Sampler, SampleUV0.zw, Level ).r;
SampleDepth.z = Texture2DSampleLevel( Texture, Sampler, SampleUV1.xy, Level ).r;
SampleDepth.w = Texture2DSampleLevel( Texture, Sampler, SampleUV1.zw, Level ).r;
#else
SampleDepth.x = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV0.xy, 0 ).r;
SampleDepth.y = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV0.zw, 0 ).r;
SampleDepth.z = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV1.xy, 0 ).r;
SampleDepth.w = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV1.zw, 0 ).r;
#endif
return SampleDepth;
}
void RayCast(
Texture2D Texture, SamplerState Sampler, float2 TextureSize,
float3 RayOriginTranslatedWorld, float3 RayDirection,
float Roughness, float ConeAngleWorld, float SceneDepth,
int NumSteps, float StepOffset,
out float4 OutHitUVzTime,
out float OutLevelHCB
)
{
// TODO provide RayStartUVz
const float4 RayStartV = mul( float4( RayOriginTranslatedWorld, 1 ), View.TranslatedWorldToView );
const float4 RayDirV = mul(float4(RayDirection * SceneDepth, 0), View.TranslatedWorldToView);
const float4 RayEndV = RayStartV + RayDirV;
const float RayEndRadiusV = length(RayDirV.xyz) * tan(ConeAngleWorld * 0.4);
const float2 RayEndBorderV = RayEndV.xy + RayEndRadiusV / sqrt(2.0);
const float4 RayStartClip = mul( RayStartV, View.ViewToClip );
const float4 RayEndClip = mul( RayEndV, View.ViewToClip );
const float2 RayEndBorderClip = mul(float4(RayEndBorderV, RayEndV.zw), View.ViewToClip).xy;
const float3 RayStartScreen = RayStartClip.xyz / RayStartClip.w;
const float3 RayEndScreen = RayEndClip.xyz / RayEndClip.w;
const float2 RayEndBorderScreen = RayEndBorderClip.xy / RayEndClip.w;
float4 RayDepthClip = RayStartClip + mul( float4( 0, 0, SceneDepth, 0 ), View.ViewToClip );
float3 RayDepthScreen = RayDepthClip.xyz / RayDepthClip.w;
float3 RayStepScreen = RayEndScreen - RayStartScreen;
float2 RayStepRadiusScreen = RayEndBorderScreen - RayEndScreen.xy;
{
// Computes the scale down factor for RayStepScreen required to fit on the X and Y axis in order to clip it in the viewport
const float RayStepScreenInvFactor = 0.5 * length( RayStepScreen.xy );
const float2 AbsRayStepScreen = abs(RayStepScreen.xy);
const float2 S = (AbsRayStepScreen - max(abs(RayStepScreen.xy + RayStartScreen.xy * RayStepScreenInvFactor) - RayStepScreenInvFactor, 0.0f)) / AbsRayStepScreen;
// Rescales RayStepScreen accordingly
const float RayStepFactor = min(S.x, S.y) / RayStepScreenInvFactor;
RayStepScreen *= RayStepFactor;
RayStepRadiusScreen *= RayStepFactor;
}
const float2 HzbSize = float2(1024, 512);
#if USE_HZB
float3 RayStartUVz = float3( (RayStartScreen.xy * float2( 0.5, -0.5 ) + 0.5) * HZBUvFactorAndInvFactor.xy, RayStartScreen.z );
float3 RayStepUVz = float3( RayStepScreen.xy * float2( 0.5, -0.5 ) * HZBUvFactorAndInvFactor.xy, RayStepScreen.z );
float2 RayStepRadiusUV = RayStepRadiusScreen.xy * float2( 0.5, -0.5 ) * HZBUvFactorAndInvFactor.xy;
#else
float3 RayStartUVz = float3( (RayStartScreen.xy * float2( 0.5, -0.5 ) + 0.5), RayStartScreen.z );
float3 RayStepUVz = float3( RayStepScreen.xy * float2( 0.5, -0.5 ), RayStepScreen.z );
float2 RayStepRadiusUV = RayStepRadiusScreen.xy * float2( 0.5, -0.5 );
#endif
const float RayStepRadiusFactor = length(RayStepRadiusUV * TextureSize);
const float Step = 1.0 / NumSteps;
const float CompareTolerance = abs( RayDepthScreen.z - RayStartScreen.z ) * Step * 4;
// avoid bugs with early returns inside of loops on certain platform compilers.
float4 Result = float4( 0, 0, 0, 1 );
#if SCALAR_BRANCHLESS
float MinHitTime = 1;
float LastDiff = 0;
float SampleTime = StepOffset * Step + Step;
UNROLL
for( int i = 0; i < NumSteps; i++ )
{
float3 SampleUVz = RayStartUVz + RayStepUVz * SampleTime;
// Use lower res for farther samples
float Level = Roughness * (i * 4.0 / NumSteps) + HZB_LEVEL_OFFSET;
float SampleDepth = Texture.SampleLevel( Sampler, SampleUVz.xy, Level ).r;
float DepthDiff = SampleUVz.z - SampleDepth;
bool Hit = abs( DepthDiff + CompareTolerance ) < CompareTolerance;
// Find more accurate hit using line segment intersection
float TimeLerp = saturate( LastDiff / (LastDiff - DepthDiff) );
float IntersectTime = SampleTime + TimeLerp * Step - Step;
float HitTime = Hit ? IntersectTime : 1;
MinHitTime = min( MinHitTime, HitTime );
LastDiff = DepthDiff;
SampleTime += Step;
}
float3 HitUVz = RayStartUVz + RayStepUVz * MinHitTime;
Result = float4( HitUVz, MinHitTime );
#elif VECTORIZED_BRANCHLESS
float MinHitTime = 1;
float LastDiff = 0;
float Level = HZB_LEVEL_OFFSET;
// Vectorized to group fetches
float4 SampleTime = ( StepOffset + float4( 1, 2, 3, 4 ) ) * Step;
float4 SampleUV0 = RayStartUVz.xyxy + RayStepUVz.xyxy * SampleTime.xxyy;
float4 SampleUV1 = RayStartUVz.xyxy + RayStepUVz.xyxy * SampleTime.zzww;
float4 SampleZ = RayStartUVz.zzzz + RayStepUVz.zzzz * SampleTime;
LOOP
for( int i = 0; i < NumSteps; i += 4 )
{
// Use lower res for farther samples
float4 SampleDepth = SampleDepthTexture( Texture, Sampler, Level, SampleUV0, SampleUV1 );
#if 1
float4 DepthDiff = SampleZ - SampleDepth;
float4 IntersectTime = ( SampleDepth - RayStartUVz.zzzz ) / RayStepUVz.zzzz;
bool4 Hit = abs( DepthDiff + CompareTolerance ) < CompareTolerance;
// If hit set to intersect time. If missed set to 1, beyond end of ray
float4 HitTime = Hit ? IntersectTime : 1;
// Take closest hit
HitTime.xy = min( HitTime.xy, HitTime.zw );
MinHitTime = min( HitTime.x, HitTime.y );
#else
// Line segment intersection
float4 DepthDiff1 = SampleZ - SampleDepth;
float4 DepthDiff0 = float4( LastDiff, DepthDiff1.xyz );
float4 TimeLerp = saturate( DepthDiff0 / (DepthDiff0 - DepthDiff1) );
float4 IntersectTime = SampleTime + (TimeLerp - 1) / (NumSteps + 1);
bool4 Hit = abs( DepthDiff1 + CompareTolerance ) < CompareTolerance;
// If hit set to intersect time. If missed set to 1, beyond end of ray
float4 HitTime = Hit ? IntersectTime : 1;
// Take closest hit
HitTime.xy = min( HitTime.xy, HitTime.zw );
MinHitTime = min( MinHitTime, min( HitTime.x, HitTime.y ) );
LastDiff = DepthDiff1.w;
#endif
Level += Roughness * (16.0 / NumSteps);
SampleTime += 4.0 / (NumSteps + 1);
SampleUV0 += RayStepUVz.xyxy * 4.0 / (NumSteps + 1);
SampleUV1 += RayStepUVz.xyxy * 4.0 / (NumSteps + 1);
SampleZ += RayStepUVz.zzzz * 4.0 / (NumSteps + 1);
}
float3 HitUVz = RayStartUVz + RayStepUVz * MinHitTime;
Result = float4( HitUVz, MinHitTime );
#elif 1
float LastDiff = 0;
float Level = HZB_LEVEL_OFFSET;
RayStepUVz *= Step;
float3 RayUVz = RayStartUVz + RayStepUVz * StepOffset;
LOOP
for( int i = 0; i < NumSteps; i += 4 )
{
// Vectorized to group fetches
float4 SampleUV0 = RayUVz.xyxy + RayStepUVz.xyxy * float4( 1, 1, 2, 2 );
float4 SampleUV1 = RayUVz.xyxy + RayStepUVz.xyxy * float4( 3, 3, 4, 4 );
float4 SampleZ = RayUVz.zzzz + RayStepUVz.zzzz * float4( 1, 2, 3, 4 );
// Use lower res for farther samples
float4 SampleDepth = SampleDepthTexture( Texture, Sampler, Level, SampleUV0, SampleUV1 );
float4 DepthDiff = SampleZ - SampleDepth;
bool4 Hit = abs( -DepthDiff - CompareTolerance ) < CompareTolerance;
BRANCH if( any( Hit ) )
{
float DepthDiff0 = DepthDiff[2];
float DepthDiff1 = DepthDiff[3];
float MinTime = 3;
FLATTEN if( Hit[2] )
{
DepthDiff0 = DepthDiff[1];
DepthDiff1 = DepthDiff[2];
MinTime = 2;
}
FLATTEN if( Hit[1] )
{
DepthDiff0 = DepthDiff[0];
DepthDiff1 = DepthDiff[1];
MinTime = 1;
}
FLATTEN if( Hit[0] )
{
DepthDiff0 = LastDiff;
DepthDiff1 = DepthDiff[0];
MinTime = 0;
}
// Find more accurate hit using line segment intersection
float TimeLerp = saturate( DepthDiff0 / (DepthDiff0 - DepthDiff1) );
float IntersectTime = MinTime + TimeLerp;
float3 HitUVz = RayUVz + RayStepUVz * IntersectTime;
Result = float4( HitUVz, 0.5 );
break;
}
LastDiff = DepthDiff.w;
Level += Roughness * (16.0 / NumSteps);
RayUVz += 4 * RayStepUVz;
}
#elif 1
float Level = HZB_LEVEL_OFFSET;
RayStepUVz *= Step;
float3 RayUVz = RayStartUVz + RayStepUVz * StepOffset;
LOOP
for( uint i = 0; i < NumSteps; i += 4 )
{
// Vectorized to group fetches
float4 SampleUV0 = RayUVz.xyxy + RayStepUVz.xyxy * float4( 1, 1, 2, 2 );
float4 SampleUV1 = RayUVz.xyxy + RayStepUVz.xyxy * float4( 3, 3, 4, 4 );
float4 SampleZ = RayUVz.zzzz + RayStepUVz.zzzz * float4( 1, 2, 3, 4 );
// Use lower res for farther samples
float4 SampleDepth = SampleDepthTexture( Texture, Sampler, Level, SampleUV0, SampleUV1 );
float4 DepthDiff = SampleZ - SampleDepth;
bool4 Hit = abs( -DepthDiff - CompareTolerance ) < CompareTolerance;
BRANCH if( any( Hit ) )
{
float MinTime = 3;
MinTime = Hit[2] ? 2 : MinTime;
MinTime = Hit[1] ? 1 : MinTime;
MinTime = Hit[0] ? 0 : MinTime;
float3 HitUVz = RayUVz + RayStepUVz * MinTime;
Result = float4( HitUVz, 0.5 );
break;
}
Level += Roughness * (16.0 / NumSteps);
RayUVz += 4 * RayStepUVz;
}
#else // VECTORIZED_EARLY_OUT
float LastDiff = 0;
float Level = HZB_LEVEL_OFFSET;
float4 SampleTime = ( StepOffset + float4( 1, 2, 3, 4 ) ) * Step;
LOOP
for( int i = 0; i < NumSteps; i += 4 )
{
// Vectorized to group fetches
float4 SampleUV0 = RayStartUVz.xyxy + RayStepUVz.xyxy * SampleTime.xxyy;
float4 SampleUV1 = RayStartUVz.xyxy + RayStepUVz.xyxy * SampleTime.zzww;
float4 SampleZ = RayStartUVz.zzzz + RayStepUVz.zzzz * SampleTime;
// Use lower res for farther samples
float4 SampleDepth = SampleDepthTexture( Texture, Sampler, Level, SampleUV0, SampleUV1 );
float4 DepthDiff1 = SampleZ - SampleDepth;
bool4 Hit = abs( -DepthDiff1 - CompareTolerance ) < CompareTolerance;
BRANCH if( any( Hit ) )
{
// Find more accurate hit using line segment intersection
float4 DepthDiff0 = float4( LastDiff, DepthDiff1.xyz );
float4 TimeLerp = saturate( DepthDiff0 / (DepthDiff0 - DepthDiff1) );
float4 IntersectTime = SampleTime + (TimeLerp - 1) / (NumSteps + 1);
float4 HitTime = Hit ? IntersectTime : 1;
// Take closest hit
HitTime.xy = min( HitTime.xy, HitTime.zw );
float MinHitTime = min( HitTime.x, HitTime.y );
float3 HitUVz = RayStartUVz + RayStepUVz * MinHitTime;
Result = float4( HitUVz, MinHitTime );
break;
}
LastDiff = DepthDiff1.w;
Level += Roughness * (16.0 / NumSteps);
SampleTime += 4.0 / (NumSteps + 1);
}
#endif
#if USE_HZB
Result.xy *= HZBUvFactorAndInvFactor.zw;
Result.xy = Result.xy * float2( 2, -2 ) + float2( -1, 1 );
Result.xy = Result.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
#endif
OutHitUVzTime = Result;
OutLevelHCB = log2(OutHitUVzTime.w * RayStepRadiusFactor) + 1;
}
float4 RayCastCheap( Texture2D Texture, SamplerState Sampler, float3 R, float SceneDepth, float3 PositionTranslatedWorld, float StepOffset )
{
// TODO provide RayStartUVz
// NOTE could clip ray against frustum planes
// TODO use screen position and skip matrix mul
float4 RayStartClip = mul( float4( PositionTranslatedWorld, 1 ), View.TranslatedWorldToClip );
float4 RayEndClip = mul( float4( PositionTranslatedWorld + R * SceneDepth, 1 ), View.TranslatedWorldToClip );
float3 RayStartScreen = RayStartClip.xyz / RayStartClip.w;
float3 RayEndScreen = RayEndClip.xyz / RayEndClip.w;
// Normalize 2D length
float3 RayStepScreen = ( RayEndScreen - RayStartScreen ) / length( RayEndScreen.xy - RayStartScreen.xy );
RayStepScreen *= 0.75;
#if USE_HZB
float3 RayStartUVz = float3( RayStartScreen.xy * float2( 0.5, -0.5 ) + 0.5, RayStartScreen.z );
float3 RayStepUVz = float3( RayStepScreen.xy * float2( 0.5, -0.5 ), RayStepScreen.z );
#else
float3 RayStartUVz = float3( RayStartScreen.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz, RayStartScreen.z );
float3 RayStepUVz = float3( RayStepScreen.xy * View.ScreenPositionScaleBias.xy, RayStepScreen.z );
#endif
const float Step = 1.0 / (4 + 1);
// *2 to get less morie pattern in extreme cases, larger values make object appear not grounded in reflections
const float CompareTolerance = abs( RayStepUVz.z ) * Step * 2;
// Vectorized to group fetches
float4 SampleTime = ( StepOffset + float4( 1, 2, 3, 4 ) ) * Step;
float4 SampleUV0 = RayStartUVz.xyxy + RayStepUVz.xyxy * SampleTime.xxyy;
float4 SampleUV1 = RayStartUVz.xyxy + RayStepUVz.xyxy * SampleTime.zzww;
float4 SampleZ = RayStartUVz.zzzz + RayStepUVz.zzzz * SampleTime;
float4 SampleDepth;
#if USE_HZB
SampleDepth.x = Texture2DSampleLevel( Texture, Sampler, SampleUV0.xy, 0 ).r;
SampleDepth.y = Texture2DSampleLevel( Texture, Sampler, SampleUV0.zw, 0 ).r;
SampleDepth.z = Texture2DSampleLevel( Texture, Sampler, SampleUV1.xy, 1 ).r;
SampleDepth.w = Texture2DSampleLevel( Texture, Sampler, SampleUV1.zw, 1 ).r;
#else
SampleDepth.x = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV0.xy, 0 ).r;
SampleDepth.y = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV0.zw, 0 ).r;
SampleDepth.z = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV1.xy, 0 ).r;
SampleDepth.w = Texture2DSampleLevel( SceneDepthTexture, SceneDepthTextureSampler, SampleUV1.zw, 0 ).r;
#endif
#if 1
float4 DepthDiff = SampleZ - SampleDepth;
float4 IntersectTime = ( SampleDepth - RayStartUVz.zzzz ) / RayStepUVz.zzzz;
bool4 Hit = abs( DepthDiff + CompareTolerance ) < CompareTolerance;
// If hit set to intersect time. If missed set to 1, beyond end of ray
float4 HitTime = Hit ? IntersectTime : 1;
// Take closest hit
HitTime.xy = min( HitTime.xy, HitTime.zw );
float MinHitTime = min( HitTime.x, HitTime.y );
#else
// Line segment intersection
float4 DepthDiff1 = SampleZ - SampleDepth;
float4 DepthDiff0 = float4( 0, DepthDiff1.xyz );
float4 TimeLerp = saturate( DepthDiff0 / (DepthDiff0 - DepthDiff1) );
float4 IntersectTime = SampleTime + (TimeLerp - 1) * Step;
bool4 Hit = abs( DepthDiff1 + CompareTolerance ) < CompareTolerance;
// If hit set to intersect time. If missed set to 1, beyond end of ray
float4 HitTime = Hit ? IntersectTime : 1;
// Take closest hit
HitTime.xy = min( HitTime.xy, HitTime.zw );
float MinHitTime = min( HitTime.x, HitTime.y );
#endif
float3 HitUVz = RayStartUVz + RayStepUVz * MinHitTime;
BRANCH
if( MinHitTime == 1 && RayStepUVz.z < 0 )
{
float4 RayInfClip = mul( float4( PositionTranslatedWorld + R * 2000000, 1 ), View.TranslatedWorldToClip );
float3 RayInfScreen = RayInfClip.xyz / RayInfClip.w;
float3 RayInfUVz = float3( RayInfScreen.xy * float2( 0.5, -0.5 ) + 0.5, RayInfScreen.z );
HitUVz = RayInfUVz;
MinHitTime = 0.5;
}
#if USE_HZB
HitUVz.xy = HitUVz.xy = HitUVz.xy * float2( 2, -2 ) + float2( -1, 1 );
HitUVz.xy = HitUVz.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
#endif
return float4( HitUVz, MinHitTime );
}
float4 SampleScreenColor( Texture2D Texture, SamplerState Sampler, float3 HitUVz )
{
float4 OutColor;
#if PREV_FRAME_COLOR
#if 0
// Find previous screen position for hit since color buffer is from last frame
// TODO combine to single matrix
float4 HitClip = float4( (HitUVz.xy - View.ScreenPositionScaleBias.wz) / View.ScreenPositionScaleBias.xy, HitUVz.z, 1 );
float4 HitTranslatedWorld = mul( HitClip, View.ClipToTranslatedWorld );
float4 PrevTranslatedWorld = float4( HitTranslatedWorld.xyz + HitTranslatedWorld.w * (View.PrevPreViewTranslation - View.PreViewTranslation), HitTranslatedWorld.w );
float4 PrevClip = mul( PrevTranslatedWorld, View.PrevTranslatedWorldToClip );
float2 PrevScreen = PrevClip.xy / PrevClip.w;
float2 PrevUV = PrevScreen.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
#else
// Camera motion for pixel (in ScreenPos space).
float4 ThisClip = float4( (HitUVz.xy - View.ScreenPositionScaleBias.wz) / View.ScreenPositionScaleBias.xy, HitUVz.z, 1 );
float4 PrevClip = mul( ThisClip, View.ClipToPrevClip );
float2 PrevScreen = PrevClip.xy / PrevClip.w;
float2 PrevUV = PrevScreen.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
#endif
OutColor.rgb = Texture.SampleLevel( Sampler, PrevUV, 0 ).rgb;
OutColor.a = 1;
// Off screen masking
float2 Vignette = saturate( abs( PrevScreen ) * 5 - 4 );
#else
OutColor.rgb = Texture.SampleLevel( Sampler, HitUVz.xy, 0 ).rgb;
OutColor.a = 1;
// Off screen masking
float2 HitScreenPos = ( HitUVz.xy - View.ScreenPositionScaleBias.wz ) / View.ScreenPositionScaleBias.xy;
float2 Vignette = saturate( abs( HitScreenPos ) * 5 - 4 );
#endif
//PrevScreen sometimes has NaNs or Infs. DX11 is protected because saturate turns NaNs -> 0.
//Do a SafeSaturate so other platforms get the same protection.
OutColor *= SafeSaturate( 1.0 - dot( Vignette, Vignette ) );
// Transform NaNs to black, transform negative colors to black.
OutColor.rgb = -min(-OutColor.rgb, 0.0);
return OutColor;
}
float4 SampleHCBLevel( Texture2D Texture, SamplerState Sampler, float3 HitUVz, float Level )
{
float4 OutColor;
#if PREV_FRAME_COLOR
// Find previous screen position for hit since color buffer is from last frame
// TODO combine to single matrix
float4 HitClip = float4( (HitUVz.xy - View.ScreenPositionScaleBias.wz) / View.ScreenPositionScaleBias.xy, HitUVz.z, 1 );
float4 HitTranslatedWorld = mul( HitClip, View.ClipToTranslatedWorld );
HitTranslatedWorld /= HitTranslatedWorld.w;
float3 PrevTranslatedWorld = HitTranslatedWorld.xyz + (View.PrevPreViewTranslation - View.PreViewTranslation);
float4 PrevClip = mul( float4( PrevTranslatedWorld, 1 ), View.PrevTranslatedWorldToClip );
float2 PrevScreen = PrevClip.xy / PrevClip.w;
float2 PrevUV = PrevScreen.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
OutColor.rgb = Texture.SampleLevel( Sampler, PrevUV * HZBUvFactorAndInvFactor.xy, Level ).rgb;
OutColor.a = 1;
// Off screen masking
float2 Vignette = saturate( abs( PrevScreen ) * 5 - 4 );
#else
OutColor.rgb = Texture.SampleLevel( Sampler, HitUVz.xy * HZBUvFactorAndInvFactor.xy, Level ).rgb;
OutColor.a = 1;
// Off screen masking
float2 HitScreenPos = ( HitUVz.xy - View.ScreenPositionScaleBias.wz ) / View.ScreenPositionScaleBias.xy;
float2 Vignette = saturate( abs( HitScreenPos ) * 5 - 4 );
#endif
//PrevScreen sometimes has NaNs or Infs. DX11 is protected because saturate turns NaNs -> 0.
//Do a SafeSaturate so other platforms get the same protection.
OutColor *= SafeSaturate( 1.0 - dot( Vignette, Vignette ) );
// Transform NaNs to black, transform negative colors to black.
OutColor.rgb = -min(-OutColor.rgb, 0.0);
return OutColor;
}