Merge pull request #36691 from clayjohn/VULKAN-cubemap-roughness
Improve cubemap importance sampling
This commit is contained in:
commit
c292aab247
|
@ -248,26 +248,30 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_framebuff
|
|||
RD::get_singleton()->draw_list_end();
|
||||
}
|
||||
|
||||
void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness) {
|
||||
void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
|
||||
|
||||
zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
|
||||
|
||||
roughness.push_constant.face_id = p_face_id;
|
||||
roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
|
||||
roughness.push_constant.roughness = p_roughness;
|
||||
roughness.push_constant.sample_count = p_sample_count;
|
||||
roughness.push_constant.use_direct_write = p_roughness == 0.0;
|
||||
roughness.push_constant.face_size = p_size;
|
||||
|
||||
//RUN
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
|
||||
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
|
||||
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP]);
|
||||
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
|
||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
|
||||
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_uniform_set_from_image(p_dest_framebuffer), 1);
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
|
||||
RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, true);
|
||||
RD::get_singleton()->draw_list_end();
|
||||
int x_groups = (p_size - 1) / 8 + 1;
|
||||
int y_groups = (p_size - 1) / 8 + 1;
|
||||
|
||||
RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1);
|
||||
|
||||
RD::get_singleton()->compute_list_end();
|
||||
}
|
||||
|
||||
void RasterizerEffectsRD::render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler) {
|
||||
|
@ -841,7 +845,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
|
|||
roughness.shader_version = roughness.shader.version_create();
|
||||
|
||||
for (int i = 0; i < CUBEMAP_ROUGHNESS_SOURCE_MAX; i++) {
|
||||
roughness.pipelines[i].setup(roughness.shader.version_get_shader(roughness.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
roughness.pipelines[i] = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -127,6 +127,8 @@ class RasterizerEffectsRD {
|
|||
uint32_t sample_count;
|
||||
float roughness;
|
||||
uint32_t use_direct_write;
|
||||
float face_size;
|
||||
float pad[3];
|
||||
};
|
||||
|
||||
struct CubemapRoughness {
|
||||
|
@ -134,7 +136,7 @@ class RasterizerEffectsRD {
|
|||
CubemapRoughnessPushConstant push_constant;
|
||||
CubemapRoughnessShaderRD shader;
|
||||
RID shader_version;
|
||||
RenderPipelineVertexFormatCacheRD pipelines[CUBEMAP_ROUGHNESS_SOURCE_MAX];
|
||||
RID pipelines[CUBEMAP_ROUGHNESS_SOURCE_MAX];
|
||||
} roughness;
|
||||
|
||||
struct SkyPushConstant {
|
||||
|
@ -419,7 +421,7 @@ public:
|
|||
void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region);
|
||||
void gaussian_glow(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
|
||||
|
||||
void cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness);
|
||||
void cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
|
||||
void render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler);
|
||||
void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size);
|
||||
void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip);
|
||||
|
|
|
@ -146,9 +146,7 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID
|
|||
if (p_quality) {
|
||||
//render directly to the layers
|
||||
for (int i = 0; i < rd.layers.size(); i++) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].mipmaps[0].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0));
|
||||
}
|
||||
storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].views[0], 10, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0), rd.layers[i].mipmaps[0].size.x);
|
||||
}
|
||||
} else {
|
||||
// Use fast filtering. Render directly to base mip levels
|
||||
|
@ -169,9 +167,7 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID
|
|||
if (p_quality) {
|
||||
//render directly to the layers
|
||||
for (int i = 0; i < rd.layers[0].mipmaps.size(); i++) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0));
|
||||
}
|
||||
storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].views[i], 10, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[i].size.x);
|
||||
}
|
||||
} else {
|
||||
// Use fast filtering. Render directly to each mip level
|
||||
|
@ -185,15 +181,13 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID
|
|||
}
|
||||
}
|
||||
|
||||
void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side) {
|
||||
void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer) {
|
||||
|
||||
if (p_use_arrays) {
|
||||
|
||||
if (p_quality) {
|
||||
//render directly to the layers
|
||||
for (int i = 1; i < rd.layers.size(); i++) {
|
||||
storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[i].mipmaps[0].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0));
|
||||
}
|
||||
storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x);
|
||||
} else {
|
||||
|
||||
storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, false, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size);
|
||||
|
@ -211,10 +205,8 @@ void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd,
|
|||
} else {
|
||||
|
||||
if (p_quality) {
|
||||
//render directly to the layers
|
||||
for (int i = 1; i < rd.layers[0].mipmaps.size(); i++) {
|
||||
storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0));
|
||||
}
|
||||
|
||||
storage->get_effects()->cubemap_roughness(rd.layers[0].views[p_base_layer - 1], false, rd.layers[0].views[p_base_layer], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[p_base_layer].size.x);
|
||||
} else {
|
||||
|
||||
storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, false, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size);
|
||||
|
@ -742,6 +734,21 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R
|
|||
reflection_atlas_set_size(p_reflection_atlas, 128, atlas->count);
|
||||
}
|
||||
|
||||
if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 7) {
|
||||
// Invalidate reflection atlas, need to regenerate
|
||||
RD::get_singleton()->free(atlas->reflection);
|
||||
atlas->reflection = RID();
|
||||
|
||||
for (int i = 0; i < atlas->reflections.size(); i++) {
|
||||
if (atlas->reflections[i].owner.is_null()) {
|
||||
continue;
|
||||
}
|
||||
reflection_probe_release_atlas_index(atlas->reflections[i].owner);
|
||||
}
|
||||
|
||||
atlas->reflections.clear();
|
||||
}
|
||||
|
||||
if (atlas->reflection.is_null()) {
|
||||
int mipmaps = MIN(roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
|
||||
mipmaps = storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS ? 7 : mipmaps; // always use 7 mipmaps with real time filtering
|
||||
|
@ -808,6 +815,7 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R
|
|||
rpi->atlas = p_reflection_atlas;
|
||||
rpi->rendering = true;
|
||||
rpi->dirty = false;
|
||||
rpi->processing_layer = 1;
|
||||
rpi->processing_side = 0;
|
||||
|
||||
return true;
|
||||
|
@ -827,24 +835,36 @@ bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instanc
|
|||
return false;
|
||||
}
|
||||
|
||||
_create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side);
|
||||
if (rpi->processing_layer > 1) {
|
||||
_create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, 10, rpi->processing_layer);
|
||||
rpi->processing_layer++;
|
||||
if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
|
||||
rpi->rendering = false;
|
||||
rpi->processing_side = 0;
|
||||
rpi->processing_layer = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
} else {
|
||||
_create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side, rpi->processing_layer);
|
||||
}
|
||||
|
||||
if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) {
|
||||
// Using real time reflections, all roughness is done in one step
|
||||
rpi->rendering = false;
|
||||
rpi->processing_side = 0;
|
||||
rpi->processing_layer = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
rpi->processing_side++;
|
||||
|
||||
if (rpi->processing_side == 6) {
|
||||
rpi->rendering = false;
|
||||
rpi->processing_side = 0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
rpi->processing_layer++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) {
|
||||
|
|
|
@ -108,7 +108,7 @@ private:
|
|||
void _clear_reflection_data(ReflectionData &rd);
|
||||
void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality);
|
||||
void _create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality);
|
||||
void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side);
|
||||
void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer);
|
||||
void _update_reflection_mipmaps(ReflectionData &rd, bool p_quality);
|
||||
|
||||
/* SKY */
|
||||
|
@ -165,6 +165,7 @@ private:
|
|||
|
||||
bool dirty = true;
|
||||
bool rendering = false;
|
||||
int processing_layer = 1;
|
||||
int processing_side = 0;
|
||||
|
||||
uint32_t render_step = 0;
|
||||
|
|
|
@ -1,83 +1,38 @@
|
|||
/* clang-format off */
|
||||
[vertex]
|
||||
[compute]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
layout(location = 0) out highp vec2 uv_interp;
|
||||
#define GROUP_SIZE 8
|
||||
|
||||
layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in;
|
||||
/* clang-format on */
|
||||
|
||||
void main() {
|
||||
|
||||
vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
|
||||
uv_interp = base_arr[gl_VertexIndex];
|
||||
gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
[fragment]
|
||||
|
||||
#version 450
|
||||
|
||||
VERSION_DEFINES
|
||||
|
||||
#ifdef MODE_SOURCE_PANORAMA
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_panorama;
|
||||
/* clang-format on */
|
||||
#endif
|
||||
|
||||
#ifdef MODE_SOURCE_CUBEMAP
|
||||
layout(set = 0, binding = 0) uniform samplerCube source_cube;
|
||||
#endif
|
||||
|
||||
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
|
||||
|
||||
layout(push_constant, binding = 1, std430) uniform Params {
|
||||
uint face_id;
|
||||
uint sample_count;
|
||||
float roughness;
|
||||
bool use_direct_write;
|
||||
float face_size;
|
||||
}
|
||||
params;
|
||||
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
|
||||
#define M_PI 3.14159265359
|
||||
|
||||
vec3 texelCoordToVec(vec2 uv, uint faceID) {
|
||||
mat3 faceUvVectors[6];
|
||||
/*
|
||||
// -x
|
||||
faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
|
||||
faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
|
||||
|
||||
// +x
|
||||
faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
|
||||
faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
|
||||
|
||||
// -y
|
||||
faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
|
||||
faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
|
||||
faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
|
||||
|
||||
// +y
|
||||
faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
|
||||
faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
|
||||
faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
|
||||
|
||||
// -z
|
||||
faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
|
||||
faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
|
||||
|
||||
// +z
|
||||
faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
|
||||
faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
|
||||
faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
|
||||
*/
|
||||
|
||||
// -x
|
||||
faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
|
||||
|
@ -179,21 +134,23 @@ vec4 texturePanorama(vec3 normal, sampler2D pano) {
|
|||
#endif
|
||||
|
||||
void main() {
|
||||
uvec3 id = gl_GlobalInvocationID;
|
||||
id.z += params.face_id;
|
||||
|
||||
vec2 uv = (uv_interp * 2.0) - 1.0;
|
||||
vec3 N = texelCoordToVec(uv, params.face_id);
|
||||
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) {
|
||||
|
||||
#ifdef MODE_SOURCE_PANORAMA
|
||||
|
||||
frag_color = vec4(texturePanorama(N, source_panorama).rgb, 1.0);
|
||||
imageStore(dest_cubemap, ivec3(id), vec4(texturePanorama(N, source_panorama).rgb, 1.0));
|
||||
#endif
|
||||
|
||||
#ifdef MODE_SOURCE_CUBEMAP
|
||||
frag_color = vec4(texture(source_cube, N).rgb, 1.0);
|
||||
imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0));
|
||||
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
@ -222,6 +179,6 @@ void main() {
|
|||
}
|
||||
sum /= sum.a;
|
||||
|
||||
frag_color = vec4(sum.rgb, 1.0);
|
||||
imageStore(dest_cubemap, ivec3(id), vec4(sum.rgb, 1.0));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue