EEVEE-Next: Simplify sphere lightprobe coordinates
The storage coordinate is left unchanged and is kept as `ReflectionProbeAtlasCoordinate`. A new structure `ReflectionProbeCoordinate` contain scale and offset for efficient sampling without integer math. The `ReflectionProbeWriteCoordinate` is only used during the octahedral map processing. This also has the benefit to centralize the coordinate changes to a single class. Pull Request: https://projects.blender.org/blender/blender/pulls/117011
This commit is contained in:
committed by
Clément Foucault
parent
dd0482da76
commit
29ec924f9f
@@ -825,8 +825,10 @@ void IrradianceBake::surfels_create(const Object &probe_object)
|
||||
capture_info_buf_.capture_indirect = capture_indirect_;
|
||||
capture_info_buf_.capture_emission = capture_emission_;
|
||||
|
||||
ReflectionProbeAtlasCoordinate atlas_coord = inst_.reflection_probes.world_atlas_coord_get();
|
||||
capture_info_buf_.world_atlas_coord = *reinterpret_cast<int4 *>(&atlas_coord);
|
||||
ReflectionProbeModule &reflections = inst_.reflection_probes;
|
||||
ReflectionProbeAtlasCoordinate atlas_coord = reflections.world_atlas_coord_get();
|
||||
ReflectionProbeCoordinate coord = atlas_coord.as_sampling_coord(reflections.atlas_extent());
|
||||
capture_info_buf_.world_atlas_coord = coord;
|
||||
|
||||
dispatch_per_grid_sample_ = math::divide_ceil(grid_resolution, int3(IRRADIANCE_GRID_GROUP_SIZE));
|
||||
capture_info_buf_.irradiance_grid_size = grid_resolution;
|
||||
|
||||
@@ -177,9 +177,12 @@ void ReflectionProbeModule::init()
|
||||
pass.init();
|
||||
pass.shader_set(instance_.shaders.static_shader_get(REFLECTION_PROBE_REMAP));
|
||||
pass.bind_texture("cubemap_tx", &cubemap_tx_);
|
||||
pass.bind_image("octahedral_img", &probes_tx_);
|
||||
pass.push_constant("probe_coord_packed", reinterpret_cast<int4 *>(&reflection_probe_coord_));
|
||||
pass.push_constant("world_coord_packed", reinterpret_cast<int4 *>(&world_probe_coord_));
|
||||
pass.bind_image("atlas_dst_mip_img", &atlas_dst_mip_tx_);
|
||||
pass.bind_image("atlas_src_mip_img", &atlas_src_mip_tx_);
|
||||
pass.push_constant("probe_coord_packed", reinterpret_cast<int4 *>(&probe_sampling_coord_));
|
||||
pass.push_constant("write_coord_packed", reinterpret_cast<int4 *>(&probe_write_coord_));
|
||||
pass.push_constant("world_coord_packed", reinterpret_cast<int4 *>(&world_write_coord_));
|
||||
pass.push_constant("mip_level", &probe_mip_level_);
|
||||
pass.dispatch(&dispatch_probe_pack_);
|
||||
}
|
||||
|
||||
@@ -187,7 +190,7 @@ void ReflectionProbeModule::init()
|
||||
PassSimple &pass = update_irradiance_ps_;
|
||||
pass.init();
|
||||
pass.shader_set(instance_.shaders.static_shader_get(REFLECTION_PROBE_UPDATE_IRRADIANCE));
|
||||
pass.push_constant("world_coord_packed", reinterpret_cast<int4 *>(&world_probe_coord_));
|
||||
pass.push_constant("world_coord_packed", reinterpret_cast<int4 *>(&world_sampling_coord_));
|
||||
pass.bind_image("irradiance_atlas_img", &instance_.irradiance_cache.irradiance_atlas_tx_);
|
||||
pass.bind_texture("reflection_probes_tx", &probes_tx_);
|
||||
pass.dispatch(int2(1, 1));
|
||||
@@ -248,7 +251,7 @@ void ReflectionProbeModule::sync_world(::World *world)
|
||||
probe.atlas_coord = find_empty_atlas_region(layer_subdivision);
|
||||
do_world_update_set(true);
|
||||
}
|
||||
world_probe_coord_ = probe.atlas_coord;
|
||||
world_sampling_coord_ = probe.atlas_coord.as_sampling_coord(atlas_extent());
|
||||
}
|
||||
|
||||
void ReflectionProbeModule::sync_world_lookdev()
|
||||
@@ -260,7 +263,7 @@ void ReflectionProbeModule::sync_world_lookdev()
|
||||
if (layer_subdivision != probe.atlas_coord.layer_subdivision) {
|
||||
probe.atlas_coord = find_empty_atlas_region(layer_subdivision);
|
||||
}
|
||||
world_probe_coord_ = probe.atlas_coord;
|
||||
world_sampling_coord_ = probe.atlas_coord.as_sampling_coord(atlas_extent());
|
||||
|
||||
do_world_update_set(true);
|
||||
}
|
||||
@@ -465,11 +468,21 @@ std::optional<ReflectionProbeUpdateInfo> ReflectionProbeModule::update_info_pop(
|
||||
void ReflectionProbeModule::remap_to_octahedral_projection(
|
||||
const ReflectionProbeAtlasCoordinate &atlas_coord)
|
||||
{
|
||||
ReflectionProbe &world_probe = probes_.lookup(world_object_key_);
|
||||
|
||||
int world_layer_subdivision = world_probe.atlas_coord.layer_subdivision;
|
||||
int resolution = max_resolution_ >> atlas_coord.layer_subdivision;
|
||||
/* Update shader parameters that change per dispatch. */
|
||||
reflection_probe_coord_ = atlas_coord;
|
||||
probe_sampling_coord_ = atlas_coord.as_sampling_coord(atlas_extent());
|
||||
probe_write_coord_ = atlas_coord.as_write_coord(atlas_extent(), 0);
|
||||
probe_mip_level_ = atlas_coord.layer_subdivision;
|
||||
world_write_coord_ = world_probe.atlas_coord.as_write_coord(atlas_extent(), probe_mip_level_);
|
||||
dispatch_probe_pack_ = int3(int2(ceil_division(resolution, REFLECTION_PROBE_GROUP_SIZE)), 1);
|
||||
|
||||
probes_tx_.ensure_mip_views();
|
||||
atlas_dst_mip_tx_ = probes_tx_.mip_view(0);
|
||||
atlas_src_mip_tx_ = probes_tx_.mip_view(probe_mip_level_ - world_layer_subdivision);
|
||||
|
||||
instance_.manager->submit(remap_ps_);
|
||||
}
|
||||
|
||||
@@ -491,7 +504,7 @@ void ReflectionProbeModule::set_view(View & /*view*/)
|
||||
if (reflection_probe_count_ >= REFLECTION_PROBES_MAX - 1) {
|
||||
break;
|
||||
}
|
||||
probe.recalc_lod_factors(probes_tx_.width());
|
||||
probe.prepare_for_upload(atlas_extent());
|
||||
/* World is always considered active and added last. */
|
||||
if (probe.type == ReflectionProbe::Type::WORLD) {
|
||||
continue;
|
||||
|
||||
@@ -28,7 +28,68 @@ struct ReflectionProbeUpdateInfo;
|
||||
/** \name Reflection Probe
|
||||
* \{ */
|
||||
|
||||
struct ReflectionProbeAtlasCoordinate {
|
||||
/** On which layer of the texture array is this reflection probe stored. */
|
||||
int layer = -1;
|
||||
/**
|
||||
* Subdivision of the layer. 0 = no subdivision and resolution would be
|
||||
* ReflectionProbeModule::MAX_RESOLUTION.
|
||||
*/
|
||||
int layer_subdivision = -1;
|
||||
/**
|
||||
* Which area of the subdivided layer is the reflection probe located.
|
||||
*
|
||||
* A layer has (2^layer_subdivision)^2 areas.
|
||||
*/
|
||||
int area_index = -1;
|
||||
|
||||
/* Return the area extent in pixel. */
|
||||
int area_extent(int atlas_extent) const
|
||||
{
|
||||
return atlas_extent >> layer_subdivision;
|
||||
}
|
||||
|
||||
/* Coordinate of the area in [0..area_count_per_dimension[ range. */
|
||||
int2 area_location() const
|
||||
{
|
||||
const int area_count_per_dimension = 1 << layer_subdivision;
|
||||
return int2(area_index % area_count_per_dimension, area_index / area_count_per_dimension);
|
||||
}
|
||||
|
||||
/* Coordinate of the bottom left corner of the area in [0..atlas_extent[ range. */
|
||||
int2 area_offset(int atlas_extent) const
|
||||
{
|
||||
return area_location() * area_extent(atlas_extent);
|
||||
}
|
||||
|
||||
ReflectionProbeCoordinate as_sampling_coord(int atlas_extent) const
|
||||
{
|
||||
const int area_count_per_dimension = 1 << layer_subdivision;
|
||||
const float area_scale = 1.0f / area_count_per_dimension;
|
||||
const float2 area_location = float2(this->area_location());
|
||||
|
||||
float texel_size = 1.0f / atlas_extent;
|
||||
float border_size = REFLECTION_PROBE_BORDER_SIZE * texel_size;
|
||||
|
||||
ReflectionProbeCoordinate coord;
|
||||
coord.offset = (border_size + 0.5f * texel_size + area_location) * area_scale;
|
||||
coord.scale = (1.0f - 2.0f * border_size) * area_scale;
|
||||
coord.layer = layer;
|
||||
return coord;
|
||||
}
|
||||
|
||||
ReflectionProbeWriteCoordinate as_write_coord(int atlas_extent, int mip_lvl) const
|
||||
{
|
||||
ReflectionProbeWriteCoordinate coord;
|
||||
coord.extent = atlas_extent >> (layer_subdivision + mip_lvl);
|
||||
coord.offset = (area_location() * coord.extent) >> mip_lvl;
|
||||
coord.layer = layer;
|
||||
return coord;
|
||||
}
|
||||
};
|
||||
|
||||
struct ReflectionProbe : ReflectionProbeData {
|
||||
public:
|
||||
enum class Type {
|
||||
WORLD,
|
||||
PROBE,
|
||||
@@ -57,19 +118,19 @@ struct ReflectionProbe : ReflectionProbeData {
|
||||
bool viewport_display;
|
||||
float viewport_display_size;
|
||||
|
||||
ReflectionProbe()
|
||||
{
|
||||
this->atlas_coord.layer_subdivision = -1;
|
||||
this->atlas_coord.layer = -1;
|
||||
this->atlas_coord.area_index = -1;
|
||||
}
|
||||
ReflectionProbeAtlasCoordinate atlas_coord;
|
||||
|
||||
void recalc_lod_factors(int atlas_resolution)
|
||||
void prepare_for_upload(int atlas_extent)
|
||||
{
|
||||
const float probe_resolution = atlas_resolution >> atlas_coord.layer_subdivision;
|
||||
/* Compute LOD factor. */
|
||||
const int probe_resolution = atlas_coord.area_extent(atlas_extent);
|
||||
const float bias = 0.0;
|
||||
const float lod_factor = bias + 0.5 * log(float(square_i(probe_resolution))) / log(2.0);
|
||||
const float lod_factor = bias + 0.5 * log2f(square_i(probe_resolution));
|
||||
this->lod_factor = lod_factor;
|
||||
|
||||
/* Compute sampling offset and scale. */
|
||||
static_cast<ReflectionProbeData *>(this)->atlas_coord = atlas_coord.as_sampling_coord(
|
||||
atlas_extent);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -97,10 +158,11 @@ class ReflectionProbeModule {
|
||||
ReflectionProbeDataBuf data_buf_;
|
||||
ReflectionProbes probes_;
|
||||
|
||||
ReflectionProbe world_probe_data;
|
||||
|
||||
/** Probes texture stored in octahedral mapping. */
|
||||
Texture probes_tx_ = {"Probes"};
|
||||
/* Reference to a specific mip map layer of a texture. */
|
||||
GPUTexture *atlas_dst_mip_tx_ = nullptr;
|
||||
GPUTexture *atlas_src_mip_tx_ = nullptr;
|
||||
|
||||
PassSimple remap_ps_ = {"Probe.CubemapToOctahedral"};
|
||||
PassSimple update_irradiance_ps_ = {"Probe.UpdateIrradiance"};
|
||||
@@ -116,11 +178,15 @@ class ReflectionProbeModule {
|
||||
*/
|
||||
Texture cubemap_tx_ = {"Probe.Cubemap"};
|
||||
/** Index of the probe being updated. */
|
||||
int reflection_probe_index_ = 0;
|
||||
int probe_index_ = 0;
|
||||
/** Mip level being sampled for remapping. */
|
||||
int probe_mip_level_ = 0;
|
||||
/** Updated Probe coordinates in the atlas. */
|
||||
ReflectionProbeAtlasCoordinate reflection_probe_coord_;
|
||||
ReflectionProbeCoordinate probe_sampling_coord_;
|
||||
ReflectionProbeWriteCoordinate probe_write_coord_;
|
||||
/** World coordinates in the atlas. */
|
||||
ReflectionProbeAtlasCoordinate world_probe_coord_;
|
||||
ReflectionProbeCoordinate world_sampling_coord_;
|
||||
ReflectionProbeWriteCoordinate world_write_coord_;
|
||||
/** Number of the probe to process in the select phase. */
|
||||
int reflection_probe_count_ = 0;
|
||||
|
||||
@@ -158,6 +224,11 @@ class ReflectionProbeModule {
|
||||
|
||||
void debug_print() const;
|
||||
|
||||
int atlas_extent() const
|
||||
{
|
||||
return probes_tx_.width();
|
||||
}
|
||||
|
||||
ReflectionProbeAtlasCoordinate world_atlas_coord_get() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1013,6 +1013,83 @@ BLI_STATIC_ASSERT_ALIGN(ShadowSceneData, 16)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Lightprobe Sphere
|
||||
* \{ */
|
||||
|
||||
struct ReflectionProbeLowFreqLight {
|
||||
packed_float3 direction;
|
||||
float ambient;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeLowFreqLight, 16)
|
||||
|
||||
enum LightProbeShape : uint32_t {
|
||||
SHAPE_ELIPSOID = 0u,
|
||||
SHAPE_CUBOID = 1u,
|
||||
};
|
||||
|
||||
struct ReflectionProbeCoordinate {
|
||||
/* Offset in UV space to the start of the sampling space of the octahedron map. */
|
||||
float2 offset;
|
||||
/* Scaling of the squared UV space of the octahedron map. */
|
||||
float scale;
|
||||
/* Layer of the atlas where the octahedron map is stored. */
|
||||
float layer;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeCoordinate, 16)
|
||||
|
||||
struct ReflectionProbeWriteCoordinate {
|
||||
/* Offset in pixel space to the start of the writing space of the octahedron map.
|
||||
* Note that the writing space is not the same as the sampling space as we have borders. */
|
||||
int2 offset;
|
||||
/* Size of the area in pixel that is covered by this probe mip-map. */
|
||||
int extent;
|
||||
/* Layer of the atlas where the octahedron map is stored. */
|
||||
int layer;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeWriteCoordinate, 16)
|
||||
|
||||
/** Mapping data to locate a reflection probe in texture. */
|
||||
struct ReflectionProbeData {
|
||||
/** Transform to probe local position with non-uniform scaling. */
|
||||
float3x4 world_to_probe_transposed;
|
||||
|
||||
packed_float3 location;
|
||||
float _pad2;
|
||||
|
||||
/** Shape of the parallax projection. */
|
||||
LightProbeShape parallax_shape;
|
||||
LightProbeShape influence_shape;
|
||||
float parallax_distance;
|
||||
/** Influence factor based on the distance to the parallax shape. */
|
||||
float influence_scale;
|
||||
float influence_bias;
|
||||
/** LOD factor for mipmap selection. */
|
||||
float lod_factor;
|
||||
float _pad0;
|
||||
float _pad1;
|
||||
|
||||
ReflectionProbeCoordinate atlas_coord;
|
||||
|
||||
/**
|
||||
* Irradiance at the probe location encoded as spherical harmonics.
|
||||
* Only contain the average luminance. Used for cube-map normalization.
|
||||
*/
|
||||
ReflectionProbeLowFreqLight low_freq_light;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeData, 16)
|
||||
|
||||
/** Viewport Display Pass. */
|
||||
struct ReflectionProbeDisplayData {
|
||||
int probe_index;
|
||||
float display_size;
|
||||
float _pad0;
|
||||
float _pad1;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeDisplayData, 16)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Irradiance Cache
|
||||
* \{ */
|
||||
@@ -1105,8 +1182,7 @@ struct CaptureInfoData {
|
||||
bool1 capture_emission;
|
||||
int _pad0;
|
||||
/* World light probe atlas coordinate. */
|
||||
/* TODO(fclem): Remove this silly aliasing. */
|
||||
int4 world_atlas_coord;
|
||||
ReflectionProbeCoordinate world_atlas_coord;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(CaptureInfoData, 16)
|
||||
|
||||
@@ -1323,77 +1399,9 @@ static inline float3 burley_eval(float3 d, float r)
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Reflection Probes
|
||||
/** \name Lightprobe Planar Data
|
||||
* \{ */
|
||||
|
||||
struct ReflectionProbeLowFreqLight {
|
||||
packed_float3 direction;
|
||||
float ambient;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeLowFreqLight, 16)
|
||||
|
||||
enum LightProbeShape : uint32_t {
|
||||
SHAPE_ELIPSOID = 0u,
|
||||
SHAPE_CUBOID = 1u,
|
||||
};
|
||||
|
||||
struct ReflectionProbeAtlasCoordinate {
|
||||
/** On which layer of the texture array is this reflection probe stored. */
|
||||
int layer;
|
||||
/**
|
||||
* Subdivision of the layer. 0 = no subdivision and resolution would be
|
||||
* ReflectionProbeModule::MAX_RESOLUTION.
|
||||
*/
|
||||
int layer_subdivision;
|
||||
/**
|
||||
* Which area of the subdivided layer is the reflection probe located.
|
||||
*
|
||||
* A layer has (2^layer_subdivision)^2 areas.
|
||||
*/
|
||||
int area_index;
|
||||
int _pad1;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeAtlasCoordinate, 16)
|
||||
|
||||
/** Mapping data to locate a reflection probe in texture. */
|
||||
struct ReflectionProbeData {
|
||||
/** Transform to probe local position with non-uniform scaling. */
|
||||
float3x4 world_to_probe_transposed;
|
||||
|
||||
packed_float3 location;
|
||||
float _pad2;
|
||||
|
||||
/** Shape of the parallax projection. */
|
||||
LightProbeShape parallax_shape;
|
||||
LightProbeShape influence_shape;
|
||||
float parallax_distance;
|
||||
/** Influence factor based on the distance to the parallax shape. */
|
||||
float influence_scale;
|
||||
float influence_bias;
|
||||
/** LOD factor for mipmap selection. */
|
||||
float lod_factor;
|
||||
float _pad0;
|
||||
float _pad1;
|
||||
|
||||
ReflectionProbeAtlasCoordinate atlas_coord;
|
||||
|
||||
/**
|
||||
* Irradiance at the probe location encoded as spherical harmonics.
|
||||
* Only contain the average luminance. Used for cube-map normalization.
|
||||
*/
|
||||
ReflectionProbeLowFreqLight low_freq_light;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeData, 16)
|
||||
|
||||
/** Viewport Display Pass. */
|
||||
struct ReflectionProbeDisplayData {
|
||||
int probe_index;
|
||||
float display_size;
|
||||
float _pad0;
|
||||
float _pad1;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeDisplayData, 16)
|
||||
|
||||
struct ProbePlanarData {
|
||||
/** Matrices used to render the planar capture. */
|
||||
float4x4 viewmat;
|
||||
@@ -1424,6 +1432,7 @@ struct ProbePlanarDisplayData {
|
||||
BLI_STATIC_ASSERT_ALIGN(ProbePlanarDisplayData, 16)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Pipeline Data
|
||||
* \{ */
|
||||
@@ -1437,6 +1446,7 @@ struct PipelineInfoData {
|
||||
BLI_STATIC_ASSERT_ALIGN(PipelineInfoData, 16)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Uniform Data
|
||||
* \{ */
|
||||
|
||||
@@ -67,10 +67,7 @@ void irradiance_capture_world(vec3 L, inout SphericalHarmonicL1 sh)
|
||||
float visibility = 0.0;
|
||||
|
||||
if (capture_info_buf.capture_world_direct) {
|
||||
ReflectionProbeAtlasCoordinate atlas_coord = reinterpret_as_atlas_coord(
|
||||
capture_info_buf.world_atlas_coord);
|
||||
|
||||
radiance = reflection_probes_sample(L, 0.0, atlas_coord).rgb;
|
||||
radiance = reflection_probes_sample(L, 0.0, capture_info_buf.world_atlas_coord).rgb;
|
||||
|
||||
/* Clamped brightness. */
|
||||
float luma = max(1e-8, reduce_max(radiance));
|
||||
|
||||
@@ -37,28 +37,6 @@ vec3 octahedral_uv_to_direction(vec2 co)
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the UV coordinates on the packed octahedral texture layer when applying the given
|
||||
* octahedral_uv to a specific probe.
|
||||
*/
|
||||
vec2 octahedral_uv_to_layer_texture_coords(vec2 octahedral_uv,
|
||||
ReflectionProbeAtlasCoordinate atlas_coord,
|
||||
vec2 texel_size)
|
||||
{
|
||||
/* Fix artifacts near edges. Proved one texel on each side. */
|
||||
octahedral_uv = octahedral_uv * (1.0 - 2.0 * REFLECTION_PROBE_BORDER_SIZE * texel_size) +
|
||||
REFLECTION_PROBE_BORDER_SIZE * texel_size + 0.5 * texel_size;
|
||||
|
||||
int areas_per_dimension = 1 << atlas_coord.layer_subdivision;
|
||||
vec2 area_scalar = vec2(1.0 / float(areas_per_dimension));
|
||||
octahedral_uv *= area_scalar;
|
||||
|
||||
vec2 area_offset = vec2(atlas_coord.area_index % areas_per_dimension,
|
||||
atlas_coord.area_index / areas_per_dimension) *
|
||||
area_scalar;
|
||||
return octahedral_uv + area_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the octahedral uv coordinates for the given texture uv coordinate on the packed
|
||||
* octahedral texture layer for the given probe.
|
||||
@@ -67,7 +45,6 @@ vec2 octahedral_uv_to_layer_texture_coords(vec2 octahedral_uv,
|
||||
* NOTE: Doesn't apply the translation part of the packing.
|
||||
*/
|
||||
vec2 octahedral_uv_from_layer_texture_coords(vec2 uv, vec2 texel_size)
|
||||
|
||||
{
|
||||
/* Apply border region. */
|
||||
vec2 shrinked_uv = (uv - REFLECTION_PROBE_BORDER_SIZE * texel_size) /
|
||||
@@ -78,14 +55,3 @@ vec2 octahedral_uv_from_layer_texture_coords(vec2 uv, vec2 texel_size)
|
||||
bool is_even = ((checker_pos.x + checker_pos.y) & 1) == 0;
|
||||
return is_even ? fract(shrinked_uv) : vec2(1.0) - fract(shrinked_uv);
|
||||
}
|
||||
|
||||
/* TODO(fclem): Find something better than this. Has no place here but its shared with files that
|
||||
* needs it. */
|
||||
ReflectionProbeAtlasCoordinate reinterpret_as_atlas_coord(ivec4 packed_coord)
|
||||
{
|
||||
ReflectionProbeAtlasCoordinate unpacked;
|
||||
unpacked.layer = packed_coord.x;
|
||||
unpacked.layer_subdivision = packed_coord.y;
|
||||
unpacked.area_index = packed_coord.z;
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
@@ -7,12 +7,9 @@
|
||||
#pragma BLENDER_REQUIRE(eevee_spherical_harmonics_lib.glsl)
|
||||
|
||||
#ifdef REFLECTION_PROBE
|
||||
vec4 reflection_probes_sample(vec3 L, float lod, ReflectionProbeAtlasCoordinate atlas_coord)
|
||||
vec4 reflection_probes_sample(vec3 L, float lod, ReflectionProbeCoordinate atlas_coord)
|
||||
{
|
||||
vec2 octahedral_uv_packed = octahedral_uv_from_direction(L);
|
||||
vec2 texel_size = vec2(1.0 / float(1 << (11 - atlas_coord.layer_subdivision)));
|
||||
vec2 octahedral_uv = octahedral_uv_to_layer_texture_coords(
|
||||
octahedral_uv_packed, atlas_coord, texel_size);
|
||||
vec2 octahedral_uv = octahedral_uv_from_direction(L) * atlas_coord.scale + atlas_coord.offset;
|
||||
return textureLod(reflection_probes_tx, vec3(octahedral_uv, atlas_coord.layer), lod);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,55 +6,58 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_octahedron_lib.glsl)
|
||||
|
||||
ivec2 probe_area_offset(ReflectionProbeAtlasCoordinate atlas_coord, ivec3 texture_size)
|
||||
ReflectionProbeCoordinate reinterpret_as_atlas_coord(ivec4 packed_coord)
|
||||
{
|
||||
ivec2 octahedral_size = ivec2(texture_size.x >> atlas_coord.layer_subdivision,
|
||||
texture_size.y >> atlas_coord.layer_subdivision);
|
||||
int probes_per_dimension = 1 << atlas_coord.layer_subdivision;
|
||||
ivec2 area_coord = ivec2(atlas_coord.area_index % probes_per_dimension,
|
||||
atlas_coord.area_index / probes_per_dimension);
|
||||
ivec2 area_offset = area_coord * octahedral_size;
|
||||
return area_offset;
|
||||
ReflectionProbeCoordinate unpacked;
|
||||
unpacked.offset = intBitsToFloat(packed_coord.xy);
|
||||
unpacked.scale = intBitsToFloat(packed_coord.z);
|
||||
unpacked.layer = intBitsToFloat(packed_coord.w);
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
ReflectionProbeWriteCoordinate reinterpret_as_write_coord(ivec4 packed_coord)
|
||||
{
|
||||
ReflectionProbeWriteCoordinate unpacked;
|
||||
unpacked.offset = packed_coord.xy;
|
||||
unpacked.extent = packed_coord.z;
|
||||
unpacked.layer = packed_coord.w;
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ReflectionProbeAtlasCoordinate probe_coord = reinterpret_as_atlas_coord(probe_coord_packed);
|
||||
ReflectionProbeAtlasCoordinate world_coord = reinterpret_as_atlas_coord(world_coord_packed);
|
||||
ReflectionProbeCoordinate sample_coord = reinterpret_as_atlas_coord(probe_coord_packed);
|
||||
ReflectionProbeWriteCoordinate write_coord = reinterpret_as_write_coord(write_coord_packed);
|
||||
ReflectionProbeWriteCoordinate world_coord = reinterpret_as_write_coord(world_coord_packed);
|
||||
|
||||
ivec3 texture_coord = ivec3(gl_GlobalInvocationID.xyz);
|
||||
ivec3 texture_size = imageSize(octahedral_img);
|
||||
/* Texel in probe. */
|
||||
ivec2 local_texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
ivec3 octahedral_coord = ivec3(gl_GlobalInvocationID.xyz);
|
||||
ivec2 octahedral_size = texture_size.xy >> probe_coord.layer_subdivision;
|
||||
/* Exit when pixel being written doesn't fit in the area reserved for the probe. */
|
||||
if (any(greaterThanEqual(octahedral_coord.xy, octahedral_size.xy))) {
|
||||
if (any(greaterThanEqual(local_texel, ivec2(write_coord.extent)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 texel_size = vec2(1.0) / vec2(octahedral_size);
|
||||
|
||||
vec2 uv = vec2(octahedral_coord.xy) / vec2(octahedral_size.xy);
|
||||
vec2 octahedral_uv = octahedral_uv_from_layer_texture_coords(uv, texel_size);
|
||||
vec3 R = octahedral_uv_to_direction(octahedral_uv);
|
||||
|
||||
vec4 col = textureLod(cubemap_tx, R, float(probe_coord.layer_subdivision));
|
||||
/* Texel in probe atlas. */
|
||||
ivec2 texel = local_texel + write_coord.offset;
|
||||
/* UV in probe atlas. */
|
||||
vec2 atlas_uv = (vec2(texel) + 0.5) / vec2(imageSize(atlas_dst_mip_img).xy);
|
||||
/* UV in sampling area. */
|
||||
vec2 sampling_uv = (atlas_uv - sample_coord.offset) / sample_coord.scale;
|
||||
/* Direction in world space. */
|
||||
vec3 direction = octahedral_uv_to_direction(sampling_uv);
|
||||
vec4 col = textureLod(cubemap_tx, direction, float(mip_level));
|
||||
|
||||
/* Convert transmittance to transparency. */
|
||||
col.a = 1.0 - col.a;
|
||||
|
||||
/* Composite world into reflection probes. */
|
||||
bool is_world = all(equal(probe_coord_packed, world_coord_packed));
|
||||
bool is_world = all(equal(write_coord_packed, world_coord_packed));
|
||||
if (!is_world && col.a != 1.0) {
|
||||
vec2 world_octahedral_size = vec2(texture_size.x >> world_coord.layer_subdivision,
|
||||
texture_size.y >> world_coord.layer_subdivision);
|
||||
ivec3 world_octahedral_coord = ivec3(ivec2(uv * world_octahedral_size), 0.0);
|
||||
ivec2 world_area_offset = probe_area_offset(world_coord, texture_size);
|
||||
vec4 world_col = imageLoad(
|
||||
octahedral_img, world_octahedral_coord + ivec3(world_area_offset, world_coord.layer));
|
||||
ivec2 world_texel = local_texel + world_coord.offset;
|
||||
vec4 world_col = imageLoad(atlas_src_mip_img, ivec3(world_texel, world_coord.layer));
|
||||
col.rgb = mix(world_col.rgb, col.rgb, col.a);
|
||||
}
|
||||
|
||||
ivec2 area_offset = probe_area_offset(probe_coord, texture_size);
|
||||
imageStore(octahedral_img, octahedral_coord + ivec3(area_offset, probe_coord.layer), col);
|
||||
imageStore(atlas_dst_mip_img, ivec3(texel, write_coord.layer), col);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,15 @@
|
||||
#pragma BLENDER_REQUIRE(eevee_octahedron_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||
|
||||
ReflectionProbeCoordinate reinterpret_as_atlas_coord(ivec4 packed_coord)
|
||||
{
|
||||
ReflectionProbeCoordinate unpacked;
|
||||
unpacked.offset = intBitsToFloat(packed_coord.xy);
|
||||
unpacked.scale = intBitsToFloat(packed_coord.z);
|
||||
unpacked.layer = intBitsToFloat(packed_coord.w);
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
void atlas_store(vec4 sh_coefficient, ivec2 atlas_coord, int layer)
|
||||
{
|
||||
for (int x = 0; x < IRRADIANCE_GRID_BRICK_SIZE; x++) {
|
||||
@@ -33,11 +42,8 @@ void main()
|
||||
cooef.L1.M0 = vec4(0.0);
|
||||
cooef.L1.Mp1 = vec4(0.0);
|
||||
|
||||
ReflectionProbeAtlasCoordinate atlas_coord = reinterpret_as_atlas_coord(world_coord_packed);
|
||||
const int subdivision_64 = 5;
|
||||
float layer_mipmap = clamp(
|
||||
subdivision_64 - atlas_coord.layer_subdivision, 0, REFLECTION_PROBE_MIPMAP_LEVELS);
|
||||
|
||||
ReflectionProbeCoordinate atlas_coord = reinterpret_as_atlas_coord(world_coord_packed);
|
||||
float layer_mipmap = 5;
|
||||
/* Perform multiple sample. */
|
||||
uint store_index = gl_LocalInvocationID.x;
|
||||
float total_samples = float(gl_WorkGroupSize.x * REFLECTION_PROBE_SH_SAMPLES_PER_GROUP);
|
||||
|
||||
@@ -88,10 +88,7 @@ void radiance_transfer_world(inout Surfel receiver, vec3 L)
|
||||
float visibility = 0.0;
|
||||
|
||||
if (capture_info_buf.capture_world_indirect) {
|
||||
ReflectionProbeAtlasCoordinate atlas_coord = reinterpret_as_atlas_coord(
|
||||
capture_info_buf.world_atlas_coord);
|
||||
|
||||
radiance = reflection_probes_sample(L, 0.0, atlas_coord).rgb;
|
||||
radiance = reflection_probes_sample(L, 0.0, capture_info_buf.world_atlas_coord).rgb;
|
||||
}
|
||||
|
||||
if (capture_info_buf.capture_visibility_indirect) {
|
||||
|
||||
@@ -20,9 +20,12 @@ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_data)
|
||||
GPU_SHADER_CREATE_INFO(eevee_reflection_probe_remap)
|
||||
.local_group_size(REFLECTION_PROBE_GROUP_SIZE, REFLECTION_PROBE_GROUP_SIZE)
|
||||
.push_constant(Type::IVEC4, "probe_coord_packed")
|
||||
.push_constant(Type::IVEC4, "write_coord_packed")
|
||||
.push_constant(Type::IVEC4, "world_coord_packed")
|
||||
.push_constant(Type::INT, "mip_level")
|
||||
.sampler(0, ImageType::FLOAT_CUBE, "cubemap_tx")
|
||||
.image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D_ARRAY, "octahedral_img")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "atlas_dst_mip_img")
|
||||
.image(1, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D_ARRAY, "atlas_src_mip_img")
|
||||
.compute_source("eevee_reflection_probe_remap_comp.glsl")
|
||||
.additional_info("eevee_shared")
|
||||
.do_static_compilation(true);
|
||||
|
||||
Reference in New Issue
Block a user