diff --git a/WickedEngine/globals.hlsli b/WickedEngine/globals.hlsli index 82062132c..8904a8870 100644 --- a/WickedEngine/globals.hlsli +++ b/WickedEngine/globals.hlsli @@ -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; diff --git a/WickedEngine/lightingHF.hlsli b/WickedEngine/lightingHF.hlsli index 4934e574c..c38ea2091 100644 --- a/WickedEngine/lightingHF.hlsli +++ b/WickedEngine/lightingHF.hlsli @@ -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); diff --git a/WickedEngine/voxelConeTracingHF.hlsli b/WickedEngine/voxelConeTracingHF.hlsli index a504180c1..69301fd05 100644 --- a/WickedEngine/voxelConeTracingHF.hlsli +++ b/WickedEngine/voxelConeTracingHF.hlsli @@ -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 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 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 voxels, in float3 uvw, in ++i; } - return float4(max(0, accumulation.rgb), saturate(accumulation.a)); + return float4(max(0, color), saturate(alpha)); } #endif \ No newline at end of file diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 323415f13..692c24194 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -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; diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 0a6218736..18133e71a 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -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; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 73a57b82c..d4969f420 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -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() diff --git a/models/CornellBox/CornellBox.wimf b/models/CornellBox/CornellBox.wimf new file mode 100644 index 000000000..99dd8f56f Binary files /dev/null and b/models/CornellBox/CornellBox.wimf differ