Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1776,10 +1776,10 @@
<member name="rendering/reflections/sky_reflections/fast_filter_high_quality" type="bool" setter="" getter="" default="false">
Use a higher quality variant of the fast filtering algorithm. Significantly slower than using default quality, but results in smoother reflections. Should only be used when the scene is especially detailed.
</member>
<member name="rendering/reflections/sky_reflections/ggx_samples" type="int" setter="" getter="" default="1024">
<member name="rendering/reflections/sky_reflections/ggx_samples" type="int" setter="" getter="" default="32">
Sets the number of samples to take when using importance sampling for [Sky]s and [ReflectionProbe]s. A higher value will result in smoother, higher quality reflections, but increases time to calculate radiance maps. In general, fewer samples are needed for simpler, low dynamic range environments while more samples are needed for HDR environments and environments with a high level of detail.
</member>
<member name="rendering/reflections/sky_reflections/ggx_samples.mobile" type="int" setter="" getter="" default="128">
<member name="rendering/reflections/sky_reflections/ggx_samples.mobile" type="int" setter="" getter="" default="16">
Lower-end override for [member rendering/reflections/sky_reflections/ggx_samples] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/reflections/sky_reflections/roughness_layers" type="int" setter="" getter="" default="8">
Expand Down
2 changes: 1 addition & 1 deletion servers/rendering/renderer_rd/effects_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2040,7 +2040,7 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, u
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline);

RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture, true), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1);

RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
Expand Down
44 changes: 35 additions & 9 deletions servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,12 +473,13 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS
}
RD::get_singleton()->draw_command_end_label(); // Filter radiance
} else {
RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);

for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
}

RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
Vector<RID> views;
if (p_use_arrays) {
for (int i = 1; i < layers.size(); i++) {
Expand All @@ -489,8 +490,9 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS
views.push_back(layers[0].views[i]);
}
}

RD::get_singleton()->draw_command_begin_label("Fast filter radiance");
effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
RD::get_singleton()->draw_command_end_label(); // Filter radiance
}
}

Expand All @@ -500,12 +502,25 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren
bool prefer_raster_effects = effects->get_prefer_raster_effects();

if (prefer_raster_effects) {
// Need to ask clayjohn but p_cube_side is set to 10, looks like in the compute shader we're doing all 6 sides in one call
// here we need to do them one by one so ignoring p_cube_side
if (p_base_layer == 1) {
RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
for (int k = 0; k < 6; k++) {
effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
}

for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
for (int k = 0; k < 6; k++) {
effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
}
}
RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
}

RD::get_singleton()->draw_command_begin_label("High Quality filter radiance");
if (p_use_arrays) {
for (int k = 0; k < 6; k++) {
effects->cubemap_roughness_raster(
radiance_base_cubemap,
downsampled_radiance_cubemap,
layers[p_base_layer].mipmaps[0].framebuffers[k],
k,
p_sky_ggx_samples_quality,
Expand All @@ -515,7 +530,7 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren
} else {
for (int k = 0; k < 6; k++) {
effects->cubemap_roughness_raster(
layers[0].views[p_base_layer - 1],
downsampled_radiance_cubemap,
layers[0].mipmaps[p_base_layer].framebuffers[k],
k,
p_sky_ggx_samples_quality,
Expand All @@ -524,19 +539,30 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren
}
}
} else {
if (p_base_layer == 1) {
RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);

for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
}
RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
}

RD::get_singleton()->draw_command_begin_label("High Quality filter radiance");
if (p_use_arrays) {
//render directly to the layers
effects->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
} else {
effects->cubemap_roughness(
layers[0].views[p_base_layer - 1],
downsampled_radiance_cubemap,
layers[0].views[p_base_layer],
p_cube_side,
p_sky_ggx_samples_quality,
float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
layers[0].mipmaps[p_base_layer].size.x);
}
}
RD::get_singleton()->draw_command_end_label(); // Filter radiance
}

void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
Expand Down
26 changes: 20 additions & 6 deletions servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,38 @@ void main() {
vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0);
vec3 N = texelCoordToVec(uv, id.z);

//vec4 color = color_interp;

if (params.use_direct_write) {
imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0));
} else {
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);

float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size);
float roughness2 = params.roughness * params.roughness;
float roughness4 = roughness2 * roughness2;
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
mat3 T;
T[0] = normalize(cross(UpVector, N));
T[1] = cross(N, T[0]);
T[2] = N;

for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
vec2 xi = Hammersley(sampleNum, params.sample_count);

vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
vec3 V = N;
vec3 L = (2.0 * dot(V, H) * H - V);
vec3 H = T * ImportanceSampleGGX(xi, roughness4);
float NdotH = dot(N, H);
vec3 L = (2.0 * NdotH * H - N);

float ndotl = clamp(dot(N, L), 0.0, 1.0);

if (ndotl > 0.0) {
sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
float D = DistributionGGX(NdotH, roughness4);
float pdf = D * NdotH / (4.0 * NdotH) + 0.0001;

float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001);

float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel);

sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl;
sum.a += ndotl;
}
}
Expand Down
21 changes: 11 additions & 10 deletions servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ vec3 texelCoordToVec(vec2 uv, uint faceID) {
return normalize(result);
}

vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]

vec3 ImportanceSampleGGX(vec2 xi, float roughness4) {
// Compute distribution direction
float Phi = 2.0 * M_PI * Xi.x;
float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
float Phi = 2.0 * M_PI * xi.x;
float CosTheta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y));
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);

// Convert to spherical direction
Expand All @@ -61,12 +59,15 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
H.y = SinTheta * sin(Phi);
H.z = CosTheta;

vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 TangentX = normalize(cross(UpVector, N));
vec3 TangentY = cross(N, TangentX);
return H;
}

float DistributionGGX(float NdotH, float roughness4) {
float NdotH2 = NdotH * NdotH;
float denom = (NdotH2 * (roughness4 - 1.0) + 1.0);
denom = M_PI * denom * denom;

// Tangent to world space
return TangentX * H.x + TangentY * H.y + N * H.z;
return roughness4 / denom;
}

// https://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,33 @@ void main() {
} else {
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);

float solid_angle_texel = 4.0 * M_PI / (6.0 * params.face_size * params.face_size);
float roughness2 = params.roughness * params.roughness;
float roughness4 = roughness2 * roughness2;
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
mat3 T;
T[0] = normalize(cross(UpVector, N));
T[1] = cross(N, T[0]);
T[2] = N;

for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
vec2 xi = Hammersley(sampleNum, params.sample_count);

vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
vec3 V = N;
vec3 L = (2.0 * dot(V, H) * H - V);
vec3 H = T * ImportanceSampleGGX(xi, roughness4);
float NdotH = dot(N, H);
vec3 L = (2.0 * NdotH * H - N);

float ndotl = clamp(dot(N, L), 0.0, 1.0);

if (ndotl > 0.0) {
sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
float D = DistributionGGX(NdotH, roughness4);
float pdf = D * NdotH / (4.0 * NdotH) + 0.0001;

float solid_angle_sample = 1.0 / (float(params.sample_count) * pdf + 0.0001);

float mipLevel = params.roughness == 0.0 ? 0.0 : 0.5 * log2(solid_angle_sample / solid_angle_texel);

sum.rgb += textureLod(source_cube, L, mipLevel).rgb * ndotl;
sum.a += ndotl;
}
}
Expand Down
6 changes: 3 additions & 3 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2860,11 +2860,11 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug", false);
GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true);

GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8);
GLOBAL_DEF_RST("rendering/reflections/sky_reflections/roughness_layers", 8); // Assumes a 256x256 cubemap
GLOBAL_DEF_RST("rendering/reflections/sky_reflections/texture_array_reflections", true);
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false);
GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples", 1024);
GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 128);
GLOBAL_DEF_RST("rendering/reflections/sky_reflections/ggx_samples", 32);
GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 16);
GLOBAL_DEF("rendering/reflections/sky_reflections/fast_filter_high_quality", false);
GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size", 256);
GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size.mobile", 128);
Expand Down