lightmapper update: added explicit light sampling paths (indirect part)
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user