WIP: eevee-next-world-irradiance #108304
@ -154,6 +154,7 @@ set(SRC
|
||||
engines/eevee_next/eevee_material.cc
|
||||
engines/eevee_next/eevee_motion_blur.cc
|
||||
engines/eevee_next/eevee_pipeline.cc
|
||||
engines/eevee_next/eevee_reflection_probes.cc
|
||||
engines/eevee_next/eevee_renderbuffers.cc
|
||||
engines/eevee_next/eevee_sampling.cc
|
||||
engines/eevee_next/eevee_shader.cc
|
||||
@ -294,6 +295,7 @@ set(SRC
|
||||
engines/eevee_next/eevee_material.hh
|
||||
engines/eevee_next/eevee_motion_blur.hh
|
||||
engines/eevee_next/eevee_pipeline.hh
|
||||
engines/eevee_next/eevee_reflection_probes.hh
|
||||
engines/eevee_next/eevee_renderbuffers.hh
|
||||
engines/eevee_next/eevee_sampling.hh
|
||||
engines/eevee_next/eevee_shader.hh
|
||||
@ -508,6 +510,7 @@ set(GLSL_SRC
|
||||
engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_motion_blur_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_nodetree_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_sampling_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl
|
||||
engines/eevee_next/shaders/eevee_shadow_lib.glsl
|
||||
|
@ -108,6 +108,7 @@
|
||||
#define SHADOW_ATLAS_TEX_SLOT 5
|
||||
#define SSS_TRANSMITTANCE_TEX_SLOT 6
|
||||
#define IRRADIANCE_ATLAS_TEX_SLOT 7
|
||||
#define REFLECTION_PROBE_TEX_SLOT 8
|
||||
/* Only during shadow rendering. */
|
||||
#define SHADOW_RENDER_MAP_SLOT 4
|
||||
|
||||
|
@ -70,6 +70,7 @@ void Instance::init(const int2 &output_res,
|
||||
motion_blur.init();
|
||||
main_view.init();
|
||||
irradiance_cache.init();
|
||||
reflection_probes.init();
|
||||
}
|
||||
|
||||
void Instance::init_light_bake(Depsgraph *depsgraph, draw::Manager *manager)
|
||||
@ -99,6 +100,7 @@ void Instance::init_light_bake(Depsgraph *depsgraph, draw::Manager *manager)
|
||||
shadows.init();
|
||||
main_view.init();
|
||||
irradiance_cache.init();
|
||||
reflection_probes.init();
|
||||
}
|
||||
|
||||
void Instance::set_time(float time)
|
||||
@ -146,6 +148,7 @@ void Instance::begin_sync()
|
||||
hiz_buffer.sync();
|
||||
main_view.sync();
|
||||
world.sync();
|
||||
reflection_probes.sync();
|
||||
film.sync();
|
||||
render_buffers.sync();
|
||||
irradiance_cache.sync();
|
||||
@ -514,6 +517,8 @@ void Instance::light_bake_irradiance(
|
||||
render_sync();
|
||||
manager->end_sync();
|
||||
|
||||
pipelines.world_probe.render();
|
||||
|
||||
irradiance_cache.bake.surfels_create(probe);
|
||||
irradiance_cache.bake.surfels_lights_eval();
|
||||
});
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "eevee_material.hh"
|
||||
#include "eevee_motion_blur.hh"
|
||||
#include "eevee_pipeline.hh"
|
||||
#include "eevee_reflection_probes.hh"
|
||||
#include "eevee_renderbuffers.hh"
|
||||
#include "eevee_sampling.hh"
|
||||
#include "eevee_shader.hh"
|
||||
@ -54,6 +55,7 @@ class Instance {
|
||||
PipelineModule pipelines;
|
||||
ShadowModule shadows;
|
||||
LightModule lights;
|
||||
ReflectionProbeModule reflection_probes;
|
||||
VelocityModule velocity;
|
||||
MotionBlurModule motion_blur;
|
||||
DepthOfField depth_of_field;
|
||||
@ -105,6 +107,7 @@ class Instance {
|
||||
pipelines(*this),
|
||||
shadows(*this),
|
||||
lights(*this),
|
||||
reflection_probes(*this),
|
||||
velocity(*this),
|
||||
motion_blur(*this),
|
||||
depth_of_field(*this),
|
||||
|
@ -6,6 +6,10 @@
|
||||
* \ingroup eevee
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup eevee
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_lightprobe_types.h"
|
||||
|
@ -56,6 +56,107 @@ void WorldPipeline::render(View &view)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name World Probe Pipeline
|
||||
* \{ */
|
||||
|
||||
void WorldProbePipeline::sync()
|
||||
{
|
||||
for (int face : IndexRange(6)) {
|
||||
CubemapSide &side = sides_[face];
|
||||
/* View */
|
||||
float4x4 view_m4 = cubeface_mat(face);
|
||||
float4x4 win_m4;
|
||||
cubeface_winmat_get(win_m4, 1.0f, 10.0f);
|
||||
side.view.sync(view_m4, win_m4);
|
||||
|
||||
side.cubemap_face_ps.init();
|
||||
side.cubemap_face_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS);
|
||||
}
|
||||
const int2 extent(1);
|
||||
constexpr eGPUTextureUsage usage = GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE;
|
||||
dummy_cryptomatte_tx_.ensure_2d(GPU_RGBA32F, extent, usage);
|
||||
dummy_renderpass_tx_.ensure_2d(GPU_RGBA16F, extent, usage);
|
||||
dummy_aov_color_tx_.ensure_2d_array(GPU_RGBA16F, extent, 1, usage);
|
||||
dummy_aov_value_tx_.ensure_2d_array(GPU_R16F, extent, 1, usage);
|
||||
|
||||
has_draw_commands_ = false;
|
||||
}
|
||||
|
||||
void WorldProbePipeline::sync(GPUMaterial *gpumat)
|
||||
{
|
||||
for (int face : IndexRange(6)) {
|
||||
sync(gpumat, face);
|
||||
}
|
||||
has_draw_commands_ = true;
|
||||
}
|
||||
|
||||
void WorldProbePipeline::sync(GPUMaterial *gpumat, int face)
|
||||
{
|
||||
Manager &manager = *inst_.manager;
|
||||
|
||||
CubemapSide &side = sides_[face];
|
||||
|
||||
/* Framebuffer. */
|
||||
Texture &cubemap = inst_.reflection_probes.cubemaps_tx_;
|
||||
side.cubemap_face_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE_CUBEFACE(cubemap, face));
|
||||
|
||||
ResourceHandle handle = manager.resource_handle(float4x4::identity());
|
||||
PassSimple &pass = side.cubemap_face_ps;
|
||||
|
||||
pass.framebuffer_set(&side.cubemap_face_fb);
|
||||
pass.material_set(manager, gpumat);
|
||||
pass.push_constant("world_opacity_fade", 1.0f);
|
||||
|
||||
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||
pass.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get());
|
||||
pass.bind_ubo(RBUFS_BUF_SLOT, &inst_.render_buffers.data);
|
||||
pass.bind_image("rp_normal_img", dummy_renderpass_tx_);
|
||||
pass.bind_image("rp_light_img", dummy_renderpass_tx_);
|
||||
pass.bind_image("rp_diffuse_color_img", dummy_renderpass_tx_);
|
||||
pass.bind_image("rp_specular_color_img", dummy_renderpass_tx_);
|
||||
pass.bind_image("rp_emission_img", dummy_renderpass_tx_);
|
||||
pass.bind_image("rp_cryptomatte_img", dummy_cryptomatte_tx_);
|
||||
pass.bind_image("rp_color_img", dummy_aov_color_tx_);
|
||||
pass.bind_image("rp_value_img", dummy_aov_value_tx_);
|
||||
/* Required by validation layers. */
|
||||
inst_.cryptomatte.bind_resources(&pass);
|
||||
|
||||
pass.bind_image("aov_color_img", dummy_aov_color_tx_);
|
||||
pass.bind_image("aov_value_img", dummy_aov_value_tx_);
|
||||
pass.bind_ssbo("aov_buf", &inst_.film.aovs_info);
|
||||
|
||||
pass.draw(DRW_cache_fullscreen_quad_get(), handle);
|
||||
|
||||
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
|
||||
void WorldProbePipeline::render()
|
||||
{
|
||||
if (!has_draw_commands_) {
|
||||
return;
|
||||
}
|
||||
GPUFrameBuffer *previous_framebuffer = GPU_framebuffer_active_get();
|
||||
|
||||
GPU_debug_group_begin("World.Probe");
|
||||
for (int face : IndexRange(6)) {
|
||||
sides_[face].render(inst_);
|
||||
}
|
||||
GPU_debug_group_end();
|
||||
|
||||
GPU_texture_update_mipmap_chain(inst_.reflection_probes.cubemaps_tx_);
|
||||
if (previous_framebuffer) {
|
||||
GPU_framebuffer_bind(previous_framebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldProbePipeline::CubemapSide::render(Instance &instance)
|
||||
{
|
||||
instance.manager->submit(cubemap_face_ps, view);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Shadow Pipeline
|
||||
*
|
||||
@ -372,6 +473,8 @@ void DeferredLayer::end_sync()
|
||||
inst_.sampling.bind_resources(&eval_light_ps_);
|
||||
inst_.hiz_buffer.bind_resources(&eval_light_ps_);
|
||||
inst_.irradiance_cache.bind_resources(&eval_light_ps_);
|
||||
inst_.reflection_probes.bind_resources(&eval_light_ps_);
|
||||
inst_.irradiance_cache.bind_resources(&eval_light_ps_);
|
||||
|
||||
eval_light_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
eval_light_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
|
@ -43,6 +43,56 @@ class WorldPipeline {
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name World Probe Pipeline
|
||||
*
|
||||
* Render reflection probe of the world background.
|
||||
* \{ */
|
||||
|
||||
class WorldProbePipeline {
|
||||
private:
|
||||
Instance &inst_;
|
||||
|
||||
Texture dummy_renderpass_tx_;
|
||||
Texture dummy_cryptomatte_tx_;
|
||||
Texture dummy_aov_color_tx_;
|
||||
Texture dummy_aov_value_tx_;
|
||||
|
||||
struct CubemapSide {
|
||||
PassSimple cubemap_face_ps;
|
||||
View view;
|
||||
Framebuffer cubemap_face_fb;
|
||||
void render(Instance &instance);
|
||||
};
|
||||
|
||||
/**
|
||||
* Keep track if the world probe needs to be updated. This should only be the case when the
|
||||
* world is updated. This flag is used to skip updating mipmaps when the world isn't changed.
|
||||
*/
|
||||
bool has_draw_commands_ = false;
|
||||
|
||||
CubemapSide sides_[6] = {
|
||||
{{"PosX"}, {"PosX"}},
|
||||
{{"NegX"}, {"NegX"}},
|
||||
{{"PosY"}, {"PosY"}},
|
||||
{{"NegY"}, {"NegY"}},
|
||||
{{"PosZ"}, {"PosZ"}},
|
||||
{{"NegZ"}, {"NegZ"}},
|
||||
};
|
||||
|
||||
public:
|
||||
WorldProbePipeline(Instance &inst) : inst_(inst){};
|
||||
|
||||
void sync();
|
||||
void sync(GPUMaterial *gpumat);
|
||||
void render();
|
||||
|
||||
private:
|
||||
void sync(GPUMaterial *gpumat, int face);
|
||||
}; // namespace blender::eevee
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Shadow Pass
|
||||
*
|
||||
@ -288,6 +338,7 @@ class UtilityTexture : public Texture {
|
||||
class PipelineModule {
|
||||
public:
|
||||
WorldPipeline world;
|
||||
WorldProbePipeline world_probe;
|
||||
DeferredPipeline deferred;
|
||||
ForwardPipeline forward;
|
||||
ShadowPipeline shadow;
|
||||
@ -297,13 +348,19 @@ class PipelineModule {
|
||||
|
||||
public:
|
||||
PipelineModule(Instance &inst)
|
||||
: world(inst), deferred(inst), forward(inst), shadow(inst), capture(inst){};
|
||||
: world(inst),
|
||||
world_probe(inst),
|
||||
deferred(inst),
|
||||
forward(inst),
|
||||
shadow(inst),
|
||||
capture(inst){};
|
||||
|
||||
void begin_sync()
|
||||
{
|
||||
deferred.begin_sync();
|
||||
forward.sync();
|
||||
shadow.sync();
|
||||
world_probe.sync();
|
||||
capture.sync();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,75 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. */
|
||||
|
||||
#include "eevee_reflection_probes.hh"
|
||||
#include "eevee_instance.hh"
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
void ReflectionProbeModule::init()
|
||||
{
|
||||
if (cubemaps_.is_empty()) {
|
||||
cubemaps_.reserve(MAX_PROBES);
|
||||
|
||||
/* Initialize the world cubemap. */
|
||||
ReflectionProbe world_cubemap;
|
||||
world_cubemap.type = ReflectionProbe::Type::World;
|
||||
world_cubemap.is_dirty = true;
|
||||
cubemaps_.append(world_cubemap);
|
||||
|
||||
cubemaps_tx_.ensure_cube_array(GPU_RGBA16F,
|
||||
MAX_RESOLUTION,
|
||||
MAX_PROBES,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT,
|
||||
NULL,
|
||||
MIPMAP_LEVELS);
|
||||
GPU_texture_mipmap_mode(cubemaps_tx_, true, true);
|
||||
|
||||
dummy_tx_.ensure_cube_array(
|
||||
GPU_RGBA16F, 1, 1, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, NULL, 1);
|
||||
dummy_tx_.clear(float4(0.0f));
|
||||
GPU_texture_mipmap_mode(dummy_tx_, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionProbeModule::sync()
|
||||
{
|
||||
for (int index : IndexRange(MAX_PROBES)) {
|
||||
ReflectionProbe &cubemap = cubemaps_[index];
|
||||
if (!cubemap.needs_update()) {
|
||||
continue;
|
||||
}
|
||||
sync(cubemap);
|
||||
cubemap.is_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionProbeModule::sync(const ReflectionProbe &cubemap)
|
||||
{
|
||||
if (cubemap.type == ReflectionProbe::Type::World) {
|
||||
GPUMaterial *world_material = instance_.world.get_world_material();
|
||||
instance_.pipelines.world_probe.sync(world_material);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionProbeModule::set_world_dirty()
|
||||
{
|
||||
cubemaps_[WORLD_SLOT].is_dirty = true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name World
|
||||
*
|
||||
* \{ */
|
||||
|
||||
bool ReflectionProbe::needs_update() const
|
||||
{
|
||||
return type != Type::Unused && is_dirty;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::eevee
|
@ -0,0 +1,96 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup eevee
|
||||
*
|
||||
* Cubemaps
|
||||
*
|
||||
* Cubemaps record light from different locations in the scene. These cubemaps are used to add
|
||||
* environment and indirect lighting from light probes.
|
||||
*
|
||||
* - Although we have Global illumination light probes can still be used for situations that
|
||||
* GI doesn't work. For example semi-transparent surfaces.
|
||||
* - The first cubemap is always reserved for the world shading.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "eevee_shader_shared.hh"
|
||||
|
||||
#include "BKE_cryptomatte.hh"
|
||||
|
||||
extern "C" {
|
||||
struct Material;
|
||||
}
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
class Instance;
|
||||
class WorldProbePipeline;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Reflection Probes
|
||||
* \{ */
|
||||
class ReflectionProbe {
|
||||
public:
|
||||
enum Type { Unused, World };
|
||||
|
||||
Type type;
|
||||
bool is_dirty = false;
|
||||
|
||||
bool needs_update() const;
|
||||
};
|
||||
|
||||
class ReflectionProbeModule {
|
||||
private:
|
||||
/** The max number of probes to track. */
|
||||
static constexpr int MAX_PROBES = 1;
|
||||
|
||||
/**
|
||||
* The maximum resolution of a cubemap side.
|
||||
*
|
||||
* Must be a power of two; intension to be used as a cubemap atlas.
|
||||
*/
|
||||
static constexpr int MAX_RESOLUTION = 2048;
|
||||
static constexpr int MIPMAP_LEVELS = 12;
|
||||
|
||||
/**
|
||||
* Index of the probe that is used for world background.
|
||||
*
|
||||
* NOTE: First probe always contains the world probe.
|
||||
*/
|
||||
static constexpr int WORLD_SLOT = 0;
|
||||
|
||||
Instance &instance_;
|
||||
|
||||
Vector<ReflectionProbe> cubemaps_;
|
||||
Texture cubemaps_tx_ = {"Probes"};
|
||||
Texture dummy_tx_ = {"DummyProbes"};
|
||||
|
||||
public:
|
||||
ReflectionProbeModule(Instance &instance) : instance_(instance) {}
|
||||
|
||||
void init();
|
||||
void set_world_dirty();
|
||||
|
||||
void sync();
|
||||
|
||||
template<typename T> void bind_resources(draw::detail::PassBase<T> *pass)
|
||||
{
|
||||
pass->bind_texture(REFLECTION_PROBE_TEX_SLOT, cubemaps_tx_);
|
||||
}
|
||||
|
||||
template<typename T> void bind_dummy_resources(draw::detail::PassBase<T> *pass)
|
||||
{
|
||||
pass->bind_texture(REFLECTION_PROBE_TEX_SLOT, dummy_tx_);
|
||||
}
|
||||
|
||||
private:
|
||||
void sync(const ReflectionProbe &cubemap);
|
||||
|
||||
friend class WorldProbePipeline;
|
||||
};
|
||||
|
||||
} // namespace blender::eevee
|
@ -118,6 +118,7 @@ void ShadingView::render()
|
||||
GPU_framebuffer_bind(combined_fb_);
|
||||
GPU_framebuffer_clear_color_depth(combined_fb_, clear_color, 1.0f);
|
||||
|
||||
inst_.pipelines.world_probe.render();
|
||||
inst_.pipelines.world.render(render_view_new_);
|
||||
|
||||
/* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */
|
||||
@ -125,8 +126,6 @@ void ShadingView::render()
|
||||
|
||||
inst_.pipelines.deferred.render(render_view_new_, prepass_fb_, combined_fb_, extent_);
|
||||
|
||||
// inst_.lightprobes.draw_cache_display();
|
||||
|
||||
// inst_.lookdev.render_overlay(view_fb_);
|
||||
|
||||
inst_.pipelines.forward.render(render_view_new_, prepass_fb_, combined_fb_, rbufs.combined_tx);
|
||||
|
@ -90,7 +90,7 @@ void World::sync()
|
||||
WorldHandle &wo_handle = inst_.sync.sync_world(bl_world);
|
||||
|
||||
if (wo_handle.recalc != 0) {
|
||||
// inst_.lightprobes.set_world_dirty();
|
||||
inst_.reflection_probes.set_world_dirty();
|
||||
}
|
||||
wo_handle.reset_recalc_flag();
|
||||
|
||||
@ -111,6 +111,21 @@ void World::sync()
|
||||
inst_.pipelines.world.sync(gpumat);
|
||||
}
|
||||
|
||||
GPUMaterial *World::get_world_material()
|
||||
{
|
||||
::World *bl_world = inst_.scene->world;
|
||||
if (bl_world == nullptr) {
|
||||
bl_world = default_world_get();
|
||||
}
|
||||
|
||||
bNodeTree *ntree = (bl_world->nodetree && bl_world->use_nodes) ?
|
||||
bl_world->nodetree :
|
||||
default_tree.nodetree_get(bl_world);
|
||||
|
||||
GPUMaterial *gpumat = inst_.shaders.world_shader_get(bl_world, ntree);
|
||||
return gpumat;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::eevee
|
||||
|
@ -62,6 +62,13 @@ class World {
|
||||
~World();
|
||||
|
||||
void sync();
|
||||
|
||||
/**
|
||||
* Get the world material.
|
||||
*
|
||||
* NOTE: this function should only be called after World::sync has been executed.
|
||||
*/
|
||||
GPUMaterial *get_world_material();
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
@ -10,6 +10,8 @@
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_reflection_probe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
@ -56,6 +58,8 @@ void main()
|
||||
|
||||
lightprobe_eval(diffuse_data, reflection_data, P, Ng, V, diffuse_light, reflection_light);
|
||||
|
||||
light_world_eval(reflection_data, P, V, reflection_light);
|
||||
|
||||
light_eval(diffuse_data,
|
||||
reflection_data,
|
||||
P,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#pragma BLENDER_REQUIRE(eevee_surfel_list_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(cubemap_lib.glsl)
|
||||
|
||||
void irradiance_capture(vec3 L, vec3 irradiance, inout SphericalHarmonicL1 sh)
|
||||
{
|
||||
@ -40,6 +41,11 @@ void irradiance_capture(Surfel surfel, vec3 P, inout SphericalHarmonicL1 sh)
|
||||
irradiance_capture(L, irradiance, sh);
|
||||
}
|
||||
|
||||
vec3 irradiance_sky_sample(vec3 R)
|
||||
{
|
||||
return textureLod_cubemapArray(reflectionProbes, vec4(R, 0.0), 0.0).rgb;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec3 grid_coord = ivec3(gl_GlobalInvocationID);
|
||||
@ -88,8 +94,8 @@ void main()
|
||||
irradiance_capture(surfel, P, sh);
|
||||
}
|
||||
else {
|
||||
/* TODO(fclem): Sky radiance. */
|
||||
irradiance_capture(sky_L, vec3(0.0), sh);
|
||||
vec3 world_radiance = irradiance_sky_sample(sky_L);
|
||||
irradiance_capture(sky_L, world_radiance, sh);
|
||||
}
|
||||
|
||||
if (surfel_prev > -1) {
|
||||
@ -97,8 +103,8 @@ void main()
|
||||
irradiance_capture(surfel, P, sh);
|
||||
}
|
||||
else {
|
||||
/* TODO(fclem): Sky radiance. */
|
||||
irradiance_capture(-sky_L, vec3(0.0), sh);
|
||||
vec3 world_radiance = irradiance_sky_sample(-sky_L);
|
||||
irradiance_capture(-sky_L, world_radiance, sh);
|
||||
}
|
||||
|
||||
/* Normalize for storage. We accumulated 2 samples. */
|
||||
|
@ -0,0 +1,12 @@
|
||||
void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 out_specular)
|
||||
{
|
||||
float linear_roughness = fast_sqrt(reflection.roughness);
|
||||
/* TODO: This should be based by actual resolution. Currently the resolution is fixed but
|
||||
* eventually this should based on a user setting. */
|
||||
float lod_cube_max = 12.0;
|
||||
float lod = linear_roughness * lod_cube_max;
|
||||
|
||||
vec3 R = -reflect(V, reflection.N);
|
||||
vec3 world_light = textureLod_cubemapArray(reflectionProbes, vec4(R, 0.0), lod).rgb;
|
||||
out_specular += world_light;
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(cubemap_lib.glsl)
|
||||
|
||||
void radiance_transfer(inout Surfel surfel, vec3 in_radiance, vec3 L)
|
||||
{
|
||||
@ -69,6 +70,11 @@ void radiance_transfer_world(inout Surfel receiver, vec3 sky_L)
|
||||
radiance_transfer(receiver, radiance, -sky_L);
|
||||
}
|
||||
|
||||
vec3 radiance_sky_sample(vec3 R)
|
||||
{
|
||||
return textureLod_cubemapArray(reflectionProbes, vec4(R, 0.0), 0.0).rgb;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int surfel_index = int(gl_GlobalInvocationID.x);
|
||||
@ -85,7 +91,8 @@ void main()
|
||||
radiance_transfer_surfel(surfel, surfel_next);
|
||||
}
|
||||
else {
|
||||
radiance_transfer_world(surfel, sky_L);
|
||||
vec3 world_radiance = radiance_sky_sample(sky_L);
|
||||
radiance_transfer(surfel, world_radiance, sky_L);
|
||||
}
|
||||
|
||||
if (surfel.prev > -1) {
|
||||
@ -93,7 +100,8 @@ void main()
|
||||
radiance_transfer_surfel(surfel, surfel_prev);
|
||||
}
|
||||
else {
|
||||
radiance_transfer_world(surfel, -sky_L);
|
||||
vec3 world_radiance = radiance_sky_sample(-sky_L);
|
||||
radiance_transfer(surfel, world_radiance, -sky_L);
|
||||
}
|
||||
|
||||
surfel_buf[surfel_index] = surfel;
|
||||
|
@ -38,6 +38,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light)
|
||||
"eevee_utility_texture",
|
||||
"eevee_light_data",
|
||||
"eevee_lightprobe_data",
|
||||
"eevee_reflection_probe_data",
|
||||
"eevee_shadow_data",
|
||||
"eevee_deferred_base",
|
||||
"eevee_transmittance_data",
|
||||
|
@ -83,7 +83,10 @@ GPU_SHADER_CREATE_INFO(eevee_surfel_list_sort)
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_surfel_ray)
|
||||
.local_group_size(SURFEL_GROUP_SIZE)
|
||||
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
|
||||
.additional_info("eevee_shared",
|
||||
"eevee_surfel_common",
|
||||
"eevee_reflection_probe_data",
|
||||
"draw_view")
|
||||
.push_constant(Type::INT, "radiance_src")
|
||||
.push_constant(Type::INT, "radiance_dst")
|
||||
.compute_source("eevee_surfel_ray_comp.glsl")
|
||||
@ -103,7 +106,10 @@ GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_ray)
|
||||
.local_group_size(IRRADIANCE_GRID_GROUP_SIZE,
|
||||
IRRADIANCE_GRID_GROUP_SIZE,
|
||||
IRRADIANCE_GRID_GROUP_SIZE)
|
||||
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
|
||||
.additional_info("eevee_shared",
|
||||
"eevee_surfel_common",
|
||||
"eevee_reflection_probe_data",
|
||||
"draw_view")
|
||||
.push_constant(Type::INT, "radiance_src")
|
||||
.storage_buf(0, Qualifier::READ, "int", "list_start_buf[]")
|
||||
.storage_buf(6, Qualifier::READ, "SurfelListInfoData", "list_info_buf")
|
||||
|
@ -0,0 +1,11 @@
|
||||
#include "eevee_defines.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Shared
|
||||
* \{ */
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_reflection_probe_data)
|
||||
.sampler(REFLECTION_PROBE_TEX_SLOT, ImageType::FLOAT_CUBE_ARRAY, "reflectionProbes");
|
||||
|
||||
/** \} */
|
@ -691,7 +691,7 @@ class Texture : NonCopyable {
|
||||
float *data = nullptr,
|
||||
int mip_len = 1)
|
||||
{
|
||||
return ensure_impl(extent, extent, layers, mip_len, format, usage, data, false, true);
|
||||
return ensure_impl(extent, extent, layers, mip_len, format, usage, data, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -651,6 +651,7 @@ set(SRC_SHADER_CREATE_INFOS
|
||||
../draw/engines/eevee_next/shaders/infos/eevee_light_culling_info.hh
|
||||
../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
|
||||
../draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh
|
||||
../draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh
|
||||
../draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh
|
||||
../draw/engines/eevee_next/shaders/infos/eevee_subsurface_info.hh
|
||||
../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
|
||||
|
@ -895,6 +895,11 @@ static char *glsl_patch_compute_get()
|
||||
STR_CONCAT(patch, slen, "#version 430\n");
|
||||
STR_CONCAT(patch, slen, "#extension GL_ARB_compute_shader :enable\n");
|
||||
|
||||
if (GLContext::texture_cube_map_array_support) {
|
||||
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n");
|
||||
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n");
|
||||
}
|
||||
|
||||
/* Array compat. */
|
||||
STR_CONCAT(patch, slen, "#define gpu_Array(_type) _type[]\n");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user