From d50255337bb4e3bd2124cdd3dc835828d7f84608 Mon Sep 17 00:00:00 2001 From: Turanszki Janos Date: Thu, 6 Dec 2018 23:41:42 +0000 Subject: [PATCH] lightmapper update: added explicit light sampling paths (indirect part) --- WickedEngine/raySceneIntersectHF.hlsli | 31 +++--- WickedEngine/renderlightmapPS.hlsl | 131 ++++++++++++++++++++++++- WickedEngine/tracedRenderingHF.hlsli | 12 ++- WickedEngine/wiVersion.cpp | 2 +- 4 files changed, 154 insertions(+), 22 deletions(-) diff --git a/WickedEngine/raySceneIntersectHF.hlsli b/WickedEngine/raySceneIntersectHF.hlsli index 0616fe6eb..2c757f3ce 100644 --- a/WickedEngine/raySceneIntersectHF.hlsli +++ b/WickedEngine/raySceneIntersectHF.hlsli @@ -201,7 +201,11 @@ inline bool TraceSceneANY(Ray ray, float maxDistance) return shadow; } -inline float3 Shade(inout Ray ray, RayHit hit, inout float seed, in float2 pixel) +// This will modify ray to continue the trace +// Also fill the final params of rayHit, such as normal, uv, materialIndex +// seed should be > 0 +// pixel should be normalized uv coordinates of the ray start position (used to randomize) +inline float3 Shade(inout Ray ray, inout RayHit hit, inout float seed, in float2 pixel) { if (hit.distance < INFINITE_RAYHIT) { @@ -211,17 +215,16 @@ inline float3 Shade(inout Ray ray, RayHit hit, inout float seed, in float2 pixel float v = hit.bary.y; float w = 1 - u - v; - float3 N = normalize(tri.n0 * w + tri.n1 * u + tri.n2 * v); - float2 UV = tri.t0 * w + tri.t1 * u + tri.t2 * v; + hit.N = normalize(tri.n0 * w + tri.n1 * u + tri.n2 * v); + hit.UV = tri.t0 * w + tri.t1 * u + tri.t2 * v; + hit.materialIndex = tri.materialIndex; - uint materialIndex = tri.materialIndex; + TracedRenderingMaterial mat = materialBuffer[hit.materialIndex]; - TracedRenderingMaterial mat = materialBuffer[materialIndex]; - - UV = frac(UV); // emulate wrap - float4 baseColorMap = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV * mat.baseColorAtlasMulAdd.xy + mat.baseColorAtlasMulAdd.zw, 0); - float4 surfaceMap = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV * mat.surfaceMapAtlasMulAdd.xy + mat.surfaceMapAtlasMulAdd.zw, 0); - float4 normalMap = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV * mat.normalMapAtlasMulAdd.xy + mat.normalMapAtlasMulAdd.zw, 0); + hit.UV = frac(hit.UV); // emulate wrap + float4 baseColorMap = materialTextureAtlas.SampleLevel(sampler_linear_clamp, hit.UV * mat.baseColorAtlasMulAdd.xy + mat.baseColorAtlasMulAdd.zw, 0); + float4 surfaceMap = materialTextureAtlas.SampleLevel(sampler_linear_clamp, hit.UV * mat.surfaceMapAtlasMulAdd.xy + mat.surfaceMapAtlasMulAdd.zw, 0); + float4 normalMap = materialTextureAtlas.SampleLevel(sampler_linear_clamp, hit.UV * mat.normalMapAtlasMulAdd.xy + mat.normalMapAtlasMulAdd.zw, 0); float4 baseColor = DEGAMMA(mat.baseColor * baseColorMap); float reflectance = mat.reflectance * surfaceMap.r; @@ -249,18 +252,18 @@ inline float3 Shade(inout Ray ray, RayHit hit, inout float seed, in float2 pixel // Specular reflection //float alpha = 150.0f; float alpha = sqr(1 - roughness) * 1000; - ray.direction = SampleHemisphere(reflect(ray.direction, N), alpha, seed, pixel); + ray.direction = SampleHemisphere(reflect(ray.direction, hit.N), alpha, seed, pixel); float f = (alpha + 2) / (alpha + 1); - ray.energy *= (1.0f / specChance) * specular * saturate(dot(N, ray.direction) * f); + ray.energy *= (1.0f / specChance) * specular * saturate(dot(hit.N, ray.direction) * f); } else { // Diffuse reflection - ray.direction = SampleHemisphere(N, 1.0f, seed, pixel); + ray.direction = SampleHemisphere(hit.N, 1.0f, seed, pixel); ray.energy *= (1.0f / diffChance) * albedo; } - ray.origin = hit.position + N * EPSILON; + ray.origin = hit.position + ray.direction * EPSILON; ray.primitiveID = hit.primitiveID; ray.bary = hit.bary; diff --git a/WickedEngine/renderlightmapPS.hlsl b/WickedEngine/renderlightmapPS.hlsl index aba007813..1e3e418e6 100644 --- a/WickedEngine/renderlightmapPS.hlsl +++ b/WickedEngine/renderlightmapPS.hlsl @@ -2,6 +2,10 @@ #include "tracedRenderingHF.hlsli" #include "raySceneIntersectHF.hlsli" +// Enable explicitly sampling lights placed in the scene. +// Otherwise, only scene materials are sampled (eg. emissive objects, sky, etc) +#define LIGHTMAPGEN_ENABLE_EXPLICIT_LIGHTSAMPLING + struct Input { float4 pos : SV_POSITION; @@ -15,16 +19,135 @@ float4 main(Input input) : SV_TARGET float3 N = normalize(input.normal); float2 uv = input.uv; float seed = g_xColor.z; - float3 result = 0; + float3 finalResult = 0; float3 direction = SampleHemisphere(N, 1.0f, seed, uv); - Ray ray = CreateRay(input.pos3D + N * EPSILON, direction); + Ray ray = CreateRay(input.pos3D + direction * EPSILON, direction); const uint bounces = 4; for (uint i = 0; i < bounces && any(ray.energy); ++i) { + // Sample primary ray (scene materials, sky, etc): RayHit hit = TraceScene(ray); - result += ray.energy * Shade(ray, hit, seed, uv); + finalResult += ray.energy * Shade(ray, hit, seed, uv); + +#ifdef LIGHTMAPGEN_ENABLE_EXPLICIT_LIGHTSAMPLING + // We sample explicit lights for every bounce, but only diffuse part. Specular will not be baked here. + // Also, because we do it after the primary ray was bounced off, we only get the indirect part. + // Dynamic (explicit) lights will contribute to the direct part later (based on render path specific shaders) + [loop] + for (uint iterator = 0; iterator < g_xFrame_LightArrayCount; iterator++) + { + ShaderEntityType light = EntityArray[g_xFrame_LightArrayOffset + iterator]; + + LightingResult result = (LightingResult)0; + + float3 L = 0; + float dist = 0; + + switch (light.type) + { + case ENTITY_TYPE_DIRECTIONALLIGHT: + { + dist = INFINITE_RAYHIT; + + float3 lightColor = light.GetColor().rgb*light.energy; + + L = light.directionWS.xyz; + + result.diffuse = lightColor; + } + break; + case ENTITY_TYPE_POINTLIGHT: + { + L = light.positionWS - ray.origin; + const float dist2 = dot(L, L); + dist = sqrt(dist2); + + [branch] + if (dist < light.range) + { + L /= dist; + + const float3 lightColor = light.GetColor().rgb*light.energy; + + result.diffuse = lightColor; + + const float range2 = light.range * light.range; + const float att = saturate(1.0 - (dist2 / range2)); + const float attenuation = att * att; + + result.diffuse *= attenuation; + } + } + break; + case ENTITY_TYPE_SPOTLIGHT: + { + L = light.positionWS - ray.origin; + const float dist2 = dot(L, L); + dist = sqrt(dist2); + + [branch] + if (dist < light.range) + { + L /= dist; + + const float3 lightColor = light.GetColor().rgb*light.energy; + + const float SpotFactor = dot(L, light.directionWS); + const float spotCutOff = light.coneAngleCos; + + [branch] + if (SpotFactor > spotCutOff) + { + result.diffuse = lightColor; + + const float range2 = light.range * light.range; + const float att = saturate(1.0 - (dist2 / range2)); + float attenuation = att * att; + attenuation *= saturate((1.0 - (1.0 - SpotFactor) * 1.0 / (1.0 - spotCutOff))); + + result.diffuse *= attenuation; + } + } + } + break; + case ENTITY_TYPE_SPHERELIGHT: + { + } + break; + case ENTITY_TYPE_DISCLIGHT: + { + } + break; + case ENTITY_TYPE_RECTANGLELIGHT: + { + } + break; + case ENTITY_TYPE_TUBELIGHT: + { + } + break; + } + + float NdotL = saturate(dot(L, hit.N)); + + if (NdotL > 0 && dist > 0) + { + result.diffuse = max(0.0f, result.diffuse); + + float3 sampling_offset = float3(rand(seed, uv), rand(seed, uv), rand(seed, uv)) * 2 - 1; + + Ray newRay; + newRay.origin = ray.origin; + newRay.direction = L + sampling_offset * 0.025f; + newRay.direction_inverse = rcp(newRay.direction); + newRay.energy = 0; + bool hit = TraceSceneANY(newRay, dist); + finalResult += ray.energy * (hit ? 0 : NdotL) * (result.diffuse); + } + } +#endif // LIGHTMAPGEN_ENABLE_EXPLICIT_LIGHTSAMPLING } - return float4(result, g_xColor.w); + return max(0, float4(finalResult, g_xColor.w)); } diff --git a/WickedEngine/tracedRenderingHF.hlsli b/WickedEngine/tracedRenderingHF.hlsli index 785833080..54a76f3e4 100644 --- a/WickedEngine/tracedRenderingHF.hlsli +++ b/WickedEngine/tracedRenderingHF.hlsli @@ -83,6 +83,11 @@ struct RayHit float3 position; uint primitiveID; float2 bary; + + // these will only be filled when bestHit is determined to avoid recomputing them for every intersection: + float3 N; + float2 UV; + uint materialIndex; }; inline RayHit CreateRayHit() @@ -92,9 +97,10 @@ inline RayHit CreateRayHit() hit.position = float3(0.0f, 0.0f, 0.0f); hit.primitiveID = 0xFFFFFFFF; hit.bary = 0; - //hit.normal = float3(0.0f, 0.0f, 0.0f); - //hit.materialIndex = 0; - //hit.texCoords = 0; + + hit.N = 0; + hit.UV = 0; + hit.materialIndex = 0; return hit; } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index d284155c9..0c24f11eb 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 24; // minor bug fixes, alterations, refactors, updates - const int revision = 4; + const int revision = 5; long GetVersion()