Eevee-next: Reflection Probe Packing #109688
No reviewers
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#109688
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "Jeroen-Bakker/blender:eevee-next-reflection-probe-packing"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
All probes (including the world background probe) are stored in a single texture. Each probe
can be of any resolution as long as it is a power of 2 and not larger than 2048. So valid options
are (2048x2048, 1024x1024, 512x512, etc).
Each probe can be stored in their own resolution and can be set by the user.
The probes are packed in an 2d texture array with the dimension of 2048*2048. The number of
layers depends on the actual needed layers. If more layers are needed the texture will be recreated.
This can happen when a new reflection probe is added, or an existing reflection probe is made visible
to the scene or its resolution is changed.
Octahedral mapping
Probes are rendered into a cubemap. To reduce memory needs and improve sampling performance the cubemap
is stored in octahedral mapping space. This is done in
eevee_reflection_probe_remap_comp.glsl
.The regular octahedral mapping has been extended to fix leakages at the edges of the texture
and to be able to be used on an atlas texture and by sampling the texture once.
To reduce sampling cost and improve the quality we add an border around the
octahedral map and extend the octahedral coordinates. This also allows us to
generate lower resolution mipmaps of the atlas texture using 2x2 box filtering
from a higher resolution.
Subdivisions and areas
Probes data are stored besides the texture. The data is used to find out where the probe is stored
in the texture. It is also used to find free space to store new probes.
For each probe the next data is stored:
probe in the layer can be determined. 0 would use the resolution of the texture (2048x2048). 1 divides the texture in 4 even areas of (1024x1024). 2 divides the texture in 16 areas of (512x512).
(2^layer_subdivision) * (2^layer_subdivision)
areas.This approach ensures that we can be flexible at storing probes with different
resolutions on the same layer. Lets see an example how that works
Example
Lets assume we have a world probe with the resolution of 1024x1024 and 2 reflection probes
with the resolution of 512x512. The resolution of the texture is 2048x2048. This could be
stored in the texture as follow
Visually:
Looking at the same data, but in subdivision level 1 would look like:
On subdivision level 1 there are 2 empty spaces left, the lower right part is allocated by probes with a higher subdivision. When wanting to allocate an area with subdivision 1 it would select area 0,1024,0 - 1023,2047,0.
Code-wise this is implemented by
ProbeLocationFinder
. ProbeLocationFinder can view a texture in agiven subdivision level and mark areas that are covered by probes. When finding a free spot it returns
the first empty area.
Notes
WIP: Eevee-next: Reflection Probe Packingto Eevee-next: Reflection Probe Packing@ -73,1 +75,4 @@
/* LightProbe->bake_resolution, World->bake_resolution. */
typedef enum eLightProbeBakeResolution {
LIGHT_PROBE_BAKE_RESOLUTION_64 = 6,
Consider removal or using less mipmap levels for small sizes.
@ -1025,0 +1038,4 @@
* TODO: remove this attribute when baking has been implemented.
* NOTE: alpha channel is not used, but here for alignment reasons.
*/
float4 color;
Use random color instead of adding dummy member to the struct
@ -1025,0 +1041,4 @@
float4 color;
packed_float3 pos;
/** On which layer of the cubemaps array is this reflection probe stored. */
Update documentation. Not a cubemap anymore
@ -1025,0 +1067,4 @@
/**
* Artistic control to change the intensity during evaluation phase.
*/
float intensity;
Remove that option for now.
@ -10,14 +10,23 @@
* \{ */
GPU_SHADER_CREATE_INFO(eevee_reflection_probe_data)
.storage_buf(REFLECTION_PROBE_BUF_SLOT,
Consider using UBO instead.
@ -74,0 +81,4 @@
LIGHT_PROBE_BAKE_RESOLUTION_512 = 9,
LIGHT_PROBE_BAKE_RESOLUTION_1024 = 10,
LIGHT_PROBE_BAKE_RESOLUTION_2048 = 11,
LIGHT_PROBE_BAKE_RESOLUTION_4096 = 12,
Remove item
@ -34,0 +73,4 @@
(1.0 - 2.0 * REFLECTION_PROBE_BORDER_SIZE * texel_size);
/* Mirror until the coordinates fit. */
/* Fix right side. */
Can we use a checkerboard to reduce the branches even more?
We could monitor the delta octahedral uvs
@ -289,0 +296,4 @@
if (!DNA_struct_elem_find(fd->filesdna, "World", "int", "bake_resolution")) {
LISTBASE_FOREACH (World *, world, &bmain->worlds) {
world->bake_resolution = LIGHT_PROBE_BAKE_RESOLUTION_1024;
I wouldn't call it
bake_resolution
because it isn't necessarily related to baking.Maybe
probe_resolution
is better for world andresolution
for lightprobes.@ -30,1 +30,4 @@
#define REFLECTION_PROBES_MAX 256
#define REFLECTION_PROBE_GROUP_SIZE 16
/* Number of additional pixels on the border of an octahedral map to reserve for fixing leakage.*/
#define REFLECTION_PROBE_BORDER_SIZE 16.0
make it
float(1 << (REFLECTION_PROBE_MIPMAP_LEVELS - 1))
@ -1025,0 +1027,4 @@
* \{ */
/** Mapping data to locate a reflection probe in texture. */
struct ReflectionProbeData {
Might be left to another PR, but one parameter that was omitted is the parallax shape and distance. Unfortunately, this means increasing the storage quite a bit to have a 3x4 matrix.
@ -1025,0 +1061,4 @@
};
BLI_STATIC_ASSERT_ALIGN(ReflectionProbeData, 16)
struct ReflectionProbeBuffer {
Do not use a wrapper struct. Use
UniformArrayBuffer<<ReflectionProbeData, REFLECTION_PROBES_MAX>
@ -34,2 +59,4 @@
pass.bind_texture("cubemap_tx", cubemap_tx_);
pass.bind_image("octahedral_img", probes_tx_);
pass.bind_ssbo(REFLECTION_PROBE_BUF_SLOT, data_buf_);
/* TODO this should be added in a subpass with the correct resolution to reduce overshooting
you can use
pass.dispatch(&dispatch_probe_pack_)
and set it insideremap_to_octahedral_projection
.@ -39,0 +188,4 @@
}
/**
* Utility class to find a location in the cubemap that can be used to store a new probe cubemap in
Check for all occurences of cubemap in the comments and see if you can change it to
texture
orprobe
.@ -39,0 +301,4 @@
bool regenerate_mipmaps_postponed = false;
for (ReflectionProbe &cubemap : probes_) {
cubemap.is_dirty |= resize_layers;
Having a bitwise operator on a bool feels weird.
@ -39,0 +384,4 @@
}
/* -------------------------------------------------------------------- */
/** \name World
Wrong naming. also maybe leave
ReflectionProbe::needs_update()
inside the header.@ -28,0 +32,4 @@
Type type = Type::Unused;
bool is_dirty = false;
It isn't clear what is the difference between
is_dirty
andis_probes_tx_dirty
.As far as I understand,
is_probes_tx_dirty
is true when mips needs to be reconstructed andis_dirty
when it needs to be rerendered.So maybe
do_render
anddo_mipmap
orupdate_render
andupdate_mipmap
.Either way, their comments should be clearer.
@ -28,0 +53,4 @@
*/
int index = -1;
bool needs_update() const;
Document function. It's not visible right away why would you need this over
is_dirty
when both are public.@ -39,2 +70,4 @@
Instance &instance_;
ReflectionProbeDataBuf data_buf_;
Vector<ReflectionProbe> probes_;
Why use a
Vector
here and not aMap<ObjectKey, ReflectionProbe>
like other modules? The linear search infind_or_insert
is a bit scary and seems to reimplement some logic already present inMap
.@ -215,6 +215,7 @@ void CaptureView::render()
view.sync(view_m4, win_m4);
inst_.pipelines.world.render(view);
}
GPU_texture_update_mipmap_chain(inst_.reflection_probes.cubemap_tx_);
Do you really need this since you create the LOD of the octahedral map?
The cubemap has a fix size of 1024x1024. When remapping a probe of 64x64 we want to use a different mipmap level so the light is more evenly spread. We could remove the mipmap and use a dynamic cubemap size. or leave it how it is now.
I do think the resolution should become dynamic, but would postpone that for the light probe rendering part. I will mention that in the PR description
@ -58,3 +64,1 @@
* the reflection probe patch. */
const float intensity_factor = 1.0;
out_specular += vec3(intensity_factor * l_col);
/* ReflectionProbeData doesn't contain any gabs, exit at first item that is invalid. */
Typo: gabs > gap
@ -28,0 +45,4 @@
/**
* Probes that aren't used during a draw can be cleared.
*/
bool is_used = false;
How is that not redundant with
type == Type::Unused
?Isn't the same. Shoudl clarify that this is for Type::Probe to detect if the probe is still in use.
@blender-bot build
@blender-bot build