├── .gitignore ├── Data ├── Deferred.slang ├── Forward.slang ├── ForwardRaytrace.slang ├── GBuffer.slang ├── GBufferUtils.slang ├── Models │ ├── Ground.fbx │ ├── Machines.fbx │ └── Pica.fscene ├── RaytracedAO.slang ├── RaytracedReflection.slang ├── RaytracedShadows.slang ├── SVGFUtils.h ├── SVGF_Atrous.slang ├── SVGF_Reprojection.slang └── SVGF_VarianceEstimation.slang ├── README.md ├── RaysRenderer.cpp ├── RaysRenderer.h ├── RaysRenderer.props ├── RaysRenderer.sln ├── RaysRenderer.vcxproj ├── RaysRenderer.vcxproj.filters ├── SVGFPass.cpp ├── SVGFPass.h ├── Screenshots └── Screenshot.png └── TAA.h /.gitignore: -------------------------------------------------------------------------------- 1 | Bin/* 2 | enc_temp_folder/ 3 | *.user 4 | *.sdf 5 | *.opensdf 6 | *.suo 7 | *.ptx 8 | .vs/* 9 | .vscode/ 10 | *.o 11 | -------------------------------------------------------------------------------- /Data/Deferred.slang: -------------------------------------------------------------------------------- 1 | import Shading; 2 | import GBufferUtils; 3 | 4 | Texture2D gReflectionTexture; 5 | Texture2D gShadowTexture; 6 | Texture2D gAOTexture; 7 | 8 | cbuffer PerImageCB 9 | { 10 | LightData gDirLight; 11 | float gNearFieldGIStrength; 12 | }; 13 | 14 | float4 main(float2 texC : TEXCOORD, float4 pos : SV_POSITION) : SV_TARGET 15 | { 16 | ShadingData sd = LoadGBuffer(pos.xy); 17 | if (sd.opacity <= 0) 18 | { 19 | discard; 20 | } 21 | 22 | float3 color = 0.0; 23 | float shadowFactor = 1.0; 24 | 25 | #if defined(RAYTRACE_SHADOWS) 26 | shadowFactor = gShadowTexture.Load(int3(pos.xy, 0)).r; 27 | #endif 28 | 29 | color = evalMaterial(sd, gLights[0], shadowFactor).color.rgb; 30 | 31 | #if defined(RAYTRACE_REFLECTIONS) 32 | color += gReflectionTexture.Load(int3(pos.xy, 0)).rgb; 33 | #endif 34 | 35 | #if defined(RAYTRACE_AO) 36 | const float ao = gAOTexture.Load(int3(pos.xy, 0)).r; 37 | #if defined(NEAR_FIELD_GI_APPROX) 38 | // Polynomial approximation from "Practical Realtime Strategies for Accurate Indirect Occlusion" 39 | const float3 albedo = sd.diffuse; 40 | const float3 A = 2.0404 * albedo - 0.3324; 41 | const float3 B = 4.7951 * albedo - 0.6417; 42 | const float3 C = 2.7552 * albedo + 0.6903; 43 | const float ao2 = ao * ao; 44 | const float ao3 = ao2 * ao; 45 | const float3 gi = A * ao3 - B * ao2 + C * ao; 46 | color *= lerp(ao.rrr, gi, gNearFieldGIStrength); 47 | #else 48 | color *= ao; 49 | #endif 50 | #endif 51 | 52 | return float4(color, 1.0); 53 | } 54 | -------------------------------------------------------------------------------- /Data/Forward.slang: -------------------------------------------------------------------------------- 1 | import ShaderCommon; 2 | import Shading; 3 | import DefaultVS; 4 | 5 | float4 main(VertexOut vOut) : SV_TARGET 6 | { 7 | ShadingData sd = prepareShadingData(vOut, gMaterial, gCamera.posW); 8 | 9 | ShadingResult sr = evalMaterial(sd, gLights[0], 1); 10 | 11 | float4 color = 0; 12 | color.rgb += sr.color.rgb; 13 | color.rgb += sd.emissive; 14 | color.a = 1; 15 | 16 | return color; 17 | } 18 | -------------------------------------------------------------------------------- /Data/ForwardRaytrace.slang: -------------------------------------------------------------------------------- 1 | import Raytracing; 2 | import Shading; 3 | import BRDF; 4 | import Helpers; 5 | #include "HostDeviceSharedMacros.h" 6 | 7 | shared cbuffer PerFrameCB 8 | { 9 | float4x4 invView; 10 | float4x4 invModel; 11 | float2 viewportDims; 12 | float tanHalfFovY; 13 | uint gFrameCount; 14 | }; 15 | 16 | [shader("raygeneration")] 17 | void RayGen() 18 | { 19 | uint3 launchIndex = DispatchRaysIndex(); 20 | uint2 launchDim = DispatchRaysDimensions().xy; 21 | 22 | float2 d = (((launchIndex.xy + 0.5) / viewportDims) * 2.f - 1.f); 23 | float aspectRatio = viewportDims.x / viewportDims.y; 24 | float3 viewDirection = normalize((d.x * invView[0].xyz * tanHalfFovY * aspectRatio) - (d.y * invView[1].xyz * tanHalfFovY) - invView[2].xyz); 25 | } 26 | -------------------------------------------------------------------------------- /Data/GBuffer.slang: -------------------------------------------------------------------------------- 1 | import ShaderCommon; 2 | import Shading; 3 | import DefaultVS; 4 | 5 | cbuffer PerFrameCB 6 | { 7 | float2 gRenderTargetDim; 8 | }; 9 | 10 | struct GBuffer 11 | { 12 | float4 position : SV_TARGET0; 13 | float4 normal : SV_TARGET1; 14 | float4 albedo : SV_TARGET2; 15 | float4 motion : SV_TARGET3; // .rg motion vector, .b position derivative, .a normal derivative 16 | float4 linearZ : SV_TARGET4; // .r linear Z, .g max Z derivative, .b last frame Z, .a obj space normal 17 | float4 compactNormDepth : SV_TARGET5; // .r world normal, .g linear Z, .b Z derivative 18 | }; 19 | 20 | // A simple utility to convert a float to a 2-component octohedral representation packed into one uint 21 | uint DirToOct(float3 normal) 22 | { 23 | float2 p = normal.xy * (1.0 / dot(abs(normal), 1.0.xxx)); 24 | float2 e = normal.z > 0.0 ? p : (1.0 - abs(p.yx)) * (step(0.0,p)*2.0-(float2)(1.0)); 25 | return (asuint(f32tof16(e.y)) << 16) + (asuint(f32tof16(e.x))); 26 | } 27 | 28 | GBuffer main(VertexOut vOut, float4 pixelCrd : SV_POSITION) 29 | { 30 | ShadingData sd = prepareShadingData(vOut, gMaterial, gCamera.posW); 31 | 32 | // The 'linearZ' buffer 33 | float linearZ = vOut.posH.z * vOut.posH.w; 34 | #ifdef FALCOR_VK 35 | float prevZBuf = vOut.prevPosH.z / vOut.prevPosH.w; 36 | float prevLinearZ = prevZBuf / vOut.prevPosH.w; 37 | #else 38 | float prevLinearZ = vOut.prevPosH.z; 39 | #endif 40 | float maxChangeZ = max(abs(ddx(linearZ)), abs(ddy(linearZ))); 41 | float objNorm = asfloat(DirToOct(normalize(vOut.normalW))); // world normal instead of object normal 42 | float4 svgfLinearZOut = float4(linearZ, maxChangeZ, prevLinearZ, objNorm); 43 | 44 | // The 'motion vector' buffer 45 | float2 jitter = float2(gCamera.jitterX, gCamera.jitterY); 46 | #ifdef FALCOR_D3D 47 | jitter.y *= -1; 48 | #endif 49 | float2 svgfMotionVec = calcMotionVector(pixelCrd.xy, vOut.prevPosH, gRenderTargetDim) + jitter; 50 | float2 posNormFWidth = float2(length(fwidth(sd.posW)), length(fwidth(sd.N))); 51 | float4 svgfMotionVecOut = float4(svgfMotionVec, posNormFWidth); 52 | 53 | GBuffer out; 54 | out.position = float4(sd.posW, 1.0); 55 | out.normal = float4(sd.N, sd.linearRoughness); 56 | out.albedo = float4(sd.diffuse, sd.opacity); 57 | out.motion = svgfMotionVecOut; 58 | out.linearZ = svgfLinearZOut; 59 | 60 | // A compacted buffer containing discretizied normal, depth, depth derivative 61 | out.compactNormDepth = float4(asfloat(DirToOct(sd.N)), linearZ, maxChangeZ, 0.0f); 62 | 63 | return out; 64 | } 65 | -------------------------------------------------------------------------------- /Data/GBufferUtils.slang: -------------------------------------------------------------------------------- 1 | import Shading; 2 | 3 | shared Texture2D gGBuf0; // WorldPosition 4 | shared Texture2D gGBuf1; // NormalRoughness 5 | shared Texture2D gGBuf2; // Albedo 6 | shared Texture2D gGBuf3; // MotionVector, unused 7 | 8 | ShadingData LoadGBuffer(float2 pos) 9 | { 10 | float3 posW = gGBuf0.Load(int3(pos.xy, 0)).rgb; 11 | float4 buf1Val = gGBuf1.Load(int3(pos.xy, 0)); 12 | float3 normalW = buf1Val.rgb; 13 | float linearRoughness = buf1Val.a; 14 | float4 albedo = gGBuf2.Load(int3(pos.xy, 0)); 15 | 16 | ShadingData sd = initShadingData(); 17 | sd.posW = posW; 18 | sd.V = normalize(gCamera.posW - posW); 19 | sd.N = normalW; 20 | sd.NdotV = abs(dot(sd.V, sd.N)); 21 | sd.linearRoughness = max(0.08, linearRoughness); // Clamp the roughness so that the BRDF won't explode 22 | sd.roughness = sd.linearRoughness * sd.linearRoughness; 23 | sd.diffuse = albedo.rgb; 24 | sd.specular = float3(0.04); // TODO: handle metalness 25 | sd.opacity = albedo.a; 26 | 27 | return sd; 28 | } 29 | -------------------------------------------------------------------------------- /Data/Models/Ground.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philcn/RaysRenderer/1d431bb6c6270b8918f6510b9e65457424fb8e03/Data/Models/Ground.fbx -------------------------------------------------------------------------------- /Data/Models/Machines.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philcn/RaysRenderer/1d431bb6c6270b8918f6510b9e65457424fb8e03/Data/Models/Machines.fbx -------------------------------------------------------------------------------- /Data/Models/Pica.fscene: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "scene_unit": 1.0, 4 | "camera_speed": 10.0, 5 | "lighting_scale": 1.0, 6 | "models": [ 7 | { 8 | "file": "D:\\Projects\\Falcor\\Media\\Pica\\Machines.fbx", 9 | "name": "Machines", 10 | "material": { 11 | "shading_model": "metal_rough" 12 | }, 13 | "instances": [ 14 | { 15 | "name": "Machines0", 16 | "translation": [ 17 | 0.0, 18 | 0.0, 19 | 0.0 20 | ], 21 | "scaling": [ 22 | 1.0, 23 | 1.0, 24 | 1.0 25 | ], 26 | "rotation": [ 27 | 0.0, 28 | -0.0, 29 | -0.0 30 | ] 31 | } 32 | ] 33 | }, 34 | { 35 | "file": "D:\\Projects\\Falcor\\Media\\Pica\\Ground.fbx", 36 | "name": "Ground", 37 | "material": { 38 | "shading_model": "metal_rough" 39 | }, 40 | "instances": [ 41 | { 42 | "name": "Ground0", 43 | "translation": [ 44 | 0.0, 45 | 0.0, 46 | 0.0 47 | ], 48 | "scaling": [ 49 | 0.20000000298023225, 50 | 0.20000000298023225, 51 | 0.20000000298023225 52 | ], 53 | "rotation": [ 54 | 0.0, 55 | -0.0, 56 | -0.0 57 | ] 58 | } 59 | ] 60 | } 61 | ], 62 | "lights": [ 63 | { 64 | "name": "DirLight0", 65 | "type": "dir_light", 66 | "intensity": [ 67 | 1.2000000476837159, 68 | 1.2000000476837159, 69 | 1.2000000476837159 70 | ], 71 | "direction": [ 72 | -0.1889593005180359, 73 | -0.741632342338562, 74 | -0.6436427235603333 75 | ] 76 | } 77 | ] 78 | } -------------------------------------------------------------------------------- /Data/RaytracedAO.slang: -------------------------------------------------------------------------------- 1 | import Raytracing; 2 | import Helpers; 3 | #include "HostDeviceSharedMacros.h" 4 | 5 | shared cbuffer PerFrameCB 6 | { 7 | uint gFrameCount; 8 | float gAODistance; 9 | }; 10 | 11 | shared Texture2D gGBuf0; 12 | shared Texture2D gGBuf1; 13 | 14 | shared RWTexture2D gOutput; 15 | 16 | struct AORayData 17 | { 18 | bool hit; 19 | }; 20 | 21 | [shader("raygeneration")] 22 | void RayGen() 23 | { 24 | uint3 launchIndex = DispatchRaysIndex(); 25 | uint2 launchDim = DispatchRaysDimensions().xy; 26 | 27 | float3 posW = gGBuf0.Load(int3(launchIndex.xy, 0)).rgb; 28 | float3 normalW = gGBuf1.Load(int3(launchIndex.xy, 0)).rgb; 29 | 30 | uint randSeed = rand_init(launchIndex.x + launchIndex.y * launchDim.x, gFrameCount, 16); 31 | float2 randVal = float2(rand_next(randSeed), rand_next(randSeed)); 32 | 33 | float3 direction = getCosHemisphereSample(randVal, normalW, getPerpendicularStark(normalW)); 34 | 35 | RayDesc ray; 36 | ray.Origin = posW; 37 | ray.Direction = normalize(direction); 38 | ray.TMin = 0.01; 39 | ray.TMax = max(0.01, gAODistance); 40 | 41 | AORayData payload; 42 | payload.hit = true; 43 | 44 | TraceRay(gRtScene, RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH, 0xFF, 0, hitProgramCount, 0, ray, payload); 45 | gOutput[launchIndex.xy] = payload.hit ? 0.0f : 1.0f; 46 | } 47 | 48 | [shader("miss")] 49 | void PrimaryMiss(inout AORayData hitData) 50 | { 51 | hitData.hit = false; 52 | } 53 | 54 | [shader("anyhit")] 55 | void PrimaryAHS(inout AORayData hitData, in BuiltInTriangleIntersectionAttributes attribs) 56 | { 57 | hitData.hit = true; 58 | } 59 | -------------------------------------------------------------------------------- /Data/RaytracedReflection.slang: -------------------------------------------------------------------------------- 1 | import Raytracing; 2 | import Shading; 3 | import BRDF; 4 | import Helpers; 5 | import GBufferUtils; 6 | #include "HostDeviceSharedMacros.h" 7 | 8 | shared cbuffer PerFrameCB 9 | { 10 | uint gFrameCount; 11 | }; 12 | 13 | shared RWTexture2D gOutput; 14 | 15 | struct ReflectionRayData 16 | { 17 | float4 color; 18 | uint depth; 19 | float hitT; 20 | uint randSeed; 21 | }; 22 | 23 | struct ShadowRayData 24 | { 25 | bool hit; 26 | }; 27 | 28 | [shader("raygeneration")] 29 | void RayGen() 30 | { 31 | uint3 launchIndex = DispatchRaysIndex(); 32 | uint2 launchDim = DispatchRaysDimensions().xy; 33 | 34 | uint randSeed = rand_init(launchIndex.x + launchIndex.y * launchDim.x, gFrameCount, 16); 35 | ShadingData sd = LoadGBuffer(launchIndex.xy); 36 | 37 | float3 reflectColor = TraceReflectionRay(sd, 0, randSeed); 38 | bool colorsNan = any(isnan(reflectColor)); 39 | 40 | gOutput[launchIndex.xy] = float4(colorsNan ? float3(0.0) : reflectColor, 1.0); 41 | } 42 | 43 | bool TraceShadowRay(uint lightIndex, float3 origin) 44 | { 45 | LightData light = gLights[lightIndex]; 46 | float3 direction; 47 | float maxT; 48 | 49 | if (light.type == LightPoint) 50 | { 51 | direction = light.posW - origin; 52 | maxT = length(direction); 53 | } 54 | else if (light.type == LightDirectional) 55 | { 56 | direction = -light.dirW; 57 | maxT = 1000.0; 58 | } 59 | 60 | RayDesc ray; 61 | ray.Origin = origin; 62 | ray.Direction = normalize(direction); 63 | ray.TMin = 0.001; 64 | ray.TMax = max(0.01, maxT); 65 | 66 | ShadowRayData rayData; 67 | rayData.hit = true; 68 | TraceRay(gRtScene, RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH, 0xFF, 1, hitProgramCount, 1, ray, rayData); 69 | return rayData.hit; 70 | } 71 | 72 | float3 TraceReflectionRay(ShadingData sd, uint rayDepth, uint randSeed) 73 | { 74 | float2 randVal = float2(rand_next(randSeed), rand_next(randSeed)); 75 | float3 H = getGGXMicrofacet(randVal, sd.N, sd.roughness); 76 | float3 L = reflect(-sd.V, H); 77 | 78 | RayDesc ray; 79 | ray.Origin = sd.posW; 80 | ray.Direction = L; 81 | ray.TMin = 0.001; 82 | ray.TMax = 100000; 83 | 84 | ReflectionRayData payload; 85 | payload.depth = rayDepth + 1; 86 | payload.randSeed = randSeed; 87 | 88 | TraceRay(gRtScene, 0, 0xFF, 0, hitProgramCount, 0, ray, payload); 89 | 90 | float NdotL = saturate(dot(sd.N, L)); 91 | float NdotV = saturate(dot(sd.N, sd.V)); 92 | float NdotH = saturate(dot(sd.N, H)); 93 | float LdotH = saturate(dot(L, H)); 94 | 95 | float D = evalGGX(sd.roughness, NdotH) * M_INV_PI; // Our GGX function does not include division by PI 96 | float G = evalSmithGGX(NdotL, NdotV, sd.roughness); // Includes division by 4 * NdotL * NdotV 97 | float3 F = fresnelSchlick(sd.specular, 1, max(0, LdotH)); 98 | float3 brdf = D * G * F; 99 | float ggxProb = D * NdotH / (4 * LdotH); 100 | 101 | return payload.color.rgb * NdotL * brdf / ggxProb; 102 | } 103 | 104 | [shader("closesthit")] 105 | void PrimaryCHS(inout ReflectionRayData hitData, in BuiltInTriangleIntersectionAttributes attribs) 106 | { 107 | float3 rayOrigW = WorldRayOrigin(); 108 | float3 rayDirW = WorldRayDirection(); 109 | float hitT = RayTCurrent(); 110 | float3 posW = rayOrigW + hitT * rayDirW; 111 | 112 | VertexOut v = getVertexAttributes(PrimitiveIndex(), attribs); 113 | ShadingData sd = prepareShadingData(v, gMaterial, rayOrigW, 0); 114 | 115 | float3 color = 0.0; 116 | 117 | [unroll] 118 | for (int i = 0; i < gLightsCount; i++) 119 | { 120 | if (TraceShadowRay(i, posW) == false) 121 | { 122 | color += evalMaterial(sd, gLights[i], 1.0).color.rgb; 123 | } 124 | } 125 | 126 | if (hitData.depth < 2) // perform 2nd bounce 127 | { 128 | color += TraceReflectionRay(sd, hitData.depth, hitData.randSeed); 129 | } 130 | 131 | hitData.hitT = hitT; 132 | hitData.color.rgb = color; 133 | hitData.color.a = 1; 134 | } 135 | 136 | [shader("miss")] 137 | void PrimaryMiss(inout ReflectionRayData hitData) 138 | { 139 | hitData.color = float4(0.2, 0.6, 0.9, 1.0); 140 | hitData.hitT = -1; 141 | } 142 | 143 | [shader("miss")] 144 | void ShadowMiss(inout ShadowRayData hitData) 145 | { 146 | hitData.hit = false; 147 | } 148 | 149 | [shader("anyhit")] 150 | void ShadowAHS(inout ShadowRayData hitData, in BuiltInTriangleIntersectionAttributes attribs) 151 | { 152 | hitData.hit = true; 153 | } 154 | -------------------------------------------------------------------------------- /Data/RaytracedShadows.slang: -------------------------------------------------------------------------------- 1 | import Raytracing; 2 | import Helpers; 3 | #include "HostDeviceSharedMacros.h" 4 | 5 | shared cbuffer PerFrameCB 6 | { 7 | uint gFrameCount; 8 | }; 9 | 10 | shared Texture2D gGBuf0; 11 | 12 | shared RWTexture2D gOutput; 13 | 14 | struct ShadowRayData 15 | { 16 | bool hit; 17 | }; 18 | 19 | float3 SampleLightCone(float2 u, float3 N, float spread) 20 | { 21 | float3 T = getPerpendicularStark(N); 22 | float3 B = normalize(cross(N, T)); 23 | 24 | u.x *= spread; 25 | 26 | float r = sqrt(u.x); 27 | float phi = u.y * M_PI2; 28 | float3 L = float3(r * cos(phi), r * sin(phi), sqrt(max(0.0f, 1.0f - u.x))); 29 | 30 | return normalize(T * L.x + B * L.y + N * L.z); 31 | } 32 | 33 | [shader("raygeneration")] 34 | void RayGen() 35 | { 36 | uint3 launchIndex = DispatchRaysIndex(); 37 | uint2 launchDim = DispatchRaysDimensions().xy; 38 | 39 | uint randSeed = rand_init(launchIndex.x + launchIndex.y * launchDim.x, gFrameCount, 16); 40 | float2 randVal = float2(rand_next(randSeed), rand_next(randSeed)); 41 | 42 | float3 posW = gGBuf0.Load(int3(launchIndex.xy, 0)).rgb; 43 | 44 | LightData light = gLights[0]; 45 | float3 direction; 46 | float maxT; 47 | 48 | if (light.type == LightPoint) 49 | { 50 | direction = light.posW - posW; 51 | maxT = length(direction); 52 | } 53 | else if (light.type == LightDirectional) 54 | { 55 | direction = -light.dirW; 56 | maxT = 1000.0; 57 | } 58 | 59 | direction = SampleLightCone(randVal, direction, 0.02); 60 | 61 | RayDesc ray; 62 | ray.Origin = posW; 63 | ray.Direction = normalize(direction); 64 | ray.TMin = 0.01; 65 | ray.TMax = max(0.01, maxT); 66 | 67 | ShadowRayData payload; 68 | payload.hit = true; 69 | 70 | TraceRay(gRtScene, RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH, 0xFF, 0, hitProgramCount, 0, ray, payload); 71 | gOutput[launchIndex.xy] = payload.hit ? 0.0f : 1.0f; 72 | } 73 | 74 | [shader("miss")] 75 | void PrimaryMiss(inout ShadowRayData hitData) 76 | { 77 | hitData.hit = false; 78 | } 79 | 80 | [shader("anyhit")] 81 | void PrimaryAHS(inout ShadowRayData hitData, in BuiltInTriangleIntersectionAttributes attribs) 82 | { 83 | hitData.hit = true; 84 | } 85 | -------------------------------------------------------------------------------- /Data/SVGFUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef SVGF_UTILS_H 2 | #define SVGF_UTILS_H 3 | 4 | #include "HostDeviceSharedCode.h" 5 | 6 | int2 GetTextureDims(Texture2D tex, uint mip) 7 | { 8 | uint w, h; 9 | tex.GetDimensions(w, h); 10 | return int2(w, h); 11 | } 12 | 13 | float3 OctToDir(uint octo) 14 | { 15 | float2 e = float2(f16tof32(octo & 0xFFFF), f16tof32((octo >> 16) & 0xFFFF)); 16 | float3 v = float3(e, 1.0 - abs(e.x) - abs(e.y)); 17 | if (v.z < 0.0) 18 | v.xy = (1.0 - abs(v.yx)) * (step(0.0, v.xy) * 2.0 - (float2)(1.0)); 19 | return normalize(v); 20 | } 21 | 22 | uint DirToOct(float3 normal) 23 | { 24 | float2 p = normal.xy * (1.0 / dot(abs(normal), 1.0.xxx)); 25 | float2 e = normal.z > 0.0 ? p : (1.0 - abs(p.yx)) * (step(0.0, p) * 2.0 - (float2)(1.0)); 26 | return (asuint(f32tof16(e.y)) << 16) + (asuint(f32tof16(e.x))); 27 | } 28 | 29 | struct SVGFSample 30 | { 31 | float3 signal; float variance; 32 | float3 normal; float linearZ; 33 | float zDerivative; 34 | float luminance; 35 | }; 36 | 37 | SVGFSample FetchSignalSample(Texture2D signalTexture, Texture2D ndTexture, int2 ipos) 38 | { 39 | const float4 signal = signalTexture.Load(int3(ipos, 0)); 40 | const float4 nd = ndTexture.Load(int3(ipos, 0)); 41 | 42 | SVGFSample s; 43 | s.signal = signal.rgb; 44 | s.variance = signal.a; 45 | s.normal = normalize(OctToDir(asuint(nd.x))); 46 | s.linearZ = nd.y; 47 | s.zDerivative = nd.z; 48 | s.luminance = luminance(s.signal); 49 | 50 | return s; 51 | } 52 | 53 | float NormalDistanceCos(float3 n1, float3 n2, float power) 54 | { 55 | return pow(saturate(dot(n1, n2)), power); 56 | } 57 | 58 | float ComputeWeight(SVGFSample sampleCenter, SVGFSample sampleP, float phiDepth, float phiNormal, float phiColor) 59 | { 60 | const float wNormal = NormalDistanceCos(sampleCenter.normal, sampleP.normal, phiNormal); 61 | const float wZ = (phiDepth == 0) ? 0.0f : abs(sampleCenter.linearZ - sampleP.linearZ) / phiDepth; 62 | const float wLdirect = abs(sampleCenter.luminance - sampleP.luminance) / phiColor; 63 | 64 | return exp(0.0 - max(wLdirect, 0.0) - max(wZ, 0.0)) * wNormal; 65 | } 66 | 67 | #define COMPARE_FUNC2(TYPE) \ 68 | bool2 equal(TYPE a, TYPE b) { return bool2(a.x == b.x, a.y == b.y); } \ 69 | bool2 notEqual(TYPE a, TYPE b) { return bool2(a.x != b.x, a.y != b.y); } \ 70 | bool2 lessThan(TYPE a, TYPE b) { return bool2(a.x < b.x, a.y < b.y); } \ 71 | bool2 greaterThan(TYPE a, TYPE b) { return bool2(a.x > b.x, a.y > b.y); } \ 72 | bool2 lessThanEqual(TYPE a, TYPE b) { return bool2(a.x <= b.x, a.y <= b.y); } \ 73 | bool2 greaterThanEqual(TYPE a, TYPE b) { return bool2(a.x >= b.x, a.y >= b.y); } 74 | 75 | COMPARE_FUNC2(int2) 76 | COMPARE_FUNC2(float2) 77 | 78 | #undef COMPARE_FUNC2 79 | 80 | #define COMPARE_FUNC3(TYPE) \ 81 | bool3 equal(TYPE a, TYPE b) { return bool3(a.x == b.x, a.y == b.y, a.z == b.z); } \ 82 | bool3 notEqual(TYPE a, TYPE b) { return bool3(a.x != b.x, a.y != b.y, a.z != b.z); } \ 83 | bool3 lessThan(TYPE a, TYPE b) { return bool3(a.x < b.x, a.y < b.y, a.z < b.z); } \ 84 | bool3 greaterThan(TYPE a, TYPE b) { return bool3(a.x > b.x, a.y > b.y, a.z > b.z); } \ 85 | bool3 lessThanEqual(TYPE a, TYPE b) { return bool3(a.x <= b.x, a.y <= b.y, a.z <= b.z); } \ 86 | bool3 greaterThanEqual(TYPE a, TYPE b) { return bool3(a.x >= b.x, a.y >= b.y, a.z >= b.z); } 87 | 88 | COMPARE_FUNC3(int3) 89 | COMPARE_FUNC3(float3) 90 | 91 | #undef COMPARE_FUNC3 92 | 93 | #define COMPARE_FUNC4(TYPE) \ 94 | bool4 equal(TYPE a, TYPE b) { return bool4(a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w); } \ 95 | bool4 notEqual(TYPE a, TYPE b) { return bool4(a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w); } \ 96 | bool4 lessThan(TYPE a, TYPE b) { return bool4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w); } \ 97 | bool4 greaterThan(TYPE a, TYPE b) { return bool4(a.x > b.x, a.y > b.y, a.z > b.z, a.w > b.w); } \ 98 | bool4 lessThanEqual(TYPE a, TYPE b) { return bool4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w); } \ 99 | bool4 greaterThanEqual(TYPE a, TYPE b) { return bool4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w); } 100 | 101 | COMPARE_FUNC4(int4) 102 | COMPARE_FUNC4(float4) 103 | 104 | #undef COMPARE_FUNC4 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /Data/SVGF_Atrous.slang: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************** 2 | # Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 5 | # following conditions are met: 6 | # * Redistributions of code must retain the copyright notice, this list of conditions and the following disclaimer. 7 | # * Neither the name of NVIDIA CORPORATION nor the names of its contributors may be used to endorse or promote products 8 | # derived from this software without specific prior written permission. 9 | # 10 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 11 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 12 | # SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 13 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 14 | # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 16 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17 | **********************************************************************************************************************/ 18 | 19 | #include "SVGFUtils.h" 20 | #include "HostDeviceSharedCode.h" 21 | 22 | cbuffer PerPassCB 23 | { 24 | uint gStepSize; 25 | float gPhiColor; 26 | float gPhiNormal; 27 | }; 28 | 29 | Texture2D gCompactNormDepth; 30 | Texture2D gInputSignal; 31 | 32 | struct PsOut 33 | { 34 | float4 signal : SV_TARGET0; 35 | }; 36 | 37 | float ComputeVarianceCenter(int2 ipos, Texture2D signalTexture) 38 | { 39 | const float kernel[2][2] = 40 | { 41 | { 1.0 / 4.0, 1.0 / 8.0 }, 42 | { 1.0 / 8.0, 1.0 / 16.0 } 43 | }; 44 | 45 | float sum = 0.0; 46 | const int radius = 1; 47 | for (int yy = -radius; yy <= radius; ++yy) 48 | { 49 | for (int xx = -radius; xx <= radius; ++xx) 50 | { 51 | int2 p = ipos + int2(xx, yy); 52 | float k = kernel[abs(xx)][abs(yy)]; 53 | sum += signalTexture[p].a * k; 54 | } 55 | } 56 | 57 | return sum; 58 | } 59 | 60 | PsOut main(float2 texC : TEXCOORD, float4 pos : SV_POSITION) 61 | { 62 | const int2 ipos = int2(pos.xy); 63 | const int2 screenSize = GetTextureDims(gInputSignal, 0); 64 | 65 | SVGFSample sampleCenter = FetchSignalSample(gInputSignal, gCompactNormDepth, ipos); 66 | 67 | if (sampleCenter.linearZ < 0) // not valid depth, must be skybox 68 | { 69 | PsOut out; 70 | out.signal = float4(sampleCenter.signal, sampleCenter.variance); 71 | return out; 72 | } 73 | 74 | const float epsVariance = 1e-10; 75 | const float kernelWeights[3] = { 1.0, 2.0 / 3.0, 1.0 / 6.0 }; 76 | const float variance = ComputeVarianceCenter(ipos, gInputSignal); 77 | const float phiColor = gPhiColor * sqrt(max(0.0, epsVariance + variance)); 78 | const float phiDepth = max(sampleCenter.zDerivative, 1e-8) * gStepSize; 79 | 80 | float sumWeight = 1.0; 81 | float3 sumSignal = sampleCenter.signal; 82 | float sumVariance = sampleCenter.variance; 83 | 84 | const int radius = ATROUS_RADIUS; // 2 85 | for (int yy = -radius; yy <= radius; ++yy) 86 | { 87 | for (int xx = -radius; xx <= radius; ++xx) 88 | { 89 | const int2 p = ipos + int2(xx, yy) * gStepSize; 90 | const bool inside = all(greaterThanEqual(p, int2(0, 0))) && all(lessThan(p, screenSize)); 91 | 92 | if (inside && (xx != 0 || yy != 0)) 93 | { 94 | SVGFSample sampleP = FetchSignalSample(gInputSignal, gCompactNormDepth, p); 95 | 96 | const float edgeStopping = ComputeWeight(sampleCenter, sampleP, phiDepth * length(float2(xx, yy)), gPhiNormal, phiColor); 97 | const float kernel = kernelWeights[abs(xx)] * kernelWeights[abs(yy)]; 98 | const float weight = edgeStopping * kernel; 99 | 100 | sumWeight += weight; 101 | sumSignal += sampleP.signal * weight; 102 | sumVariance += sampleP.variance * weight * weight; 103 | } 104 | } 105 | } 106 | 107 | PsOut out; 108 | out.signal = float4(sumSignal / sumWeight, sumVariance / (sumWeight * sumWeight)); 109 | 110 | return out; 111 | } 112 | -------------------------------------------------------------------------------- /Data/SVGF_Reprojection.slang: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************** 2 | # Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 5 | # following conditions are met: 6 | # * Redistributions of code must retain the copyright notice, this list of conditions and the following disclaimer. 7 | # * Neither the name of NVIDIA CORPORATION nor the names of its contributors may be used to endorse or promote products 8 | # derived from this software without specific prior written permission. 9 | # 10 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 11 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 12 | # SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 13 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 14 | # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 16 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17 | **********************************************************************************************************************/ 18 | 19 | #include "SVGFUtils.h" 20 | 21 | cbuffer PerPassCB 22 | { 23 | float gAlpha; 24 | float gMomentsAlpha; 25 | bool gEnableTemporalReprojection; 26 | }; 27 | 28 | Texture2D gInputSignal; 29 | Texture2D gLinearZ; 30 | Texture2D gMotion; 31 | Texture2D gPrevLinearZ; 32 | Texture2D gPrevInputSignal; 33 | Texture2D gPrevMoments; 34 | Texture2D gHistoryLength; 35 | 36 | struct PsOut 37 | { 38 | float4 signal : SV_TARGET0; 39 | float2 moments : SV_TARGET1; 40 | float historyLength : SV_TARGET2; 41 | }; 42 | 43 | bool IsReprjValid(int2 coord, float Z, float Zprev, float zDeriv, float3 normal, float3 normalPrev, float normalDeriv) 44 | { 45 | const int2 imageDim = GetTextureDims(gInputSignal, 0); 46 | 47 | // check whether reprojected pixel is inside of the screen 48 | if (any(lessThan(coord, int2(1, 1))) || any(greaterThan(coord, imageDim - int2(1, 1)))) return false; 49 | 50 | // check if deviation of depths is acceptable 51 | if (abs(Zprev - Z) / (zDeriv + 1e-4) > 2.0) return false; 52 | 53 | // check normals for compatibility 54 | if (distance(normal, normalPrev) / (normalDeriv + 1e-2) > 16.0) return false; 55 | 56 | return true; 57 | } 58 | 59 | bool ReprojectLastFilteredData(float2 fragCoord, out float3 prevSignal, out float2 prevMoments, out float historyLength) 60 | { 61 | const int2 ipos = fragCoord; 62 | const float2 imageDim = float2(GetTextureDims(gInputSignal, 0)); 63 | 64 | // .xy motion, .z position derivative (unused), .w normal derivative 65 | const float4 motion = gMotion[ipos]; 66 | 67 | // .x Z, .y Z derivative, .z last frame Z, .w world normal 68 | const float4 depth = gLinearZ[ipos]; 69 | const float3 normal = OctToDir(asuint(depth.w)); 70 | 71 | const int2 iposPrev = int2(float2(ipos) + motion.xy * imageDim + float2(0.5, 0.5)); 72 | const float2 posPrev = floor(fragCoord.xy) + motion.xy * imageDim; 73 | 74 | prevSignal = 0.0; 75 | prevMoments = 0.0; 76 | historyLength = gHistoryLength[iposPrev].r; 77 | 78 | bool v[4]; 79 | const int2 offset[4] = { int2(0, 0), int2(1, 0), int2(0, 1), int2(1, 1) }; 80 | 81 | // Check for all 4 taps of the bilinear filter for validity 82 | bool valid = false; 83 | for (int sampleIdx = 0; sampleIdx < 4; ++sampleIdx) 84 | { 85 | const int2 loc = int2(posPrev) + offset[sampleIdx]; 86 | const float4 depthPrev = gPrevLinearZ[loc]; 87 | const float3 normalPrev = OctToDir(asuint(depthPrev.w)); 88 | 89 | v[sampleIdx] = IsReprjValid(iposPrev, depth.z, depthPrev.x, depth.y, normal, normalPrev, motion.w); 90 | 91 | valid = valid || v[sampleIdx]; 92 | } 93 | 94 | // Perform bilinear interpolation 95 | if (valid) 96 | { 97 | float sumWeights = 0.0; 98 | const float x = frac(posPrev.x); 99 | const float y = frac(posPrev.y); 100 | 101 | const float w[4] = { (1 - x) * (1 - y), 102 | x * (1 - y), 103 | (1 - x) * y, 104 | x * y }; 105 | 106 | for (int sampleIdx = 0; sampleIdx < 4; ++sampleIdx) 107 | { 108 | if (v[sampleIdx]) 109 | { 110 | const int2 loc = int2(posPrev) + offset[sampleIdx]; 111 | prevSignal += w[sampleIdx] * gPrevInputSignal[loc].rgb; 112 | prevMoments += w[sampleIdx] * gPrevMoments[loc].rg; 113 | sumWeights += w[sampleIdx]; 114 | } 115 | } 116 | 117 | // Redistribute weights in case not all taps were used 118 | valid = (sumWeights >= 0.01); 119 | prevSignal = valid ? prevSignal / sumWeights : 0.0; 120 | prevMoments = valid ? prevMoments / sumWeights : 0.0; 121 | } 122 | 123 | // Perform a cross-bilateral filter with binary decision to find some suitable samples spatially 124 | if (!valid) 125 | { 126 | float cnt = 0.0; 127 | const int radius = 1; 128 | for (int yy = -radius; yy <= radius; ++yy) 129 | { 130 | for (int xx = -radius; xx <= radius; ++xx) 131 | { 132 | int2 p = iposPrev + int2(xx, yy); 133 | float4 depthP = gPrevLinearZ[p]; 134 | float3 normalP = OctToDir(asuint(depthP.w)); 135 | 136 | if (IsReprjValid(iposPrev, depth.z, depthP.x, depth.y, normal, normalP, motion.w)) 137 | { 138 | prevSignal += gPrevInputSignal[p].rgb; 139 | prevMoments += gPrevMoments[p].rg; 140 | cnt += 1.0; 141 | } 142 | } 143 | } 144 | 145 | if (cnt > 0.0) 146 | { 147 | valid = true; 148 | prevSignal /= cnt; 149 | prevMoments /= cnt; 150 | } 151 | } 152 | 153 | if (!valid) 154 | { 155 | prevSignal = 0.0; 156 | prevMoments = 0.0; 157 | historyLength = 0.0; 158 | } 159 | 160 | return valid; 161 | } 162 | 163 | PsOut main(float2 texC : TEXCOORD, float4 pos : SV_POSITION) 164 | { 165 | const float3 signal = gInputSignal[pos.xy].rgb; 166 | 167 | if (!gEnableTemporalReprojection) 168 | { 169 | PsOut out; 170 | out.signal = float4(signal, 1.0); // Performs uniform bilateral filter with variance = 1.0 171 | out.moments = 0.0; 172 | out.historyLength = 1.0; 173 | return out; 174 | } 175 | 176 | float historyLength; 177 | float3 prevSignal; 178 | float2 prevMoments; 179 | bool success = ReprojectLastFilteredData(pos.xy, prevSignal, prevMoments, historyLength); 180 | 181 | historyLength = min(32.0f, success ? historyLength + 1.0f : 1.0f); 182 | 183 | // This adjusts the alpha for the case where insufficient history is available. 184 | // It boosts the temporal accumulation to give the samples equal weights in the beginning. 185 | const float alpha = success ? max(gAlpha, 1.0 / historyLength) : 1.0; 186 | const float alphaMoments = success ? max(gMomentsAlpha, 1.0 / historyLength) : 1.0; 187 | 188 | float2 moments; 189 | moments.r = luminance(signal); 190 | moments.g = moments.r * moments.r; 191 | moments = lerp(prevMoments, moments, alphaMoments); 192 | 193 | PsOut out; 194 | out.signal.rgb = lerp(prevSignal, signal, alpha); 195 | out.signal.a = max(0.0, moments.g - moments.r * moments.r); 196 | out.moments = moments; 197 | out.historyLength = historyLength; 198 | 199 | return out; 200 | } 201 | -------------------------------------------------------------------------------- /Data/SVGF_VarianceEstimation.slang: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************** 2 | # Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 5 | # following conditions are met: 6 | # * Redistributions of code must retain the copyright notice, this list of conditions and the following disclaimer. 7 | # * Neither the name of NVIDIA CORPORATION nor the names of its contributors may be used to endorse or promote products 8 | # derived from this software without specific prior written permission. 9 | # 10 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 11 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 12 | # SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 13 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 14 | # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 16 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17 | **********************************************************************************************************************/ 18 | 19 | #include "SVGFUtils.h" 20 | 21 | cbuffer PerPassCB 22 | { 23 | float gPhiColor; 24 | float gPhiNormal; 25 | bool gEnableSpatialVarianceEstimation; 26 | }; 27 | 28 | Texture2D gCompactNormDepth; 29 | Texture2D gInputSignal; 30 | Texture2D gMoments; 31 | Texture2D gHistoryLength; 32 | 33 | struct PsOut 34 | { 35 | float4 signal : SV_TARGET0; 36 | }; 37 | 38 | PsOut main(float2 texC : TEXCOORD, float4 pos : SV_POSITION) 39 | { 40 | int2 ipos = int2(pos.xy); 41 | const int2 screenSize = GetTextureDims(gInputSignal, 0); 42 | 43 | float h = gHistoryLength[ipos].r; 44 | if (h >= 4.0 || !gEnableSpatialVarianceEstimation) 45 | { 46 | PsOut out; 47 | out.signal = gInputSignal[pos.xy]; 48 | return out; 49 | } 50 | 51 | SVGFSample sampleCenter = FetchSignalSample(gInputSignal, gCompactNormDepth, ipos); 52 | if (sampleCenter.linearZ < 0) // not valid depth, must be skybox 53 | { 54 | PsOut out; 55 | out.signal = float4(sampleCenter.signal, sampleCenter.variance); 56 | return out; 57 | } 58 | 59 | const float phiColor = gPhiColor; 60 | const float phiDepth = max(sampleCenter.zDerivative, 1e-8) * 3.0; 61 | 62 | float sumWeight = 0.0; 63 | float3 sumSignal = 0.0; 64 | float2 sumMoments = 0.0; 65 | 66 | // Compute first and second moment spatially. This code also applies cross-bilateral filtering on the input color samples 67 | const int radius = 3; 68 | for (int yy = -radius; yy <= radius; ++yy) 69 | { 70 | for (int xx = -radius; xx <= radius; ++xx) 71 | { 72 | const int2 p = ipos + int2(xx, yy); 73 | const bool inside = all(greaterThanEqual(p, int2(0, 0))) && all(lessThan(p, screenSize)); 74 | 75 | if (inside) 76 | { 77 | SVGFSample sampleP = FetchSignalSample(gInputSignal, gCompactNormDepth, p); 78 | const float2 momentsP = gMoments[p].rg; 79 | 80 | const float weight = ComputeWeight(sampleCenter, sampleP, phiDepth * length(float2(xx, yy)), gPhiNormal, phiColor); 81 | 82 | sumWeight += weight; 83 | sumSignal += sampleP.signal * weight; 84 | sumMoments += momentsP * weight; 85 | } 86 | } 87 | } 88 | 89 | sumWeight = max(sumWeight, 1e-6f); 90 | sumSignal /= sumWeight; 91 | sumMoments /= sumWeight; 92 | 93 | float variance = sumMoments.g - sumMoments.r * sumMoments.r; 94 | variance *= 4.0 / h; // Boost variance for first few frames 95 | 96 | PsOut out; 97 | out.signal = float4(sumSignal, variance); 98 | 99 | return out; 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RaysRenderer 2 | 3 | Hybrid raytracing and filtering playground. 4 | 5 | ![Screenshot](./Screenshots/Screenshot.png?raw=true "Hybrid Raytracing") 6 | 7 | ## Features 8 | 9 | * A selection of forward raster, deferred raster, hybrid (G-Buffer) raytracing and forward raytracing pipelines 10 | * Raytraced reflection, shadow and AO 11 | * Single component SVGF filter 12 | 13 | ## Future Work 14 | 15 | ### Lighting 16 | 17 | * Shadowed analytical area light (Heitz 18) 18 | * Emissive mesh light 19 | 20 | ### Global Illumination 21 | 22 | * 1 bounce GGX diffuse global illumination 23 | * Surfel global illumination (EA SEED 18) 24 | * Raytraced irradiance fields (McGuire 19) 25 | 26 | ### Filters 27 | 28 | * A-SVGF (Schied 18) 29 | * Axis aligned shadow filter (Mehta 12) 30 | * Anisotropic reflection filter (Liu 18) 31 | 32 | ## Dependencies 33 | 34 | Falcor 3.2 35 | 36 | ## Setup Guide 37 | 38 | Clone Falcor. Place RaysRenderer inside a folder (any name) that is sibling to Falcor. Open the solution and build. 39 | 40 | ``` 41 | Projects/ 42 | Falcor/ 43 | Apps/ 44 | RaysRenderer/ 45 | ``` 46 | 47 | ## Reference 48 | 49 | https://github.com/NVIDIAGameWorks/Falcor 50 | 51 | https://cg.ivd.kit.edu/svgf.php 52 | -------------------------------------------------------------------------------- /RaysRenderer.cpp: -------------------------------------------------------------------------------- 1 | #include "RaysRenderer.h" 2 | 3 | namespace 4 | { 5 | // Relative to working directory. Note: different between running from VS and standalone 6 | static const char* kDefaultScene = "Data/Models/Pica.fscene"; 7 | static const glm::vec4 kClearColor(0.0f, 0.0f, 0.0f, 0.0f); 8 | static const glm::vec4 kSkyColor(0.2f, 0.6f, 0.9f, 1.0f); 9 | 10 | enum GBuffer : uint32_t 11 | { 12 | WorldPosition = 0, 13 | NormalRoughness, 14 | Albedo, 15 | MotionVector, 16 | SVGF_LinearZ, 17 | SVGF_CompactNormDepth 18 | }; 19 | } 20 | 21 | void RaysRenderer::onLoad(SampleCallbacks* sample, RenderContext* renderContext) 22 | { 23 | mFrameCount = 0; 24 | mEnableRaytracedShadows = true; 25 | mEnableRaytracedReflection = true; 26 | mEnableRaytracedAO = true; 27 | mEnableDenoiseShadows = true; 28 | mEnableDenoiseReflection = true; 29 | mEnableDenoiseAO = true; 30 | mEnableNearFieldGI = true; 31 | mEnableTAA = true; 32 | mRenderMode = RenderMode::Hybrid; 33 | mAODistance = 3.0f; 34 | mNearFieldGIStrength = 0.5f; 35 | 36 | uint32_t width = sample->getCurrentFbo()->getWidth(); 37 | uint32_t height = sample->getCurrentFbo()->getHeight(); 38 | 39 | mCamera = Camera::create(); 40 | mCamera->setAspectRatio((float)width / (float)height); 41 | mCamController.attachCamera(mCamera); 42 | 43 | SetupScene(kDefaultScene); 44 | SetupRendering(width, height); 45 | SetupRaytracing(width, height); 46 | SetupDenoising(width, height); 47 | SetupTAA(width, height); 48 | 49 | ConfigureDeferredProgram(); 50 | } 51 | 52 | void RaysRenderer::SetupScene(const std::string& filename) 53 | { 54 | mScene = RtScene::loadFromFile(filename, RtBuildFlags::None, Model::LoadFlags::None, Scene::LoadFlags::None); 55 | 56 | mSceneRenderer = SceneRenderer::create(mScene); 57 | mRaytracer = RtSceneRenderer::create(mScene); 58 | 59 | if (filename == kDefaultScene) 60 | { 61 | // Create and bind materials 62 | mBasicMaterial = Material::create("Model"); 63 | mBasicMaterial->setBaseColor(glm::vec4(0.95f, 0.0f, 0.0f, 1.0f)); 64 | mBasicMaterial->setSpecularParams(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); 65 | 66 | mGroundMaterial = Material::create("Ground"); 67 | mGroundMaterial->setBaseColor(glm::vec4(0.03f, 0.0f, 0.0f, 1.0f)); 68 | mGroundMaterial->setSpecularParams(glm::vec4(0.0f, 0.54f, 0.0f, 0.0f)); 69 | 70 | mScene->getModel(0)->getMesh(0)->setMaterial(mBasicMaterial); 71 | mScene->getModel(1)->getMesh(0)->setMaterial(mGroundMaterial); 72 | } 73 | else 74 | { 75 | mBasicMaterial = nullptr; 76 | mGroundMaterial = nullptr; 77 | } 78 | 79 | // Set scene specific camera parameters 80 | float radius = mScene->getRadius(); 81 | float nearZ = std::max(0.1f, radius / 750.0f); 82 | float farZ = radius * 20; 83 | 84 | mCamera->setPosition(glm::vec3(0.2f, 0.5f, 1.0f) * radius * 0.5f); 85 | mCamera->setTarget(mScene->getCenter()); 86 | mCamera->setDepthRange(nearZ, farZ); 87 | mCamController.setCameraSpeed(radius); 88 | } 89 | 90 | void RaysRenderer::SetupRendering(uint32_t width, uint32_t height) 91 | { 92 | // Forward pass 93 | mForwardProgram = GraphicsProgram::createFromFile("Forward.slang", "", "main"); 94 | mForwardVars = GraphicsVars::create(mForwardProgram->getReflector()); 95 | mForwardState = GraphicsState::create(); 96 | mForwardState->setProgram(mForwardProgram); 97 | mForwardState->setRasterizerState(RasterizerState::create(RasterizerState::Desc().setCullMode(RasterizerState::CullMode::None))); 98 | 99 | // G-Buffer pass 100 | mGBufferProgram = GraphicsProgram::createFromFile("GBuffer.slang", "", "main"); 101 | mGBufferVars = GraphicsVars::create(mGBufferProgram->getReflector()); 102 | mGBufferState = GraphicsState::create(); 103 | mGBufferState->setProgram(mGBufferProgram); 104 | 105 | Fbo::Desc fboDesc; 106 | fboDesc.setColorTarget(GBuffer::WorldPosition, ResourceFormat::RGBA32Float); 107 | fboDesc.setColorTarget(GBuffer::NormalRoughness, ResourceFormat::RGBA32Float); 108 | fboDesc.setColorTarget(GBuffer::Albedo, ResourceFormat::RGBA8Unorm); 109 | fboDesc.setColorTarget(GBuffer::MotionVector, ResourceFormat::RGBA16Float); 110 | fboDesc.setColorTarget(GBuffer::SVGF_LinearZ, ResourceFormat::RGBA16Float); 111 | fboDesc.setColorTarget(GBuffer::SVGF_CompactNormDepth, ResourceFormat::RGBA16Float); 112 | fboDesc.setDepthStencilTarget(ResourceFormat::D32Float); 113 | mGBuffer = FboHelper::create2D(width, height, fboDesc); 114 | 115 | // Deferred pass 116 | mDeferredPass = FullScreenPass::create("Deferred.slang"); 117 | mDeferredVars = GraphicsVars::create(mDeferredPass->getProgram()->getReflector()); 118 | mDeferredState = GraphicsState::create(); 119 | } 120 | 121 | void RaysRenderer::SetupRaytracing(uint32_t width, uint32_t height) 122 | { 123 | // Raytraced reflection 124 | RtProgram::Desc reflectionProgDesc; 125 | reflectionProgDesc.addShaderLibrary("RaytracedReflection.slang"); 126 | reflectionProgDesc.setRayGen("RayGen"); 127 | reflectionProgDesc.addHitGroup(0, "PrimaryCHS", ""); 128 | reflectionProgDesc.addHitGroup(1, "", "ShadowAHS"); 129 | reflectionProgDesc.addMiss(0, "PrimaryMiss"); 130 | reflectionProgDesc.addMiss(1, "ShadowMiss"); 131 | 132 | mRtReflectionProgram = RtProgram::create(reflectionProgDesc); 133 | mRtReflectionVars = RtProgramVars::create(mRtReflectionProgram, mScene); 134 | 135 | mRtReflectionState = RtState::create(); 136 | mRtReflectionState->setProgram(mRtReflectionProgram); 137 | mRtReflectionState->setMaxTraceRecursionDepth(4); // 1 camera ray, 2 reflection and 1 NEE ray 138 | 139 | Resource::BindFlags bindFlags = Resource::BindFlags::UnorderedAccess | Resource::BindFlags::ShaderResource; 140 | mReflectionTexture = Texture::create2D(width, height, ResourceFormat::RGBA16Float, 1, 1, nullptr, bindFlags); 141 | 142 | // Raytraced shadows 143 | RtProgram::Desc shadowProgDesc; 144 | shadowProgDesc.addShaderLibrary("RaytracedShadows.slang"); 145 | shadowProgDesc.setRayGen("RayGen"); 146 | shadowProgDesc.addHitGroup(0, "", "PrimaryAHS"); 147 | shadowProgDesc.addMiss(0, "PrimaryMiss"); 148 | 149 | mRtShadowProgram = RtProgram::create(shadowProgDesc); 150 | mRtShadowVars = RtProgramVars::create(mRtShadowProgram, mScene); 151 | 152 | mRtShadowState = RtState::create(); 153 | mRtShadowState->setProgram(mRtShadowProgram); 154 | mRtShadowState->setMaxTraceRecursionDepth(1); // no recursion 155 | 156 | mShadowTexture = Texture::create2D(width, height, ResourceFormat::R8Unorm, 1, 1, nullptr, bindFlags); 157 | 158 | // Raytraced AO 159 | RtProgram::Desc aoProgDesc; 160 | aoProgDesc.addShaderLibrary("RaytracedAO.slang"); 161 | aoProgDesc.setRayGen("RayGen"); 162 | aoProgDesc.addHitGroup(0, "", "PrimaryAHS"); 163 | aoProgDesc.addMiss(0, "PrimaryMiss"); 164 | 165 | mRtAOProgram = RtProgram::create(aoProgDesc); 166 | mRtAOVars = RtProgramVars::create(mRtAOProgram, mScene); 167 | 168 | mRtAOState = RtState::create(); 169 | mRtAOState->setProgram(mRtAOProgram); 170 | mRtAOState->setMaxTraceRecursionDepth(1); 171 | 172 | mAOTexture = Texture::create2D(width, height, ResourceFormat::R8Unorm, 1, 1, nullptr, bindFlags); 173 | } 174 | 175 | void RaysRenderer::SetupDenoising(uint32_t width, uint32_t height) 176 | { 177 | mShadowFilter = std::make_shared(width, height); 178 | mReflectionFilter = std::make_shared(width, height); 179 | mAOFilter = std::make_shared(width, height); 180 | } 181 | 182 | void RaysRenderer::SetupTAA(uint32_t width, uint32_t height) 183 | { 184 | mTAA.pTAA = TemporalAA::create(); 185 | 186 | Fbo::Desc fboDesc; 187 | fboDesc.setColorTarget(0, ResourceFormat::RGBA8UnormSrgb); 188 | mTAA.createFbos(width, height, fboDesc); 189 | 190 | PatternGenerator::SharedPtr generator; 191 | generator = HaltonSamplePattern::create(); 192 | mCamera->setPatternGenerator(generator, 1.0f / vec2(width, height)); 193 | } 194 | 195 | void RaysRenderer::ConfigureDeferredProgram() 196 | { 197 | const auto& program = mDeferredPass->getProgram(); 198 | 199 | #define HANDLE_DEFINE(condition, literal) \ 200 | if (mRenderMode == RenderMode::Hybrid && condition) program->addDefine(literal); \ 201 | else program->removeDefine(literal); 202 | 203 | HANDLE_DEFINE(mEnableRaytracedReflection, "RAYTRACE_REFLECTIONS"); 204 | HANDLE_DEFINE(mEnableRaytracedShadows, "RAYTRACE_SHADOWS"); 205 | HANDLE_DEFINE(mEnableRaytracedAO, "RAYTRACE_AO"); 206 | HANDLE_DEFINE(mEnableNearFieldGI, "NEAR_FIELD_GI_APPROX"); 207 | } 208 | 209 | void RaysRenderer::onFrameRender(SampleCallbacks* sample, RenderContext* renderContext, const Fbo::SharedPtr& targetFbo) 210 | { 211 | mCamera->beginFrame(); 212 | mCamController.update(); 213 | mSceneRenderer->update(sample->getCurrentTime()); 214 | 215 | renderContext->clearFbo(targetFbo.get(), kSkyColor, 1.0f, 0u, FboAttachmentType::All); 216 | renderContext->clearFbo(mTAA.getActiveFbo().get(), kClearColor, 1.0f, 0u, FboAttachmentType::Color); 217 | 218 | if (mRenderMode == RenderMode::Forward) 219 | { 220 | PROFILE("Forward"); 221 | 222 | mForwardState->setFbo(targetFbo); 223 | renderContext->setGraphicsState(mForwardState); 224 | renderContext->setGraphicsVars(mForwardVars); 225 | mSceneRenderer->renderScene(renderContext, mCamera.get()); 226 | } 227 | else if (mRenderMode == RenderMode::Deferred) 228 | { 229 | PROFILE("Deferred"); 230 | 231 | RenderGBuffer(renderContext); 232 | DeferredPass(renderContext, targetFbo); 233 | } 234 | else if (mRenderMode == RenderMode::Hybrid) 235 | { 236 | PROFILE("Hybrid"); 237 | 238 | RenderGBuffer(renderContext); 239 | 240 | const auto& motionTex = mGBuffer->getColorTexture(GBuffer::MotionVector); 241 | const auto& linearZTex = mGBuffer->getColorTexture(GBuffer::SVGF_LinearZ); 242 | const auto& compactTex = mGBuffer->getColorTexture(GBuffer::SVGF_CompactNormDepth); 243 | 244 | if (mEnableRaytracedShadows) 245 | { 246 | RaytraceShadows(renderContext); 247 | } 248 | if (mEnableRaytracedReflection) 249 | { 250 | RaytraceReflection(renderContext); 251 | } 252 | if (mEnableRaytracedAO) 253 | { 254 | RaytraceAmbientOcclusion(renderContext); 255 | } 256 | if (mEnableRaytracedShadows && mEnableDenoiseShadows) 257 | { 258 | PROFILE("DenoiseShadows"); 259 | mDenoisedShadowTexture = mShadowFilter->Execute(renderContext, mShadowTexture, motionTex, linearZTex, compactTex); 260 | } 261 | if (mEnableRaytracedReflection && mEnableDenoiseReflection) 262 | { 263 | PROFILE("DenoiseReflection"); 264 | mDenoisedReflectionTexture = mReflectionFilter->Execute(renderContext, mReflectionTexture, motionTex, linearZTex, compactTex); 265 | } 266 | if (mEnableRaytracedAO && mEnableDenoiseAO) 267 | { 268 | PROFILE("DenoiseAO"); 269 | mDenoisedAOTexture = mAOFilter->Execute(renderContext, mAOTexture, motionTex, linearZTex, compactTex); 270 | } 271 | 272 | DeferredPass(renderContext, targetFbo); 273 | } 274 | 275 | if (mEnableTAA) 276 | { 277 | RunTAA(renderContext, targetFbo); 278 | } 279 | 280 | mFrameCount++; 281 | } 282 | 283 | void RaysRenderer::RenderGBuffer(RenderContext* renderContext) 284 | { 285 | PROFILE("GBuffer"); 286 | mGBufferVars["PerFrameCB"]["gRenderTargetDim"] = glm::vec2(mGBuffer->getWidth(), mGBuffer->getHeight()); 287 | 288 | mGBufferState->setFbo(mGBuffer); 289 | renderContext->clearFbo(mGBuffer.get(), kClearColor, 1.0f, 0u); 290 | renderContext->setGraphicsState(mGBufferState); 291 | renderContext->setGraphicsVars(mGBufferVars); 292 | mSceneRenderer->renderScene(renderContext, mCamera.get()); 293 | } 294 | 295 | void RaysRenderer::ForwardRaytrace(RenderContext* renderContext) 296 | { 297 | uint32_t width = mForwardRaytraceOutput->getWidth(); 298 | uint32_t height = mForwardRaytraceOutput->getHeight(); 299 | 300 | mForwardRaytraceVars->getRayGenVars()->setTexture("gOutput", mForwardRaytraceOutput); 301 | 302 | auto vars = mForwardRaytraceVars->getGlobalVars(); 303 | vars["PerFrameCB"]["invView"] = glm::inverse(mCamera->getViewMatrix()); 304 | vars["PerFrameCB"]["viewportDims"] = vec2(width, height); 305 | float fovY = focalLengthToFovY(mCamera->getFocalLength(), Camera::kDefaultFrameHeight); 306 | vars["PerFrameCB"]["tanHalfFovY"] = tanf(fovY * 0.5f); 307 | vars["PerFrameCB"]["gFrameCount"] = mFrameCount; 308 | 309 | renderContext->clearUAV(mForwardRaytraceOutput->getUAV().get(), kClearColor); 310 | mRaytracer->renderScene(renderContext, mForwardRaytraceVars, mForwardRaytraceState, uvec3(width, height, 1), mCamera.get()); 311 | } 312 | 313 | void RaysRenderer::RaytraceShadows(RenderContext* renderContext) 314 | { 315 | PROFILE("RaytraceShadows"); 316 | 317 | uint32_t width = mShadowTexture->getWidth(); 318 | uint32_t height = mShadowTexture->getHeight(); 319 | 320 | mRtShadowVars->getGlobalVars()->setTexture("gOutput", mShadowTexture); 321 | mRtShadowVars->getGlobalVars()->setTexture("gGBuf0", mGBuffer->getColorTexture(GBuffer::WorldPosition)); 322 | 323 | auto shadowVars = mRtShadowVars->getGlobalVars(); 324 | shadowVars["PerFrameCB"]["gFrameCount"] = mFrameCount; 325 | 326 | renderContext->clearUAV(mShadowTexture->getUAV().get(), kClearColor); 327 | mRaytracer->renderScene(renderContext, mRtShadowVars, mRtShadowState, uvec3(width, height, 1), mCamera.get()); 328 | } 329 | 330 | void RaysRenderer::RaytraceReflection(RenderContext* renderContext) 331 | { 332 | PROFILE("RaytraceReflection"); 333 | 334 | uint32_t width = mReflectionTexture->getWidth(); 335 | uint32_t height = mReflectionTexture->getHeight(); 336 | 337 | mRtReflectionVars->getGlobalVars()->setTexture("gOutput", mReflectionTexture); 338 | mRtReflectionVars->getGlobalVars()->setTexture("gGBuf0", mGBuffer->getColorTexture(GBuffer::WorldPosition)); 339 | mRtReflectionVars->getGlobalVars()->setTexture("gGBuf1", mGBuffer->getColorTexture(GBuffer::NormalRoughness)); 340 | mRtReflectionVars->getGlobalVars()->setTexture("gGBuf2", mGBuffer->getColorTexture(GBuffer::Albedo)); 341 | 342 | auto reflectionVars = mRtReflectionVars->getGlobalVars(); 343 | reflectionVars["PerFrameCB"]["gFrameCount"] = mFrameCount; 344 | 345 | renderContext->clearUAV(mReflectionTexture->getUAV().get(), kClearColor); 346 | mRaytracer->renderScene(renderContext, mRtReflectionVars, mRtReflectionState, uvec3(width, height, 1), mCamera.get()); 347 | } 348 | 349 | void RaysRenderer::RaytraceAmbientOcclusion(RenderContext* renderContext) 350 | { 351 | PROFILE("RaytraceAO"); 352 | 353 | uint32_t width = mAOTexture->getWidth(); 354 | uint32_t height = mAOTexture->getHeight(); 355 | 356 | mRtAOVars->getGlobalVars()->setTexture("gOutput", mAOTexture); 357 | mRtAOVars->getGlobalVars()->setTexture("gGBuf0", mGBuffer->getColorTexture(GBuffer::WorldPosition)); 358 | mRtAOVars->getGlobalVars()->setTexture("gGBuf1", mGBuffer->getColorTexture(GBuffer::NormalRoughness)); 359 | 360 | auto aoVars = mRtAOVars->getGlobalVars(); 361 | aoVars["PerFrameCB"]["gFrameCount"] = mFrameCount; 362 | aoVars["PerFrameCB"]["gAODistance"] = mAODistance; 363 | 364 | renderContext->clearUAV(mAOTexture->getUAV().get(), kClearColor); 365 | mRaytracer->renderScene(renderContext, mRtAOVars, mRtAOState, uvec3(width, height, 1), mCamera.get()); 366 | } 367 | 368 | void RaysRenderer::DeferredPass(RenderContext* renderContext, const Fbo::SharedPtr& targetFbo) 369 | { 370 | PROFILE("DeferredPass"); 371 | 372 | mCamera->setIntoConstantBuffer(mDeferredVars["InternalPerFrameCB"].get(), 0); 373 | if (mScene->getLightCount() > 0) 374 | { 375 | mScene->getLight(0)->setIntoProgramVars(mDeferredVars.get(), mDeferredVars["InternalPerFrameCB"].get(), "gLights[0]"); 376 | } 377 | 378 | mDeferredVars->setTexture("gGBuf0", mGBuffer->getColorTexture(GBuffer::WorldPosition)); 379 | mDeferredVars->setTexture("gGBuf1", mGBuffer->getColorTexture(GBuffer::NormalRoughness)); 380 | mDeferredVars->setTexture("gGBuf2", mGBuffer->getColorTexture(GBuffer::Albedo)); 381 | mDeferredVars->setTexture("gGBuf3", mGBuffer->getColorTexture(GBuffer::MotionVector)); 382 | 383 | if (mRenderMode == RenderMode::Hybrid) 384 | { 385 | mDeferredVars->setTexture("gReflectionTexture", mEnableDenoiseReflection ? mDenoisedReflectionTexture : mReflectionTexture); 386 | mDeferredVars->setTexture("gShadowTexture", mEnableDenoiseShadows ? mDenoisedShadowTexture : mShadowTexture); 387 | mDeferredVars->setTexture("gAOTexture", mEnableDenoiseAO ? mDenoisedAOTexture : mAOTexture); 388 | mDeferredVars["PerImageCB"]["gNearFieldGIStrength"] = mNearFieldGIStrength; 389 | } 390 | 391 | mDeferredState->setFbo(targetFbo); 392 | renderContext->setGraphicsState(mDeferredState); 393 | renderContext->setGraphicsVars(mDeferredVars); 394 | mDeferredPass->execute(renderContext); 395 | } 396 | 397 | void RaysRenderer::RunTAA(RenderContext* renderContext, const Fbo::SharedPtr& targetFbo) 398 | { 399 | PROFILE("TAA"); 400 | 401 | const Texture::SharedPtr pCurColor = targetFbo->getColorTexture(0); 402 | const Texture::SharedPtr pMotionVec = mGBuffer->getColorTexture(GBuffer::MotionVector); 403 | const Texture::SharedPtr pPrevColor = mTAA.getInactiveFbo()->getColorTexture(0); 404 | 405 | renderContext->getGraphicsState()->pushFbo(mTAA.getActiveFbo()); 406 | mTAA.pTAA->execute(renderContext, pCurColor, pPrevColor, pMotionVec); 407 | renderContext->getGraphicsState()->popFbo(); 408 | 409 | renderContext->blit(mTAA.getActiveFbo()->getColorTexture(0)->getSRV(0, 1), targetFbo->getColorTexture(0)->getRTV()); 410 | 411 | mTAA.switchFbos(); 412 | } 413 | 414 | void RaysRenderer::onGuiRender(SampleCallbacks* sample, Gui* gui) 415 | { 416 | if (gui->beginGroup("Rendering")) 417 | { 418 | if (mRenderMode == RenderMode::Hybrid) 419 | { 420 | if (gui->addCheckBox("Raytraced Reflection", mEnableRaytracedReflection)) 421 | { 422 | ConfigureDeferredProgram(); 423 | } 424 | if (gui->addCheckBox("Raytraced Shadows", mEnableRaytracedShadows)) 425 | { 426 | ConfigureDeferredProgram(); 427 | } 428 | if (gui->addCheckBox("Raytraced AO", mEnableRaytracedAO)) 429 | { 430 | ConfigureDeferredProgram(); 431 | } 432 | 433 | gui->addFloatSlider("AO Distance", mAODistance, 0.1f, 20.0f); 434 | 435 | gui->addCheckBox("Denoise Reflection", mEnableDenoiseReflection); 436 | gui->addCheckBox("Denoise Shadows", mEnableDenoiseShadows); 437 | gui->addCheckBox("Denoise AO", mEnableDenoiseAO); 438 | 439 | if (gui->beginGroup("Reflection Filter")) 440 | { 441 | mReflectionFilter->RenderGui(gui); 442 | gui->endGroup(); 443 | } 444 | 445 | if (gui->beginGroup("Shadow Filter")) 446 | { 447 | mReflectionFilter->RenderGui(gui); 448 | gui->endGroup(); 449 | } 450 | 451 | if (gui->beginGroup("AO Filter")) 452 | { 453 | mAOFilter->RenderGui(gui); 454 | gui->endGroup(); 455 | } 456 | 457 | if (gui->addCheckBox("Near Field GI", mEnableNearFieldGI)) 458 | { 459 | ConfigureDeferredProgram(); 460 | } 461 | 462 | gui->addFloatSlider("Near Field GI Strength", mNearFieldGIStrength, 0.0f, 1.0f); 463 | } 464 | 465 | gui->addCheckBox("TAA", mEnableTAA); 466 | mTAA.pTAA->renderUI(gui, "TAA"); 467 | 468 | gui->endGroup(); 469 | } 470 | 471 | #define EDIT_MATERIAL(name, material) \ 472 | if (gui->beginGroup(name)) \ 473 | { \ 474 | auto spec = material->getSpecularParams(); \ 475 | if (gui->addFloatSlider(name ## "_Roughness", spec.g, 0.0f, 1.0f)) material->setSpecularParams(spec); \ 476 | if (gui->addFloatSlider(name ## "_Metalness", spec.b, 0.0f, 1.0f)) material->setSpecularParams(spec); \ 477 | auto diff = material->getBaseColor(); \ 478 | if (gui->addRgbaColor(name ## "Diffuse", diff)) material->setBaseColor(diff); \ 479 | gui->endGroup(); \ 480 | } 481 | 482 | if (gui->beginGroup("Content")) 483 | { 484 | if (gui->addButton("Load Scene")) 485 | { 486 | std::string filename; 487 | if (openFileDialog(Scene::kFileExtensionFilters, filename)) 488 | { 489 | SetupScene(filename); 490 | SetupRaytracing(sample->getCurrentFbo()->getWidth(), sample->getCurrentFbo()->getHeight()); 491 | } 492 | } 493 | if (mGroundMaterial) 494 | { 495 | EDIT_MATERIAL("Ground", mGroundMaterial) 496 | } 497 | 498 | if (mBasicMaterial) 499 | { 500 | EDIT_MATERIAL("Model", mBasicMaterial) 501 | } 502 | 503 | mScene->renderUI(gui, "Scene"); 504 | 505 | gui->endGroup(); 506 | } 507 | } 508 | 509 | bool RaysRenderer::onKeyEvent(SampleCallbacks* sample, const KeyboardEvent& keyEvent) 510 | { 511 | if (mCamController.onKeyEvent(keyEvent)) return true; 512 | 513 | if (keyEvent.type == KeyboardEvent::Type::KeyPressed) 514 | { 515 | if (keyEvent.key == KeyboardEvent::Key::R) 516 | { 517 | mRenderMode = (RenderMode)((mRenderMode + 1) % RenderMode::Count); 518 | ConfigureDeferredProgram(); 519 | return true; 520 | } 521 | } 522 | return false; 523 | } 524 | 525 | bool RaysRenderer::onMouseEvent(SampleCallbacks* sample, const MouseEvent& mouseEvent) 526 | { 527 | if (mCamController.onMouseEvent(mouseEvent)) return true; 528 | return false; 529 | } 530 | 531 | void RaysRenderer::onDataReload(SampleCallbacks* sample) 532 | { 533 | } 534 | 535 | void RaysRenderer::onResizeSwapChain(SampleCallbacks* sample, uint32_t width, uint32_t height) 536 | { 537 | } 538 | 539 | void RaysRenderer::onShutdown(SampleCallbacks* sample) 540 | { 541 | } 542 | 543 | int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) 544 | { 545 | Logger::setVerbosity(Logger::Level::Error); 546 | 547 | RaysRenderer::UniquePtr pRenderer = std::make_unique(); 548 | SampleConfig config; 549 | config.windowDesc.title = "Rays Renderer"; 550 | config.windowDesc.resizableWindow = true; 551 | config.deviceDesc.enableRaytracing = true; 552 | Sample::run(config, pRenderer); 553 | return 0; 554 | } 555 | -------------------------------------------------------------------------------- /RaysRenderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Falcor.h" 4 | #include "FalcorExperimental.h" 5 | #include "TAA.h" 6 | #include "SVGFPass.h" 7 | 8 | using namespace Falcor; 9 | 10 | class RaysRenderer : public Renderer 11 | { 12 | public: 13 | void onLoad(SampleCallbacks* sample, RenderContext* renderContext) override; 14 | void onFrameRender(SampleCallbacks* sample, RenderContext* renderContext, const Fbo::SharedPtr& targetFbo) override; 15 | void onShutdown(SampleCallbacks* sample) override; 16 | void onResizeSwapChain(SampleCallbacks* sample, uint32_t width, uint32_t height) override; 17 | bool onKeyEvent(SampleCallbacks* sample, const KeyboardEvent& keyEvent) override; 18 | bool onMouseEvent(SampleCallbacks* sample, const MouseEvent& mouseEvent) override; 19 | void onDataReload(SampleCallbacks* sample) override; 20 | void onGuiRender(SampleCallbacks* sample, Gui* gui) override; 21 | 22 | private: 23 | void SetupScene(const std::string& filename); 24 | void SetupRendering(uint32_t width, uint32_t height); 25 | void SetupRaytracing(uint32_t width, uint32_t height); 26 | void SetupDenoising(uint32_t width, uint32_t height); 27 | void SetupTAA(uint32_t width, uint32_t height); 28 | void ConfigureDeferredProgram(); 29 | 30 | void RenderGBuffer(RenderContext* renderContext); 31 | void DeferredPass(RenderContext* renderContext, const Fbo::SharedPtr& targetFbo); 32 | void ForwardRaytrace(RenderContext* renderContext); 33 | void RaytraceShadows(RenderContext* renderContext); 34 | void RaytraceReflection(RenderContext* renderContext); 35 | void RaytraceAmbientOcclusion(RenderContext* renderContext); 36 | void RunTAA(RenderContext* renderContext, const Fbo::SharedPtr& colorFbo); 37 | 38 | RtScene::SharedPtr mScene; 39 | Material::SharedPtr mBasicMaterial; 40 | Material::SharedPtr mGroundMaterial; 41 | 42 | Camera::SharedPtr mCamera; 43 | FirstPersonCameraController mCamController; 44 | 45 | SceneRenderer::SharedPtr mSceneRenderer; 46 | RtSceneRenderer::SharedPtr mRaytracer; 47 | 48 | RtProgram::SharedPtr mForwardRaytraceProgram; 49 | RtProgramVars::SharedPtr mForwardRaytraceVars; 50 | RtState::SharedPtr mForwardRaytraceState; 51 | Texture::SharedPtr mForwardRaytraceOutput; 52 | 53 | RtProgram::SharedPtr mRtShadowProgram; 54 | RtProgramVars::SharedPtr mRtShadowVars; 55 | RtState::SharedPtr mRtShadowState; 56 | Texture::SharedPtr mShadowTexture; 57 | Texture::SharedPtr mDenoisedShadowTexture; 58 | 59 | RtProgram::SharedPtr mRtReflectionProgram; 60 | RtProgramVars::SharedPtr mRtReflectionVars; 61 | RtState::SharedPtr mRtReflectionState; 62 | Texture::SharedPtr mReflectionTexture; 63 | Texture::SharedPtr mDenoisedReflectionTexture; 64 | 65 | RtProgram::SharedPtr mRtAOProgram; 66 | RtProgramVars::SharedPtr mRtAOVars; 67 | RtState::SharedPtr mRtAOState; 68 | Texture::SharedPtr mAOTexture; 69 | Texture::SharedPtr mDenoisedAOTexture; 70 | 71 | std::shared_ptr mShadowFilter; 72 | std::shared_ptr mReflectionFilter; 73 | std::shared_ptr mAOFilter; 74 | 75 | GraphicsProgram::SharedPtr mForwardProgram; 76 | GraphicsVars::SharedPtr mForwardVars; 77 | GraphicsState::SharedPtr mForwardState; 78 | 79 | GraphicsProgram::SharedPtr mGBufferProgram; 80 | GraphicsVars::SharedPtr mGBufferVars; 81 | GraphicsState::SharedPtr mGBufferState; 82 | Fbo::SharedPtr mGBuffer; 83 | 84 | FullScreenPass::UniquePtr mDeferredPass; 85 | GraphicsVars::SharedPtr mDeferredVars; 86 | GraphicsState::SharedPtr mDeferredState; 87 | 88 | TAA mTAA; 89 | 90 | enum RenderMode : uint32_t { Forward = 0, Deferred, Hybrid, Count }; 91 | RenderMode mRenderMode; 92 | 93 | bool mEnableRaytracedShadows; 94 | bool mEnableRaytracedReflection; 95 | bool mEnableRaytracedAO; 96 | bool mEnableDenoiseShadows; 97 | bool mEnableDenoiseReflection; 98 | bool mEnableDenoiseAO; 99 | bool mEnableNearFieldGI; 100 | bool mEnableTAA; 101 | 102 | uint32_t mFrameCount; 103 | float mAODistance; 104 | float mNearFieldGIStrength; 105 | }; 106 | -------------------------------------------------------------------------------- /RaysRenderer.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(SolutionDir)\..\..\Falcor\Framework\ 6 | 7 | 8 | 9 | 10 | 11 | $(FALCOR_CORE_DIRECTORY) 12 | 13 | 14 | -------------------------------------------------------------------------------- /RaysRenderer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.421 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RaysRenderer", "RaysRenderer.vcxproj", "{605856E4-34D4-40DF-B859-EEA3A7D52A7B}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FalcorSharedObjects", "..\..\Falcor\Framework\FalcorSharedObjects\FalcorSharedObjects.vcxproj", "{2C535635-E4C5-4098-A928-574F0E7CD5F9}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Falcor", "..\..\Falcor\Framework\Source\Falcor.vcxproj", "{3B602F0E-3834-4F73-B97D-7DFC91597A98}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|x64 = Debug|x64 15 | DebugD3D12|x64 = DebugD3D12|x64 16 | DebugVK|x64 = DebugVK|x64 17 | Release|x64 = Release|x64 18 | ReleaseD3D12|x64 = ReleaseD3D12|x64 19 | ReleaseVK|x64 = ReleaseVK|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.Debug|x64.ActiveCfg = Debug|x64 23 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.Debug|x64.Build.0 = Debug|x64 24 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.DebugD3D12|x64.ActiveCfg = Debug|x64 25 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.DebugD3D12|x64.Build.0 = Debug|x64 26 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.DebugVK|x64.ActiveCfg = Debug|x64 27 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.DebugVK|x64.Build.0 = Debug|x64 28 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.Release|x64.ActiveCfg = Release|x64 29 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.Release|x64.Build.0 = Release|x64 30 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.ReleaseD3D12|x64.ActiveCfg = Release|x64 31 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.ReleaseD3D12|x64.Build.0 = Release|x64 32 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.ReleaseVK|x64.ActiveCfg = Release|x64 33 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B}.ReleaseVK|x64.Build.0 = Release|x64 34 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.Debug|x64.ActiveCfg = DebugVK|x64 35 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.Debug|x64.Build.0 = DebugVK|x64 36 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.DebugD3D12|x64.ActiveCfg = DebugD3D12|x64 37 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.DebugD3D12|x64.Build.0 = DebugD3D12|x64 38 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.DebugVK|x64.ActiveCfg = DebugVK|x64 39 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.DebugVK|x64.Build.0 = DebugVK|x64 40 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.Release|x64.ActiveCfg = ReleaseVK|x64 41 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.Release|x64.Build.0 = ReleaseVK|x64 42 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.ReleaseD3D12|x64.ActiveCfg = ReleaseD3D12|x64 43 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.ReleaseD3D12|x64.Build.0 = ReleaseD3D12|x64 44 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.ReleaseVK|x64.ActiveCfg = ReleaseVK|x64 45 | {2C535635-E4C5-4098-A928-574F0E7CD5F9}.ReleaseVK|x64.Build.0 = ReleaseVK|x64 46 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.Debug|x64.ActiveCfg = DebugVK|x64 47 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.Debug|x64.Build.0 = DebugVK|x64 48 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.DebugD3D12|x64.ActiveCfg = DebugD3D12|x64 49 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.DebugD3D12|x64.Build.0 = DebugD3D12|x64 50 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.DebugVK|x64.ActiveCfg = DebugVK|x64 51 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.DebugVK|x64.Build.0 = DebugVK|x64 52 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.Release|x64.ActiveCfg = ReleaseVK|x64 53 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.Release|x64.Build.0 = ReleaseVK|x64 54 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.ReleaseD3D12|x64.ActiveCfg = ReleaseD3D12|x64 55 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.ReleaseD3D12|x64.Build.0 = ReleaseD3D12|x64 56 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.ReleaseVK|x64.ActiveCfg = ReleaseVK|x64 57 | {3B602F0E-3834-4F73-B97D-7DFC91597A98}.ReleaseVK|x64.Build.0 = ReleaseVK|x64 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {389EB45F-F06A-42D1-8AFF-B349F9031E2B} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /RaysRenderer.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {3b602f0e-3834-4f73-b97d-7dfc91597a98} 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | {605856E4-34D4-40DF-B859-EEA3A7D52A7B} 43 | Win32Proj 44 | RaysRenderer 45 | 10.0.17763.0 46 | 47 | 48 | 49 | Application 50 | true 51 | v141 52 | Unicode 53 | 54 | 55 | Application 56 | false 57 | v141 58 | true 59 | Unicode 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | 81 | 82 | 83 | Level3 84 | Disabled 85 | WIN32;_DEBUG;%(PreprocessorDefinitions) 86 | 87 | 88 | Windows 89 | true 90 | 91 | 92 | 93 | 94 | Level3 95 | 96 | 97 | MaxSpeed 98 | true 99 | true 100 | WIN32;NDEBUG;%(PreprocessorDefinitions) 101 | 102 | 103 | Windows 104 | true 105 | true 106 | true 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /RaysRenderer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Data 13 | 14 | 15 | 16 | 17 | {9bfa944a-fa4e-458e-abb2-e7d76857491a} 18 | 19 | 20 | 21 | 22 | Data 23 | 24 | 25 | Data 26 | 27 | 28 | Data 29 | 30 | 31 | Data 32 | 33 | 34 | Data 35 | 36 | 37 | Data 38 | 39 | 40 | Data 41 | 42 | 43 | Data 44 | 45 | 46 | Data 47 | 48 | 49 | Data 50 | 51 | 52 | Data 53 | 54 | 55 | -------------------------------------------------------------------------------- /SVGFPass.cpp: -------------------------------------------------------------------------------- 1 | #include "SVGFPass.h" 2 | 3 | using namespace Falcor; 4 | 5 | SVGFPass::SVGFPass(uint32_t width, uint32_t height) 6 | : mAtrousIterations(4), 7 | mFeedbackTap(1), 8 | mAtrousRadius(2), 9 | mAlpha(0.15f), 10 | mMomentsAlpha(0.2f), 11 | mPhiColor(10.0f), 12 | mPhiNormal(128.0f), 13 | mEnableTemporalReprojection(true), 14 | mEnableSpatialVarianceEstimation(true) 15 | { 16 | Fbo::Desc reprojFboDesc; 17 | reprojFboDesc.setColorTarget(0, ResourceFormat::RGBA16Float); // Input signal, variance 18 | reprojFboDesc.setColorTarget(1, ResourceFormat::RG16Float); // 1st and 2nd Moments 19 | reprojFboDesc.setColorTarget(2, ResourceFormat::R16Float); // History length 20 | 21 | mCurrReprojFbo = FboHelper::create2D(width, height, reprojFboDesc); 22 | mPrevReprojFbo = FboHelper::create2D(width, height, reprojFboDesc); 23 | 24 | Fbo::Desc atrousFboDesc; 25 | atrousFboDesc.setColorTarget(0, ResourceFormat::RGBA16Float); // Input signal, variance 26 | 27 | mOutputFbo = FboHelper::create2D(width, height, atrousFboDesc); 28 | mLastFilteredFbo = FboHelper::create2D(width, height, atrousFboDesc); 29 | mAtrousPingFbo = FboHelper::create2D(width, height, atrousFboDesc); 30 | mAtrousPongFbo = FboHelper::create2D(width, height, atrousFboDesc); 31 | 32 | mPrevLinearZTexture = Texture::create2D(width, height, ResourceFormat::RGBA16Float, 1, 1, nullptr, ResourceBindFlags::ShaderResource | ResourceBindFlags::RenderTarget); 33 | 34 | mReprojectionPass = FullScreenPass::create("SVGF_Reprojection.slang"); 35 | mReprojectionVars = GraphicsVars::create(mReprojectionPass->getProgram()->getReflector()); 36 | mReprojectionState = GraphicsState::create(); 37 | 38 | mVarianceEstimationPass = FullScreenPass::create("SVGF_VarianceEstimation.slang"); 39 | mVarianceEstimationVars = GraphicsVars::create(mVarianceEstimationPass->getProgram()->getReflector()); 40 | mVarianceEstimationState = GraphicsState::create(); 41 | 42 | mAtrousPass = FullScreenPass::create("SVGF_Atrous.slang"); 43 | mAtrousPass->getProgram()->addDefine("ATROUS_RADIUS", std::to_string(mAtrousRadius)); 44 | mAtrousVars = GraphicsVars::create(mAtrousPass->getProgram()->getReflector()); 45 | mAtrousState = GraphicsState::create(); 46 | } 47 | 48 | SVGFPass::~SVGFPass() 49 | { 50 | } 51 | 52 | Texture::SharedPtr SVGFPass::Execute( 53 | RenderContext* renderContext, 54 | Texture::SharedPtr inputSignal, 55 | Texture::SharedPtr motionVec, 56 | Texture::SharedPtr linearZ, 57 | Texture::SharedPtr normalDepth) 58 | { 59 | mGBufferInput.inputSignal = inputSignal; 60 | mGBufferInput.linearZ = linearZ; 61 | mGBufferInput.motionVec = motionVec; 62 | mGBufferInput.compactNormalDepth = normalDepth; 63 | 64 | TemporalReprojection(renderContext); 65 | SpatialVarianceEstimation(renderContext); 66 | 67 | for (uint32_t i = 0; i < mAtrousIterations; ++i) 68 | { 69 | Fbo::SharedPtr output = (i == mAtrousIterations - 1) ? mOutputFbo : mAtrousPongFbo; 70 | AtrousFilter(renderContext, i, mAtrousPingFbo, output); 71 | 72 | if (i == mFeedbackTap) 73 | { 74 | renderContext->blit(output->getColorTexture(0)->getSRV(), mLastFilteredFbo->getColorTexture(0)->getRTV()); 75 | } 76 | 77 | std::swap(mAtrousPingFbo, mAtrousPongFbo); 78 | } 79 | 80 | std::swap(mCurrReprojFbo, mPrevReprojFbo); 81 | 82 | renderContext->blit(mGBufferInput.linearZ->getSRV(), mPrevLinearZTexture->getRTV()); 83 | 84 | return mOutputFbo->getColorTexture(0); 85 | } 86 | 87 | void SVGFPass::TemporalReprojection(RenderContext* renderContext) 88 | { 89 | mReprojectionVars->setTexture("gInputSignal", mGBufferInput.inputSignal); 90 | mReprojectionVars->setTexture("gLinearZ", mGBufferInput.linearZ); 91 | mReprojectionVars->setTexture("gMotion", mGBufferInput.motionVec); 92 | mReprojectionVars->setTexture("gPrevLinearZ", mPrevLinearZTexture); 93 | mReprojectionVars->setTexture("gPrevInputSignal", mLastFilteredFbo->getColorTexture(0)); 94 | mReprojectionVars->setTexture("gPrevMoments", mPrevReprojFbo->getColorTexture(1)); 95 | mReprojectionVars->setTexture("gHistoryLength", mPrevReprojFbo->getColorTexture(2)); 96 | 97 | mReprojectionVars["PerPassCB"]["gAlpha"] = mAlpha; 98 | mReprojectionVars["PerPassCB"]["gMomentsAlpha"] = mMomentsAlpha; 99 | mReprojectionVars["PerPassCB"]["gEnableTemporalReprojection"] = mEnableTemporalReprojection; 100 | 101 | mReprojectionState->setFbo(mCurrReprojFbo); 102 | 103 | renderContext->pushGraphicsState(mReprojectionState); 104 | renderContext->pushGraphicsVars(mReprojectionVars); 105 | mReprojectionPass->execute(renderContext); 106 | renderContext->popGraphicsVars(); 107 | renderContext->popGraphicsState(); 108 | } 109 | 110 | void SVGFPass::SpatialVarianceEstimation(RenderContext* renderContext) 111 | { 112 | mVarianceEstimationVars->setTexture("gCompactNormDepth", mGBufferInput.compactNormalDepth); 113 | mVarianceEstimationVars->setTexture("gInputSignal", mCurrReprojFbo->getColorTexture(0)); 114 | mVarianceEstimationVars->setTexture("gMoments", mCurrReprojFbo->getColorTexture(1)); 115 | mVarianceEstimationVars->setTexture("gHistoryLength", mCurrReprojFbo->getColorTexture(2)); 116 | 117 | mVarianceEstimationVars["PerPassCB"]["gPhiColor"] = mPhiColor; 118 | mVarianceEstimationVars["PerPassCB"]["gPhiNormal"] = mPhiNormal; 119 | mVarianceEstimationVars["PerPassCB"]["gEnableSpatialVarianceEstimation"] = mEnableSpatialVarianceEstimation; 120 | 121 | mVarianceEstimationState->setFbo(mAtrousPingFbo); 122 | 123 | renderContext->pushGraphicsState(mVarianceEstimationState); 124 | renderContext->pushGraphicsVars(mVarianceEstimationVars); 125 | mVarianceEstimationPass->execute(renderContext); 126 | renderContext->popGraphicsVars(); 127 | renderContext->popGraphicsState(); 128 | } 129 | 130 | void SVGFPass::AtrousFilter(RenderContext* renderContext, uint32_t iteration, Fbo::SharedPtr input, Fbo::SharedPtr output) 131 | { 132 | mAtrousVars->setTexture("gCompactNormDepth", mGBufferInput.compactNormalDepth); 133 | mAtrousVars->setTexture("gInputSignal", input->getColorTexture(0)); 134 | 135 | mAtrousVars["PerPassCB"]["gStepSize"] = 1u << iteration; 136 | mAtrousVars["PerPassCB"]["gPhiColor"] = mPhiColor; 137 | mAtrousVars["PerPassCB"]["gPhiNormal"] = mPhiNormal; 138 | 139 | mAtrousState->setFbo(output); 140 | 141 | renderContext->pushGraphicsState(mAtrousState); 142 | renderContext->pushGraphicsVars(mAtrousVars); 143 | mAtrousPass->execute(renderContext); 144 | renderContext->popGraphicsVars(); 145 | renderContext->popGraphicsState(); 146 | } 147 | 148 | void SVGFPass::RenderGui(Gui* gui) 149 | { 150 | gui->addCheckBox("Temporal Reprojection", mEnableTemporalReprojection); 151 | gui->addCheckBox("Spatial Variance Estimation", mEnableSpatialVarianceEstimation); 152 | gui->addFloatSlider("Color Alpha", mAlpha, 0.0f, 1.0f); 153 | gui->addFloatSlider("Moments Alpha", mMomentsAlpha, 0.0f, 1.0f); 154 | gui->addFloatSlider("Phi Color", mPhiColor, 0.0f, 64.0f); 155 | gui->addFloatSlider("Phi Normal", mPhiNormal, 1.0f, 256.0f); 156 | gui->addIntSlider("Atrous Iterations", *reinterpret_cast(&mAtrousIterations), 1, 5); 157 | gui->addIntSlider("Feedback Tap", *reinterpret_cast(&mFeedbackTap), 1, 5); 158 | if (gui->addIntSlider("Atrous Radius", *reinterpret_cast(&mAtrousRadius), 1, 2)) 159 | { 160 | mAtrousPass->getProgram()->addDefine("ATROUS_RADIUS", std::to_string(mAtrousRadius)); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /SVGFPass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Falcor.h" 4 | 5 | class SVGFPass 6 | { 7 | public: 8 | SVGFPass(uint32_t width, uint32_t height); 9 | ~SVGFPass(); 10 | 11 | Falcor::Texture::SharedPtr Execute( 12 | Falcor::RenderContext* renderContext, 13 | Falcor::Texture::SharedPtr inputSignal, 14 | Falcor::Texture::SharedPtr motionVec, 15 | Falcor::Texture::SharedPtr linearZ, 16 | Falcor::Texture::SharedPtr normalDepth); 17 | 18 | void RenderGui(Falcor::Gui* gui); 19 | 20 | private: 21 | void TemporalReprojection(Falcor::RenderContext* renderContext); 22 | void SpatialVarianceEstimation(Falcor::RenderContext* renderContext); 23 | void AtrousFilter(Falcor::RenderContext* renderContext, uint32_t iteration, Falcor::Fbo::SharedPtr input, Falcor::Fbo::SharedPtr output); 24 | 25 | Falcor::FullScreenPass::UniquePtr mReprojectionPass; 26 | Falcor::GraphicsVars::SharedPtr mReprojectionVars; 27 | Falcor::GraphicsState::SharedPtr mReprojectionState; 28 | 29 | Falcor::FullScreenPass::UniquePtr mVarianceEstimationPass; 30 | Falcor::GraphicsVars::SharedPtr mVarianceEstimationVars; 31 | Falcor::GraphicsState::SharedPtr mVarianceEstimationState; 32 | 33 | Falcor::FullScreenPass::UniquePtr mAtrousPass; 34 | Falcor::GraphicsVars::SharedPtr mAtrousVars; 35 | Falcor::GraphicsState::SharedPtr mAtrousState; 36 | 37 | Falcor::Fbo::SharedPtr mAtrousPingFbo; 38 | Falcor::Fbo::SharedPtr mAtrousPongFbo; 39 | 40 | Falcor::Fbo::SharedPtr mLastFilteredFbo; 41 | 42 | Falcor::Fbo::SharedPtr mCurrReprojFbo; 43 | Falcor::Fbo::SharedPtr mPrevReprojFbo; 44 | 45 | Falcor::Fbo::SharedPtr mOutputFbo; 46 | 47 | Falcor::Texture::SharedPtr mPrevLinearZTexture; 48 | 49 | uint32_t mAtrousIterations; 50 | uint32_t mFeedbackTap; 51 | uint32_t mAtrousRadius; 52 | float mAlpha; 53 | float mMomentsAlpha; 54 | float mPhiColor; 55 | float mPhiNormal; 56 | bool mEnableTemporalReprojection; 57 | bool mEnableSpatialVarianceEstimation; 58 | 59 | struct 60 | { 61 | Falcor::Texture::SharedPtr inputSignal; 62 | Falcor::Texture::SharedPtr linearZ; 63 | Falcor::Texture::SharedPtr motionVec; 64 | Falcor::Texture::SharedPtr compactNormalDepth; 65 | } mGBufferInput; 66 | }; 67 | -------------------------------------------------------------------------------- /Screenshots/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philcn/RaysRenderer/1d431bb6c6270b8918f6510b9e65457424fb8e03/Screenshots/Screenshot.png -------------------------------------------------------------------------------- /TAA.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Falcor.h" 4 | 5 | class TAA 6 | { 7 | public: 8 | Falcor::TemporalAA::SharedPtr pTAA; 9 | Falcor::Fbo::SharedPtr getActiveFbo() { return pTAAFbos[activeFboIndex]; } 10 | Falcor::Fbo::SharedPtr getInactiveFbo() { return pTAAFbos[1 - activeFboIndex]; } 11 | void createFbos(uint32_t width, uint32_t height, const Falcor::Fbo::Desc & fboDesc) 12 | { 13 | pTAAFbos[0] = Falcor::FboHelper::create2D(width, height, fboDesc); 14 | pTAAFbos[1] = Falcor::FboHelper::create2D(width, height, fboDesc); 15 | } 16 | 17 | void switchFbos() { activeFboIndex = 1 - activeFboIndex; } 18 | void resetFbos() 19 | { 20 | activeFboIndex = 0; 21 | pTAAFbos[0] = nullptr; 22 | pTAAFbos[1] = nullptr; 23 | } 24 | 25 | void resetFboActiveIndex() { activeFboIndex = 0;} 26 | 27 | private: 28 | Falcor::Fbo::SharedPtr pTAAFbos[2]; 29 | uint32_t activeFboIndex = 0; 30 | }; 31 | --------------------------------------------------------------------------------