voxel GI quality update; added cornell-box model for better testing
This commit is contained in:
@@ -59,14 +59,14 @@ CBUFFER(WorldCB, CBSLOT_RENDERER_WORLD)
|
||||
float3 g_xWorld_Fog; // Fog Start,End,Height
|
||||
float g_xWorld_SpecularAA;
|
||||
float g_xWorld_VoxelRadianceDataSize;
|
||||
float g_xWorld_VoxelRadianceDataSize_Inverse;
|
||||
uint g_xWorld_VoxelRadianceDataRes;
|
||||
float g_xWorld_VoxelRadianceDataRes_Inverse;
|
||||
uint g_xWorld_VoxelRadianceDataMIPs;
|
||||
uint g_xWorld_VoxelRadianceConeTracingQuality;
|
||||
uint g_xWorld_VoxelRadianceConeTracingQuality_Inverse;
|
||||
float g_xWorld_VoxelRadianceConeTracingQuality_Inverse;
|
||||
float g_xWorld_VoxelRadianceFalloff;
|
||||
bool g_xWorld_VoxelRadianceReflectionsEnabled;
|
||||
float xPadding1_WorldCB;
|
||||
float3 g_xWorld_VoxelRadianceDataCenter;
|
||||
bool g_xWorld_AdvancedRefractions;
|
||||
uint3 g_xWorld_EntityCullingTileCount;
|
||||
|
||||
@@ -704,10 +704,19 @@ inline void VoxelRadiance(in Surface surface, inout float3 diffuse, inout float3
|
||||
{
|
||||
[branch]if (g_xWorld_VoxelRadianceDataRes != 0)
|
||||
{
|
||||
float3 diff = (surface.P - g_xWorld_VoxelRadianceDataCenter) / g_xWorld_VoxelRadianceDataRes / g_xWorld_VoxelRadianceDataSize;
|
||||
float3 uvw = diff * float3(0.5f, -0.5f, 0.5f) + 0.5f;
|
||||
diff = abs(diff);
|
||||
float blend = pow(saturate(max(diff.x, max(diff.y, diff.z))), 4);
|
||||
// Convert world space surface pos to voxel grid space:
|
||||
float3 voxelSpacePos = surface.P - g_xWorld_VoxelRadianceDataCenter;
|
||||
// offset by half a voxel in the direction of the surface normal (try to avoid self-occlusion)
|
||||
voxelSpacePos += surface.N * 0.5f;
|
||||
// normalize voxel space pos to [-1, 1]:
|
||||
voxelSpacePos *= g_xWorld_VoxelRadianceDataSize_Inverse;
|
||||
voxelSpacePos *= g_xWorld_VoxelRadianceDataRes_Inverse;
|
||||
// calculate uvw coords into voxel texture:
|
||||
float3 uvw = voxelSpacePos * float3(0.5f, -0.5f, 0.5f) + 0.5f;
|
||||
|
||||
// determine blending factor (we will blend out voxel GI on grid edges):
|
||||
voxelSpacePos = saturate(abs(voxelSpacePos));
|
||||
float blend = pow(max(voxelSpacePos.x, max(voxelSpacePos.y, voxelSpacePos.z)), 4);
|
||||
|
||||
float4 radiance = ConeTraceRadiance(texture_voxelradiance, uvw, surface.N);
|
||||
diffuse += lerp(radiance.rgb, 0, blend);
|
||||
|
||||
@@ -3,63 +3,64 @@
|
||||
#include "globals.hlsli"
|
||||
|
||||
static const float3 CONES[] = {
|
||||
float3(0.355512, -0.709318, -0.102371),
|
||||
float3(0.534186, 0.71511, -0.115167),
|
||||
float3(-0.87866, 0.157139, -0.115167),
|
||||
float3(0.140679, -0.475516, -0.0639818),
|
||||
float3(-0.0796121, 0.158842, -0.677075),
|
||||
float3(-0.0759516, -0.101676, -0.483625),
|
||||
float3(0.12493, -0.0223423, -0.483625),
|
||||
float3(-0.0720074, 0.243395, -0.967251),
|
||||
float3(-0.207641, 0.414286, 0.187755),
|
||||
float3(-0.277332, -0.371262, 0.187755),
|
||||
float3(0.63864, -0.114214, 0.262857),
|
||||
float3(-0.184051, 0.622119, 0.262857),
|
||||
float3(0.110007, -0.219486, 0.435574),
|
||||
float3(0.235085, 0.314707, 0.696918),
|
||||
float3(-0.290012, 0.0518654, 0.522688),
|
||||
float3(0.0975089, -0.329594, 0.609803)
|
||||
float3(0.57735, 0.57735, 0.57735),
|
||||
float3(0.57735, -0.57735, -0.57735),
|
||||
float3(-0.57735, 0.57735, -0.57735),
|
||||
float3(-0.57735, -0.57735, 0.57735),
|
||||
float3(-0.903007, -0.182696, -0.388844),
|
||||
float3(-0.903007, 0.182696, 0.388844),
|
||||
float3(0.903007, -0.182696, 0.388844),
|
||||
float3(0.903007, 0.182696, -0.388844),
|
||||
float3(-0.388844, -0.903007, -0.182696),
|
||||
float3(0.388844, -0.903007, 0.182696),
|
||||
float3(0.388844, 0.903007, -0.182696),
|
||||
float3(-0.388844, 0.903007, 0.182696),
|
||||
float3(-0.182696, -0.388844, -0.903007),
|
||||
float3(0.182696, 0.388844, -0.903007),
|
||||
float3(-0.182696, 0.388844, 0.903007),
|
||||
float3(0.182696, -0.388844, 0.903007)
|
||||
};
|
||||
|
||||
inline float4 ConeTraceRadiance(in Texture3D<float4> voxels, in float3 uvw, in float3 N)
|
||||
{
|
||||
const uint numCones = clamp(g_xWorld_VoxelRadianceConeTracingQuality, 1, 16);
|
||||
|
||||
// Cone tracing:
|
||||
float4 radiance = 0;
|
||||
for (uint cone = 0; cone < numCones; ++cone)
|
||||
|
||||
for (uint cone = 0; cone < g_xWorld_VoxelRadianceConeTracingQuality; ++cone) // quality is between 1 and 16 cones
|
||||
{
|
||||
// try to approximate a hemisphere from random points inside a sphere:
|
||||
float3 coneVec = CONES[cone];
|
||||
// if point on sphere is facing below normal (so it's located on bottom hemisphere), put it on the opposite hemisphere instead:
|
||||
coneVec *= dot(coneVec, N) < 0 ? -1 : 1;
|
||||
// try to avoid cone extending below horizon by offsetting a bit by normal:
|
||||
coneVec += N * 0.1f;
|
||||
coneVec *= g_xWorld_VoxelRadianceDataRes_Inverse * float3(1, -1, 1);
|
||||
|
||||
float4 accumulation = 0;
|
||||
float3 color = 0;
|
||||
float alpha = 0;
|
||||
|
||||
float3 tc = uvw;
|
||||
uint i = 0;
|
||||
while (accumulation.a < 1 && !any(tc - saturate(tc)))
|
||||
while (alpha < 1 && !any(tc - saturate(tc)))
|
||||
{
|
||||
float mip = 0.7 * i;
|
||||
float mip = 0.8 * i;
|
||||
|
||||
tc += coneVec * (1 + mip);
|
||||
|
||||
float4 sam = voxels.SampleLevel(sampler_linear_clamp, tc, mip);
|
||||
accumulation.a += sam.a;
|
||||
accumulation.rgb += sam.rgb * sam.a;
|
||||
|
||||
float a = 1 - alpha;
|
||||
color += a * sam.rgb;
|
||||
alpha += a * sam.a;
|
||||
|
||||
if (mip >= (float)g_xWorld_VoxelRadianceDataMIPs)
|
||||
break;
|
||||
|
||||
++i;
|
||||
}
|
||||
float searchDist = length(uvw - tc) * g_xWorld_VoxelRadianceDataRes * g_xWorld_VoxelRadianceFalloff;
|
||||
accumulation.a /= searchDist;
|
||||
radiance += accumulation;
|
||||
|
||||
radiance += float4(color, alpha);
|
||||
}
|
||||
radiance /= numCones;
|
||||
|
||||
// final radiance is average of all the cones radiances
|
||||
radiance *= g_xWorld_VoxelRadianceConeTracingQuality_Inverse;
|
||||
radiance.a = saturate(radiance.a);
|
||||
|
||||
return max(0, radiance);
|
||||
@@ -69,24 +70,28 @@ inline float4 ConeTraceReflection(in Texture3D<float4> voxels, in float3 uvw, in
|
||||
{
|
||||
float aperture = pow(roughness, 4);
|
||||
float3 coneVec = reflect(-V, N) / g_xWorld_VoxelRadianceDataRes * float3(1, -1, 1);
|
||||
float4 accumulation = 0;
|
||||
float3 tc = uvw + coneVec;
|
||||
float NdotV = saturate(dot(N, V));
|
||||
coneVec *= lerp(0.25, 4, pow(1 - NdotV, 8));
|
||||
|
||||
float3 color = 0;
|
||||
float alpha = 0;
|
||||
|
||||
// TODO: this can result in huge loops if ray enters empty space.
|
||||
// Simply limiting iteration count is not good enough solution because most reflections won't be found that way.
|
||||
// Need to have at least some form of binary search. Maybe we could reuse lower mip to find where to backtrace?
|
||||
uint i = 0;
|
||||
while (accumulation.a < 1 && !any(tc - saturate(tc)))
|
||||
while (alpha < 1 && !any(tc - saturate(tc)))
|
||||
{
|
||||
float mip = aperture * i;
|
||||
|
||||
tc += coneVec * (1 + mip);
|
||||
|
||||
float4 sam = voxels.SampleLevel(sampler_linear_clamp, tc, mip);
|
||||
accumulation.a += sam.a;
|
||||
accumulation.rgb += sam.rgb * sam.a;
|
||||
|
||||
float a = 1 - alpha;
|
||||
color += a * sam.rgb;
|
||||
alpha += a * sam.a;
|
||||
|
||||
if (mip >= (float)g_xWorld_VoxelRadianceDataMIPs)
|
||||
{
|
||||
@@ -96,7 +101,7 @@ inline float4 ConeTraceReflection(in Texture3D<float4> voxels, in float3 uvw, in
|
||||
++i;
|
||||
}
|
||||
|
||||
return float4(max(0, accumulation.rgb), saturate(accumulation.a));
|
||||
return float4(max(0, color), saturate(alpha));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6293,10 +6293,11 @@ void wiRenderer::UpdateWorldCB(GRAPHICSTHREAD threadID)
|
||||
value.mZenith = world.zenith;
|
||||
value.mSpecularAA = SPECULARAA;
|
||||
value.mVoxelRadianceDataSize = voxelSceneData.voxelsize;
|
||||
value.mVoxelRadianceDataSize_Inverse = 1.0f / (float)value.mVoxelRadianceDataSize;
|
||||
value.mVoxelRadianceDataRes = GetVoxelRadianceEnabled() ? (UINT)voxelSceneData.res : 0;
|
||||
value.mVoxelRadianceDataRes_Inverse = 1.0f / (float)value.mVoxelRadianceDataRes;
|
||||
value.mVoxelRadianceDataMIPs = voxelSceneData.mips;
|
||||
value.mVoxelRadianceDataConeTracingQuality = voxelSceneData.coneTracingQuality;
|
||||
value.mVoxelRadianceDataConeTracingQuality = max(min(voxelSceneData.coneTracingQuality, 16), 1);
|
||||
value.mVoxelRadianceDataConeTracingQuality_Inverse = 1.0f / (float)value.mVoxelRadianceDataConeTracingQuality;
|
||||
value.mVoxelRadianceDataFalloff = voxelSceneData.falloff;
|
||||
value.mVoxelRadianceReflectionsEnabled = voxelSceneData.reflectionsEnabled;
|
||||
|
||||
@@ -133,6 +133,7 @@ public:
|
||||
XMFLOAT3 mFog;
|
||||
float mSpecularAA;
|
||||
float mVoxelRadianceDataSize;
|
||||
float mVoxelRadianceDataSize_Inverse;
|
||||
UINT mVoxelRadianceDataRes;
|
||||
float mVoxelRadianceDataRes_Inverse;
|
||||
UINT mVoxelRadianceDataMIPs;
|
||||
@@ -140,7 +141,6 @@ public:
|
||||
float mVoxelRadianceDataConeTracingQuality_Inverse;
|
||||
float mVoxelRadianceDataFalloff;
|
||||
BOOL mVoxelRadianceReflectionsEnabled;
|
||||
float pad1;
|
||||
XMFLOAT3 mVoxelRadianceDataCenter;
|
||||
BOOL mAdvancedRefractions;
|
||||
XMUINT3 mEntityCullingTileCount;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wiVersion
|
||||
// minor features, major updates
|
||||
const int minor = 16;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 8;
|
||||
const int revision = 9;
|
||||
|
||||
|
||||
long GetVersion()
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user