diff --git a/WickedEngine/shaders/emittedparticlePS_soft.hlsl b/WickedEngine/shaders/emittedparticlePS_soft.hlsl index 27d04205e..903774ac2 100644 --- a/WickedEngine/shaders/emittedparticlePS_soft.hlsl +++ b/WickedEngine/shaders/emittedparticlePS_soft.hlsl @@ -70,7 +70,7 @@ float4 main(VertextoPixel input) : SV_TARGET Surface surface; surface.init(); - surface.create(material, color, 0); + surface.create(material, color, surfacemap_simple); surface.P = input.P; surface.N = N; surface.V = 0; diff --git a/WickedEngine/shaders/filterEnvMapCS.hlsl b/WickedEngine/shaders/filterEnvMapCS.hlsl index 6da1cf7ac..b23ab5643 100644 --- a/WickedEngine/shaders/filterEnvMapCS.hlsl +++ b/WickedEngine/shaders/filterEnvMapCS.hlsl @@ -3,7 +3,8 @@ PUSHCONSTANT(push, FilterEnvmapPushConstants); -// From "Real Shading in UnrealEngine 4" by Brian Karis +// From "Real Shading in UnrealEngine 4" by Brian Karis, page 4 +// https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf float3 ImportanceSampleGGX(float2 Xi, float Roughness, float3 N) { float a = Roughness * Roughness; @@ -14,7 +15,11 @@ float3 ImportanceSampleGGX(float2 Xi, float Roughness, float3 N) H.x = SinTheta * cos(Phi); H.y = SinTheta * sin(Phi); H.z = CosTheta; - return H; + float3 UpVector = abs(N.z) < 0.999 ? float3(0, 0, 1) : float3(1, 0, 0); + float3 TangentX = normalize(cross(UpVector, N)); + float3 TangentY = cross(N, TangentX); + // Tangent to world space + return TangentX * H.x + TangentY * H.y + N * H.z; } [numthreads(GENERATEMIPCHAIN_2D_BLOCK_SIZE, GENERATEMIPCHAIN_2D_BLOCK_SIZE, 1)] @@ -27,20 +32,30 @@ void main(uint3 DTid : SV_DispatchThreadID) float2 uv = (DTid.xy + 0.5f) * push.filterResolution_rcp.xy; float3 N = uv_to_cubemap(uv, DTid.z); - - float3x3 tangentSpace = get_tangentspace(N); + float3 V = N; float4 col = 0; + + float Roughness = push.filterRoughness; - for (uint i = 0; i < push.filterRayCount; ++i) + uint rayCount = push.filterRayCount; + for (uint i = 0; i < rayCount; ++i) { - float2 hamm = hammersley2d(i, push.filterRayCount); - float3 hemisphere = ImportanceSampleGGX(hamm, push.filterRoughness, N); - float3 cone = mul(hemisphere, tangentSpace); - - col += input.SampleLevel(sampler_linear_clamp, cone, 0); + float2 Xi = hammersley2d(i, rayCount); + float3 H = ImportanceSampleGGX(Xi, Roughness, N); + float3 L = 2 * dot(V, H) * H - V; + + float NoL = saturate(dot(N, L)); + if (NoL > 0) + { + col += input.SampleLevel(sampler_linear_clamp, L, 0) * NoL; + } + } + + if(col.a > 0) + { + col /= col.a; } - col /= (float)push.filterRayCount; output[uint3(DTid.xy, DTid.z)] = col; } diff --git a/WickedEngine/shaders/hairparticlePS.hlsl b/WickedEngine/shaders/hairparticlePS.hlsl index 27c32ed86..0e19e7f8c 100644 --- a/WickedEngine/shaders/hairparticlePS.hlsl +++ b/WickedEngine/shaders/hairparticlePS.hlsl @@ -29,7 +29,7 @@ float4 main(VertexToPixel input) : SV_Target Surface surface; surface.init(); - surface.create(material, color, 0); + surface.create(material, color, surfacemap_simple); surface.P = input.pos3D; surface.N = input.nor; surface.V = V; diff --git a/WickedEngine/shaders/lightingHF.hlsli b/WickedEngine/shaders/lightingHF.hlsli index 9d1087897..85e1eddb9 100644 --- a/WickedEngine/shaders/lightingHF.hlsli +++ b/WickedEngine/shaders/lightingHF.hlsli @@ -379,7 +379,7 @@ inline float3 EnvironmentReflection_Global(in Surface surface) GetDynamicSkyColor(float3(0, 1, 0), false, false, true), saturate(surface.R.y * 0.5 + 0.5)); - envColor = lerp(skycolor_real, skycolor_rough, saturate(surface.roughness)) * surface.F; + envColor = lerp(skycolor_real, skycolor_rough, surface.roughness) * surface.F; #else diff --git a/WickedEngine/shaders/surfaceHF.hlsli b/WickedEngine/shaders/surfaceHF.hlsli index 262086327..21f6d14fa 100644 --- a/WickedEngine/shaders/surfaceHF.hlsli +++ b/WickedEngine/shaders/surfaceHF.hlsli @@ -4,12 +4,32 @@ #define max3(v) max(max(v.x, v.y), v.z) +// hard coded value for surfaces with simplified lighting: +// occlusion = 1 +// roughness = 1 +// metalness = 0 +// reflectance = 0 +static const float4 surfacemap_simple = float4(1, 1, 0, 0); + +static const float roughness_min = 0.045f; + float3 F_Schlick(const float3 f0, float f90, float VoH) { // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering" return f0 + (f90 - f0) * pow5(1.0 - VoH); } +// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile +half3 EnvBRDFApprox(half3 SpecularColor, half Roughness, half NoV) +{ + const half4 c0 = { -1, -0.0275, -0.572, 0.022 }; + const half4 c1 = { 1, 0.0425, 1.04, -0.04 }; + half4 r = Roughness * c0 + c1; + half a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; + half2 AB = half2(-1.04, 1.04) * a004 + r.zw; + return SpecularColor * AB.x + AB.y; +} + struct SheenSurface { float3 color; @@ -222,26 +242,31 @@ struct Surface create(material); } - + inline void update() { - roughness = clamp(roughness, 0.045, 1); - roughnessBRDF = roughness * roughness; + roughness = saturate(roughness); + roughnessBRDF = sqr(max(roughness, roughness_min)); // only clamp min for BRDF! #ifdef SHEEN - sheen.roughness = clamp(sheen.roughness, 0.045, 1); - sheen.roughnessBRDF = sheen.roughness * sheen.roughness; + sheen.roughness = saturate(sheen.roughness); + sheen.roughnessBRDF = sqr(max(sheen.roughness, roughness_min)); // only clamp min for BRDF! #endif // SHEEN #ifdef CLEARCOAT - clearcoat.roughness = clamp(clearcoat.roughness, 0.045, 1); - clearcoat.roughnessBRDF = clearcoat.roughness * clearcoat.roughness; + clearcoat.roughness = saturate(clearcoat.roughness); + clearcoat.roughnessBRDF = sqr(max(clearcoat.roughness, roughness_min)); // only clamp min for BRDF! #endif // CLEARCOAT NdotV = saturate(dot(N, V) + 1e-5); - + f90 = saturate(50.0 * dot(f0, 0.33)); + +#ifdef CARTOON F = F_Schlick(f0, f90, NdotV); +#else + F = EnvBRDFApprox(f0, roughness, NdotV); +#endif // CARTOON R = -reflect(V, N); @@ -252,7 +277,12 @@ struct Surface #endif // SHEEN #ifdef CLEARCOAT - clearcoat.F = F_Schlick(f0, f90, saturate(dot(clearcoat.N, V) + 1e-5)); + float clearcoatNdotV = saturate(dot(clearcoat.N, V) + 1e-5); +#ifdef CARTOON + clearcoat.F = F_Schlick(f0, f90, clearcoatNdotV); +#else + clearcoat.F = EnvBRDFApprox(f0, clearcoat.roughness, clearcoatNdotV); +#endif // CARTOON clearcoat.F *= clearcoat.factor; clearcoat.R = -reflect(V, clearcoat.N); #endif // CLEARCOAT @@ -544,7 +574,7 @@ struct Surface if (simple_lighting) { - surfaceMap = 0; + surfaceMap = surfacemap_simple; } #ifdef SURFACE_LOAD_QUAD_DERIVATIVES diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index dc73e98d6..2ae35f51f 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -7642,9 +7642,10 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) device->BindComputeShader(&shaders[CSTYPE_FILTERENVMAP], cmd); - desc.width = std::max(1u, desc.width >> (desc.mip_levels - 1)); - desc.height = std::max(1u, desc.height >> (desc.mip_levels - 1)); - for (uint32_t i = desc.mip_levels - 1; i > 0; --i) + int mip_start = desc.mip_levels - 1; + desc.width = std::max(1u, desc.width >> mip_start); + desc.height = std::max(1u, desc.height >> mip_start); + for (int i = mip_start; i > 0; --i) { { GPUBarrier barriers[] = { @@ -7664,8 +7665,15 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) push.filterResolution_rcp.x = 1.0f / push.filterResolution.x; push.filterResolution_rcp.y = 1.0f / push.filterResolution.y; push.filterRoughness = (float)i / (float)desc.mip_levels; - push.filterRayCount = 128; - push.texture_input = device->GetDescriptorIndex(&vis.scene->envrenderingColorBuffer, SubresourceType::SRV, std::max(0, (int)i - 2)); + if (probe.IsRealTime()) + { + push.filterRayCount = 128; + } + else + { + push.filterRayCount = 1024; + } + push.texture_input = device->GetDescriptorIndex(&vis.scene->envrenderingColorBuffer, SubresourceType::SRV, std::max(0, (int)i - 1)); push.texture_output = device->GetDescriptorIndex(&vis.scene->envrenderingColorBuffer, SubresourceType::UAV, i); device->PushConstants(&push, sizeof(push), cmd); @@ -7703,6 +7711,7 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) EnvironmentProbeComponent probe; probe.textureIndex = 0; probe.position = vis.camera->Eye; + probe.SetRealTime(true); AABB probe_aabb; probe_aabb.layerMask = 0; @@ -8728,7 +8737,6 @@ void BlockCompress(const Texture& texture_src, const Texture& texture_bc, Comman desc.height = std::max(1u, texture_bc.desc.height / block_size); desc.bind_flags = BindFlag::UNORDERED_ACCESS; desc.layout = ResourceState::UNORDERED_ACCESS; - desc.mip_levels = GetMipCount(desc.width, desc.height); Texture bc_raw_dest; { @@ -8797,22 +8805,14 @@ void BlockCompress(const Texture& texture_src, const Texture& texture_bc, Comman bc_raw_desc.height = std::max(bc_raw->desc.height, bc_raw_desc.height); bc_raw_desc.width = wi::math::GetNextPowerOfTwo(bc_raw_desc.width); bc_raw_desc.height = wi::math::GetNextPowerOfTwo(bc_raw_desc.height); - bc_raw_desc.mip_levels = GetMipCount(bc_raw_desc.width, bc_raw_desc.height); device->CreateTexture(&bc_raw_desc, nullptr, bc_raw); device->SetName(bc_raw, "bc_raw"); - for (uint32_t i = 0; i < bc_raw->desc.mip_levels; ++i) - { - int subresource_index = device->CreateSubresource(bc_raw, SubresourceType::UAV, 0, bc_raw_desc.array_size, i, 1); - assert(subresource_index == i); - } - std::string info; info += "BlockCompress created a new raw block texture to fit request: " + std::string(GetFormatString(texture_bc.desc.format)) + " (" + std::to_string(texture_bc.desc.width) + ", " + std::to_string(texture_bc.desc.height) + ")"; info += "\n\tFormat = "; info += GetFormatString(bc_raw_desc.format); info += "\n\tResolution = " + std::to_string(bc_raw_desc.width) + " * " + std::to_string(bc_raw_desc.height); - info += "\n\tMip Levels = " + std::to_string(bc_raw_desc.mip_levels); info += "\n\tArray Size = " + std::to_string(bc_raw_desc.array_size); size_t total_size = 0; total_size += ComputeTextureMemorySizeInBytes(bc_raw_desc); @@ -8823,28 +8823,22 @@ void BlockCompress(const Texture& texture_src, const Texture& texture_bc, Comman bc_raw_dest = *bc_raw; } - const uint32_t mip_levels = std::min(desc.mip_levels, std::min(texture_src.desc.mip_levels, texture_bc.desc.mip_levels)); - for (uint32_t mip = 0; mip < mip_levels; ++mip) + for (uint32_t mip = 0; mip < texture_bc.desc.mip_levels; ++mip) { const uint32_t width = std::max(1u, desc.width >> mip); const uint32_t height = std::max(1u, desc.height >> mip); device->BindResource(&texture_src, 0, cmd, texture_src.desc.mip_levels == 1 ? -1 : mip); - device->BindUAV(&bc_raw_dest, 0, cmd, mip); + device->BindUAV(&bc_raw_dest, 0, cmd); device->Dispatch((width + 7u) / 8u, (height + 7u) / 8u, desc.array_size, cmd); - } - GPUBarrier barriers[] = { - GPUBarrier::Image(&bc_raw_dest, ResourceState::UNORDERED_ACCESS, ResourceState::COPY_SRC), - GPUBarrier::Image(&texture_bc, texture_bc.desc.layout, ResourceState::COPY_DST), - }; - device->Barrier(barriers, arraysize(barriers), cmd); + GPUBarrier barriers[] = { + GPUBarrier::Image(&bc_raw_dest, ResourceState::UNORDERED_ACCESS, ResourceState::COPY_SRC), + GPUBarrier::Image(&texture_bc, texture_bc.desc.layout, ResourceState::COPY_DST), + }; + device->Barrier(barriers, arraysize(barriers), cmd); - for (uint32_t slice = 0; slice < desc.array_size; ++slice) - { - for (uint32_t mip = 0; mip < texture_bc.desc.mip_levels; ++mip) + for (uint32_t slice = 0; slice < desc.array_size; ++slice) { - const uint32_t width = std::max(1u, desc.width >> mip); - const uint32_t height = std::max(1u, desc.height >> mip); Box box; box.left = 0; box.right = width; @@ -8855,18 +8849,18 @@ void BlockCompress(const Texture& texture_src, const Texture& texture_bc, Comman device->CopyTexture( &texture_bc, 0, 0, 0, mip, dst_slice_offset + slice, - &bc_raw_dest, std::min(mip, bc_raw_dest.desc.mip_levels - 1), slice, + &bc_raw_dest, 0, slice, cmd, &box ); } - } - for (int i = 0; i < arraysize(barriers); ++i) - { - std::swap(barriers[i].image.layout_before, barriers[i].image.layout_after); + for (int i = 0; i < arraysize(barriers); ++i) + { + std::swap(barriers[i].image.layout_before, barriers[i].image.layout_after); + } + device->Barrier(barriers, arraysize(barriers), cmd); } - device->Barrier(barriers, arraysize(barriers), cmd); device->EventEnd(cmd); } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 62828b536..2d23e48ca 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 280; + const int revision = 281; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);