Envmap improvements
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+28
-34
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user