EEVEE-Next: Deferred Pipeline #105868
@ -429,6 +429,7 @@ set(GLSL_SRC
|
|||||||
engines/eevee_next/shaders/eevee_transparency_lib.glsl
|
engines/eevee_next/shaders/eevee_transparency_lib.glsl
|
||||||
engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl
|
engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl
|
||||||
engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl
|
engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl
|
||||||
|
engines/eevee_next/shaders/eevee_deferred_light_frag.glsl
|
||||||
engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl
|
engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl
|
||||||
engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl
|
engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl
|
||||||
engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl
|
engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl
|
||||||
@ -448,6 +449,7 @@ set(GLSL_SRC
|
|||||||
engines/eevee_next/shaders/eevee_film_cryptomatte_post_comp.glsl
|
engines/eevee_next/shaders/eevee_film_cryptomatte_post_comp.glsl
|
||||||
engines/eevee_next/shaders/eevee_film_frag.glsl
|
engines/eevee_next/shaders/eevee_film_frag.glsl
|
||||||
engines/eevee_next/shaders/eevee_film_lib.glsl
|
engines/eevee_next/shaders/eevee_film_lib.glsl
|
||||||
|
engines/eevee_next/shaders/eevee_gbuffer_lib.glsl
|
||||||
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
|
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
|
||||||
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
|
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
|
||||||
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
|
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
|
||||||
|
@ -105,6 +105,9 @@
|
|||||||
#define RBUFS_AOV_COLOR_SLOT 5
|
#define RBUFS_AOV_COLOR_SLOT 5
|
||||||
#define RBUFS_AOV_VALUE_SLOT 6
|
#define RBUFS_AOV_VALUE_SLOT 6
|
||||||
#define RBUFS_CRYPTOMATTE_SLOT 7
|
#define RBUFS_CRYPTOMATTE_SLOT 7
|
||||||
|
/* G-buffer reuses render passes slots. */
|
||||||
|
#define GBUF_CLOSURE_SLOT RBUFS_LIGHT_SLOT
|
||||||
|
#define GBUF_COLOR_SLOT RBUFS_DIFF_COLOR_SLOT
|
||||||
|
|
||||||
/* Uniform Buffers. */
|
/* Uniform Buffers. */
|
||||||
/* Only during prepass. */
|
/* Only during prepass. */
|
||||||
|
@ -649,7 +649,7 @@ void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx)
|
|||||||
|
|
||||||
draw::View drw_view("MainView", view);
|
draw::View drw_view("MainView", view);
|
||||||
|
|
||||||
DRW_manager_get()->submit(accumulate_ps_, drw_view);
|
inst_.manager->submit(accumulate_ps_, drw_view);
|
||||||
|
|
||||||
combined_tx_.swap();
|
combined_tx_.swap();
|
||||||
weight_tx_.swap();
|
weight_tx_.swap();
|
||||||
|
89
source/blender/draw/engines/eevee_next/eevee_gbuffer.hh
Normal file
89
source/blender/draw/engines/eevee_next/eevee_gbuffer.hh
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup eevee
|
||||||
|
*
|
||||||
|
* Gbuffer layout used for deferred shading pipeline.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DRW_render.h"
|
||||||
|
|
||||||
|
#include "eevee_material.hh"
|
||||||
|
#include "eevee_shader_shared.hh"
|
||||||
|
|
||||||
|
namespace blender::eevee {
|
||||||
|
|
||||||
|
class Instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fullscreen textures containing geometric and surface data.
|
||||||
|
* Used by deferred shading passes. Only one gbuffer is allocated per view
|
||||||
|
* and is reused for each deferred layer. This is why there can only be temporary
|
||||||
|
* texture inside it.
|
||||||
|
*
|
||||||
|
* Everything is stored inside two array texture, one for each format. This is to fit the
|
||||||
|
* limitation of the number of images we can bind on a single shader.
|
||||||
|
*
|
||||||
|
* First layer is always for reflection. All parameters to shoot a reflection ray are inside
|
||||||
|
* this layer.
|
||||||
|
*
|
||||||
|
* - Layer 1 : Reflection
|
||||||
|
* - R : Normal packed X
|
||||||
|
* - G : Normal packed Y
|
||||||
|
* - B : Roughness
|
||||||
|
* - A : Unused (Could be used for anisotropic roughness)
|
||||||
|
*
|
||||||
|
* Second layer is either for diffuse or transmission. Material mixing both are not
|
||||||
|
* physically based and are uncommon. So in order to save bandwidth and texture memory, we only
|
||||||
|
* store one. We use random sampling to mix between both. All parameters to shoot a refraction
|
||||||
|
* ray are inside this layer.
|
||||||
|
*
|
||||||
|
* - Layer 2 : Refraction
|
||||||
|
* - R : Normal packed X
|
||||||
|
* - G : Normal packed Y
|
||||||
|
* - B : Roughness (isotropic)
|
||||||
|
* - A : IOR
|
||||||
|
*
|
||||||
|
* - Layer 2 : Diffuse / Sub-Surface Scattering
|
||||||
|
* - R : Normal packed X
|
||||||
|
* - G : Normal packed Y
|
||||||
|
* - B : Thickness
|
||||||
|
* - A : Unused (Could be used for diffuse roughness)
|
||||||
|
*
|
||||||
|
* Layer 3 is only allocated if Sub-Surface Scattering is needed. All parameters for
|
||||||
|
* screen-space scattering are inside this layer.
|
||||||
|
*
|
||||||
|
* - Layer 3 : Sub-Surface Scattering
|
||||||
|
* - R : Scattering radius R
|
||||||
|
* - G : Scattering radius G
|
||||||
|
* - B : Scattering radius B
|
||||||
|
* - A : Object ID
|
||||||
|
*
|
||||||
|
* For each output closure, we also output the color to apply after the lighting computation.
|
||||||
|
* The color is stored with a 2 exponent that allows input color with component higher than 1.
|
||||||
|
* Color degradation is expected to happen in this case.
|
||||||
|
*/
|
||||||
|
struct GBuffer {
|
||||||
|
/* TODO(fclem): Use texture from pool once they support texture array. */
|
||||||
|
Texture closure_tx = {"GbufferClosure"};
|
||||||
|
Texture color_tx = {"GbufferColor"};
|
||||||
|
|
||||||
|
void acquire(int2 extent, eClosureBits closure_bits_)
|
||||||
|
{
|
||||||
|
const bool use_sss = (closure_bits_ & CLOSURE_SSS) != 0;
|
||||||
|
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
|
||||||
|
closure_tx.ensure_2d_array(GPU_RGBA16, extent, use_sss ? 3 : 2, usage);
|
||||||
|
color_tx.ensure_2d_array(GPU_RGB10_A2, extent, 2, usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
/* TODO(fclem): Use texture from pool once they support texture array. */
|
||||||
|
// closure_tx.release();
|
||||||
|
// color_tx.release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace blender::eevee
|
@ -105,6 +105,7 @@ void Instance::begin_sync()
|
|||||||
velocity.begin_sync(); /* NOTE: Also syncs camera. */
|
velocity.begin_sync(); /* NOTE: Also syncs camera. */
|
||||||
lights.begin_sync();
|
lights.begin_sync();
|
||||||
shadows.begin_sync();
|
shadows.begin_sync();
|
||||||
|
pipelines.begin_sync();
|
||||||
cryptomatte.begin_sync();
|
cryptomatte.begin_sync();
|
||||||
|
|
||||||
gpencil_engine_enabled = false;
|
gpencil_engine_enabled = false;
|
||||||
@ -114,7 +115,6 @@ void Instance::begin_sync()
|
|||||||
depth_of_field.sync();
|
depth_of_field.sync();
|
||||||
motion_blur.sync();
|
motion_blur.sync();
|
||||||
hiz_buffer.sync();
|
hiz_buffer.sync();
|
||||||
pipelines.sync();
|
|
||||||
main_view.sync();
|
main_view.sync();
|
||||||
world.sync();
|
world.sync();
|
||||||
film.sync();
|
film.sync();
|
||||||
@ -206,6 +206,7 @@ void Instance::end_sync()
|
|||||||
sampling.end_sync();
|
sampling.end_sync();
|
||||||
film.end_sync();
|
film.end_sync();
|
||||||
cryptomatte.end_sync();
|
cryptomatte.end_sync();
|
||||||
|
pipelines.end_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::render_sync()
|
void Instance::render_sync()
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "eevee_cryptomatte.hh"
|
#include "eevee_cryptomatte.hh"
|
||||||
#include "eevee_depth_of_field.hh"
|
#include "eevee_depth_of_field.hh"
|
||||||
#include "eevee_film.hh"
|
#include "eevee_film.hh"
|
||||||
|
#include "eevee_gbuffer.hh"
|
||||||
#include "eevee_hizbuffer.hh"
|
#include "eevee_hizbuffer.hh"
|
||||||
#include "eevee_irradiance_cache.hh"
|
#include "eevee_irradiance_cache.hh"
|
||||||
#include "eevee_light.hh"
|
#include "eevee_light.hh"
|
||||||
@ -54,6 +55,7 @@ class Instance {
|
|||||||
MotionBlurModule motion_blur;
|
MotionBlurModule motion_blur;
|
||||||
DepthOfField depth_of_field;
|
DepthOfField depth_of_field;
|
||||||
Cryptomatte cryptomatte;
|
Cryptomatte cryptomatte;
|
||||||
|
GBuffer gbuffer;
|
||||||
HiZBuffer hiz_buffer;
|
HiZBuffer hiz_buffer;
|
||||||
Sampling sampling;
|
Sampling sampling;
|
||||||
Camera camera;
|
Camera camera;
|
||||||
|
@ -193,11 +193,6 @@ MaterialPass MaterialModule::material_pass_get(Object *ob,
|
|||||||
inst_.sampling.reset();
|
inst_.sampling.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pipeline_type == MAT_PIPE_DEFERRED) &&
|
|
||||||
GPU_material_flag_get(matpass.gpumat, GPU_MATFLAG_SHADER_TO_RGBA)) {
|
|
||||||
pipeline_type = MAT_PIPE_FORWARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ELEM(pipeline_type,
|
if (ELEM(pipeline_type,
|
||||||
MAT_PIPE_FORWARD,
|
MAT_PIPE_FORWARD,
|
||||||
MAT_PIPE_FORWARD_PREPASS,
|
MAT_PIPE_FORWARD_PREPASS,
|
||||||
@ -240,10 +235,6 @@ Material &MaterialModule::material_sync(Object *ob,
|
|||||||
(has_motion ? MAT_PIPE_DEFERRED_PREPASS_VELOCITY :
|
(has_motion ? MAT_PIPE_DEFERRED_PREPASS_VELOCITY :
|
||||||
MAT_PIPE_DEFERRED_PREPASS);
|
MAT_PIPE_DEFERRED_PREPASS);
|
||||||
|
|
||||||
/* TEST until we have deferred pipeline up and running. */
|
|
||||||
surface_pipe = MAT_PIPE_FORWARD;
|
|
||||||
prepass_pipe = has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY : MAT_PIPE_FORWARD_PREPASS;
|
|
||||||
|
|
||||||
MaterialKey material_key(blender_mat, geometry_type, surface_pipe);
|
MaterialKey material_key(blender_mat, geometry_type, surface_pipe);
|
||||||
|
|
||||||
Material &mat = material_map_.lookup_or_add_cb(material_key, [&]() {
|
Material &mat = material_map_.lookup_or_add_cb(material_key, [&]() {
|
||||||
|
@ -278,4 +278,229 @@ void ForwardPipeline::render(View &view,
|
|||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Deferred Layer
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
void DeferredLayer::begin_sync()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
prepass_ps_.init();
|
||||||
|
{
|
||||||
|
/* Common resources. */
|
||||||
|
|
||||||
|
/* Textures. */
|
||||||
|
prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||||
|
/* Uniform Buf. */
|
||||||
|
prepass_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get());
|
||||||
|
|
||||||
|
inst_.velocity.bind_resources(&prepass_ps_);
|
||||||
|
inst_.sampling.bind_resources(&prepass_ps_);
|
||||||
|
}
|
||||||
|
|
||||||
|
DRWState state_depth_only = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
|
||||||
|
DRWState state_depth_color = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS |
|
||||||
|
DRW_STATE_WRITE_COLOR;
|
||||||
|
|
||||||
|
prepass_double_sided_static_ps_ = &prepass_ps_.sub("DoubleSided.Static");
|
||||||
|
prepass_double_sided_static_ps_->state_set(state_depth_only);
|
||||||
|
|
||||||
|
prepass_single_sided_static_ps_ = &prepass_ps_.sub("SingleSided.Static");
|
||||||
|
prepass_single_sided_static_ps_->state_set(state_depth_only | DRW_STATE_CULL_BACK);
|
||||||
|
|
||||||
|
prepass_double_sided_moving_ps_ = &prepass_ps_.sub("DoubleSided.Moving");
|
||||||
|
prepass_double_sided_moving_ps_->state_set(state_depth_color);
|
||||||
|
|
||||||
|
prepass_single_sided_moving_ps_ = &prepass_ps_.sub("SingleSided.Moving");
|
||||||
|
prepass_single_sided_moving_ps_->state_set(state_depth_color | DRW_STATE_CULL_BACK);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
gbuffer_ps_.init();
|
||||||
|
gbuffer_ps_.clear_stencil(0x00u);
|
||||||
|
gbuffer_ps_.state_stencil(0x01u, 0x01u, 0x01u);
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Common resources. */
|
||||||
|
|
||||||
|
/* G-buffer. */
|
||||||
|
gbuffer_ps_.bind_image(GBUF_CLOSURE_SLOT, &inst_.gbuffer.closure_tx);
|
||||||
|
gbuffer_ps_.bind_image(GBUF_COLOR_SLOT, &inst_.gbuffer.color_tx);
|
||||||
|
/* RenderPasses. */
|
||||||
|
gbuffer_ps_.bind_image(RBUFS_NORMAL_SLOT, &inst_.render_buffers.normal_tx);
|
||||||
|
/* TODO(fclem): Pack all render pass into the same texture. */
|
||||||
|
// gbuffer_ps_.bind_image(RBUFS_DIFF_COLOR_SLOT, &inst_.render_buffers.diffuse_color_tx);
|
||||||
|
gbuffer_ps_.bind_image(RBUFS_SPEC_COLOR_SLOT, &inst_.render_buffers.specular_color_tx);
|
||||||
|
gbuffer_ps_.bind_image(RBUFS_EMISSION_SLOT, &inst_.render_buffers.emission_tx);
|
||||||
|
/* AOVs. */
|
||||||
|
gbuffer_ps_.bind_image(RBUFS_AOV_COLOR_SLOT, &inst_.render_buffers.aov_color_tx);
|
||||||
|
gbuffer_ps_.bind_image(RBUFS_AOV_VALUE_SLOT, &inst_.render_buffers.aov_value_tx);
|
||||||
|
/* Cryptomatte. */
|
||||||
|
gbuffer_ps_.bind_image(RBUFS_CRYPTOMATTE_SLOT, &inst_.render_buffers.cryptomatte_tx);
|
||||||
|
/* Storage Buf. */
|
||||||
|
gbuffer_ps_.bind_ssbo(RBUFS_AOV_BUF_SLOT, &inst_.film.aovs_info);
|
||||||
|
/* Textures. */
|
||||||
|
gbuffer_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||||
|
/* Uniform Buf. */
|
||||||
|
gbuffer_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get());
|
||||||
|
|
||||||
|
inst_.sampling.bind_resources(&gbuffer_ps_);
|
||||||
|
inst_.cryptomatte.bind_resources(&gbuffer_ps_);
|
||||||
|
}
|
||||||
|
|
||||||
|
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_EQUAL |
|
||||||
|
DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
|
||||||
|
|
||||||
|
gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided");
|
||||||
|
gbuffer_double_sided_ps_->state_set(state);
|
||||||
|
|
||||||
|
gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided");
|
||||||
|
gbuffer_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeferredLayer::end_sync()
|
||||||
|
{
|
||||||
|
/* Use stencil test to reject pixel not written by this layer. */
|
||||||
|
/* WORKAROUND: Stencil write is only here to avoid rasterizer discard. */
|
||||||
|
DRWState state = DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_EQUAL;
|
||||||
|
/* Allow output to combined pass for the last pass. */
|
||||||
|
DRWState state_write_color = state | DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
|
||||||
|
|
||||||
|
if (closure_bits_ & (CLOSURE_DIFFUSE | CLOSURE_REFLECTION)) {
|
||||||
|
const bool is_last_eval_pass = true;
|
||||||
|
|
||||||
|
eval_light_ps_.init();
|
||||||
|
eval_light_ps_.state_set(is_last_eval_pass ? state_write_color : state);
|
||||||
|
eval_light_ps_.state_stencil(0x00u, 0x01u, 0xFFu);
|
||||||
|
eval_light_ps_.shader_set(inst_.shaders.static_shader_get(DEFERRED_LIGHT));
|
||||||
|
eval_light_ps_.bind_image("out_diffuse_light_img", &diffuse_light_tx_);
|
||||||
|
eval_light_ps_.bind_image("out_specular_light_img", &specular_light_tx_);
|
||||||
|
eval_light_ps_.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx);
|
||||||
|
eval_light_ps_.bind_texture("gbuffer_color_tx", &inst_.gbuffer.color_tx);
|
||||||
|
eval_light_ps_.push_constant("is_last_eval_pass", is_last_eval_pass);
|
||||||
|
eval_light_ps_.bind_image(RBUFS_LIGHT_SLOT, &inst_.render_buffers.light_tx);
|
||||||
|
eval_light_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
|
||||||
|
|
||||||
|
inst_.lights.bind_resources(&eval_light_ps_);
|
||||||
|
inst_.shadows.bind_resources(&eval_light_ps_);
|
||||||
|
inst_.sampling.bind_resources(&eval_light_ps_);
|
||||||
|
inst_.hiz_buffer.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PassMain::Sub *DeferredLayer::prepass_add(::Material *blender_mat,
|
||||||
|
GPUMaterial *gpumat,
|
||||||
|
bool has_motion)
|
||||||
|
{
|
||||||
|
PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ?
|
||||||
|
(has_motion ? prepass_single_sided_moving_ps_ :
|
||||||
|
prepass_single_sided_static_ps_) :
|
||||||
|
(has_motion ? prepass_double_sided_moving_ps_ :
|
||||||
|
prepass_double_sided_static_ps_);
|
||||||
|
|
||||||
|
return &pass->sub(GPU_material_get_name(gpumat));
|
||||||
|
}
|
||||||
|
|
||||||
|
PassMain::Sub *DeferredLayer::material_add(::Material *blender_mat, GPUMaterial *gpumat)
|
||||||
|
{
|
||||||
|
closure_bits_ |= shader_closure_bits_from_flag(gpumat);
|
||||||
|
|
||||||
|
PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ?
|
||||||
|
gbuffer_single_sided_ps_ :
|
||||||
|
gbuffer_double_sided_ps_;
|
||||||
|
return &pass->sub(GPU_material_get_name(gpumat));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeferredLayer::render(View &view,
|
||||||
|
Framebuffer &prepass_fb,
|
||||||
|
Framebuffer &combined_fb,
|
||||||
|
int2 extent)
|
||||||
|
{
|
||||||
|
|
||||||
|
GPU_framebuffer_bind(prepass_fb);
|
||||||
|
inst_.manager->submit(prepass_ps_, view);
|
||||||
|
|
||||||
|
inst_.hiz_buffer.set_dirty();
|
||||||
|
inst_.shadows.set_view(view);
|
||||||
|
|
||||||
|
inst_.gbuffer.acquire(extent, closure_bits_);
|
||||||
|
|
||||||
|
GPU_framebuffer_bind(combined_fb);
|
||||||
|
inst_.manager->submit(gbuffer_ps_, view);
|
||||||
|
|
||||||
|
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
|
||||||
|
diffuse_light_tx_.acquire(extent, GPU_RGBA16F, usage);
|
||||||
|
specular_light_tx_.acquire(extent, GPU_RGBA16F, usage);
|
||||||
|
diffuse_light_tx_.clear(float4(0.0f));
|
||||||
|
specular_light_tx_.clear(float4(0.0f));
|
||||||
|
|
||||||
|
inst_.manager->submit(eval_light_ps_, view);
|
||||||
|
|
||||||
|
diffuse_light_tx_.release();
|
||||||
|
specular_light_tx_.release();
|
||||||
|
|
||||||
|
inst_.gbuffer.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Deferred Pipeline
|
||||||
|
*
|
||||||
|
* Closure data are written to intermediate buffer allowing screen space processing.
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
void DeferredPipeline::begin_sync()
|
||||||
|
{
|
||||||
|
opaque_layer_.begin_sync();
|
||||||
|
refraction_layer_.begin_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeferredPipeline::end_sync()
|
||||||
|
{
|
||||||
|
opaque_layer_.end_sync();
|
||||||
|
refraction_layer_.end_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
PassMain::Sub *DeferredPipeline::prepass_add(::Material *blender_mat,
|
||||||
|
GPUMaterial *gpumat,
|
||||||
|
bool has_motion)
|
||||||
|
{
|
||||||
|
if (blender_mat->blend_flag & MA_BL_SS_REFRACTION) {
|
||||||
|
return refraction_layer_.prepass_add(blender_mat, gpumat, has_motion);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return opaque_layer_.prepass_add(blender_mat, gpumat, has_motion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PassMain::Sub *DeferredPipeline::material_add(::Material *blender_mat, GPUMaterial *gpumat)
|
||||||
|
{
|
||||||
|
if (blender_mat->blend_flag & MA_BL_SS_REFRACTION) {
|
||||||
|
return refraction_layer_.material_add(blender_mat, gpumat);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return opaque_layer_.material_add(blender_mat, gpumat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeferredPipeline::render(View &view,
|
||||||
|
Framebuffer &prepass_fb,
|
||||||
|
Framebuffer &combined_fb,
|
||||||
|
int2 extent)
|
||||||
|
{
|
||||||
|
DRW_stats_group_start("Deferred.Opaque");
|
||||||
|
opaque_layer_.render(view, prepass_fb, combined_fb, extent);
|
||||||
|
DRW_stats_group_end();
|
||||||
|
|
||||||
|
DRW_stats_group_start("Deferred.Refract");
|
||||||
|
refraction_layer_.render(view, prepass_fb, combined_fb, extent);
|
||||||
|
DRW_stats_group_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
} // namespace blender::eevee
|
} // namespace blender::eevee
|
||||||
|
@ -113,6 +113,77 @@ class ForwardPipeline {
|
|||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Deferred lighting.
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
class DeferredLayer {
|
||||||
|
private:
|
||||||
|
Instance &inst_;
|
||||||
|
|
||||||
|
PassMain prepass_ps_ = {"Prepass"};
|
||||||
|
PassMain::Sub *prepass_single_sided_static_ps_ = nullptr;
|
||||||
|
PassMain::Sub *prepass_single_sided_moving_ps_ = nullptr;
|
||||||
|
PassMain::Sub *prepass_double_sided_static_ps_ = nullptr;
|
||||||
|
PassMain::Sub *prepass_double_sided_moving_ps_ = nullptr;
|
||||||
|
|
||||||
|
PassMain gbuffer_ps_ = {"Shading"};
|
||||||
|
PassMain::Sub *gbuffer_single_sided_ps_ = nullptr;
|
||||||
|
PassMain::Sub *gbuffer_double_sided_ps_ = nullptr;
|
||||||
|
|
||||||
|
PassSimple eval_light_ps_ = {"EvalLights"};
|
||||||
|
|
||||||
|
/* Closures bits from the materials in this pass. */
|
||||||
|
eClosureBits closure_bits_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulation textures for all stages of lighting evaluation (Light, SSR, SSSS, SSGI ...).
|
||||||
|
* These are split and separate from the main radiance buffer in order to accumulate light for
|
||||||
|
* the render passes and avoid too much bandwidth waste. Otherwise, we would have to load the
|
||||||
|
* BSDF color and do additive blending for each of the lighting step.
|
||||||
|
*
|
||||||
|
* NOTE: Not to be confused with the render passes.
|
||||||
|
*/
|
||||||
|
TextureFromPool diffuse_light_tx_ = {"diffuse_light_accum_tx"};
|
||||||
|
TextureFromPool specular_light_tx_ = {"specular_light_accum_tx"};
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeferredLayer(Instance &inst) : inst_(inst){};
|
||||||
|
|
||||||
|
void begin_sync();
|
||||||
|
void end_sync();
|
||||||
|
|
||||||
|
PassMain::Sub *prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion);
|
||||||
|
PassMain::Sub *material_add(::Material *blender_mat, GPUMaterial *gpumat);
|
||||||
|
|
||||||
|
void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeferredPipeline {
|
||||||
|
private:
|
||||||
|
Instance &inst_;
|
||||||
|
|
||||||
|
/* Gbuffer filling passes. We could have an arbitrary number of them but for now we just have
|
||||||
|
* a hardcoded number of them. */
|
||||||
|
DeferredLayer opaque_layer_;
|
||||||
|
DeferredLayer refraction_layer_;
|
||||||
|
DeferredLayer volumetric_layer_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeferredPipeline(Instance &inst)
|
||||||
|
: inst_(inst), opaque_layer_(inst), refraction_layer_(inst), volumetric_layer_(inst){};
|
||||||
|
|
||||||
|
void begin_sync();
|
||||||
|
void end_sync();
|
||||||
|
|
||||||
|
PassMain::Sub *prepass_add(::Material *material, GPUMaterial *gpumat, bool has_motion);
|
||||||
|
PassMain::Sub *material_add(::Material *material, GPUMaterial *gpumat);
|
||||||
|
|
||||||
|
void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Utility texture
|
/** \name Utility texture
|
||||||
*
|
*
|
||||||
@ -197,22 +268,25 @@ class UtilityTexture : public Texture {
|
|||||||
class PipelineModule {
|
class PipelineModule {
|
||||||
public:
|
public:
|
||||||
WorldPipeline world;
|
WorldPipeline world;
|
||||||
// DeferredPipeline deferred;
|
DeferredPipeline deferred;
|
||||||
ForwardPipeline forward;
|
ForwardPipeline forward;
|
||||||
ShadowPipeline shadow;
|
ShadowPipeline shadow;
|
||||||
// VelocityPipeline velocity;
|
|
||||||
|
|
||||||
UtilityTexture utility_tx;
|
UtilityTexture utility_tx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PipelineModule(Instance &inst) : world(inst), forward(inst), shadow(inst){};
|
PipelineModule(Instance &inst) : world(inst), deferred(inst), forward(inst), shadow(inst){};
|
||||||
|
|
||||||
void sync()
|
void begin_sync()
|
||||||
{
|
{
|
||||||
// deferred.sync();
|
deferred.begin_sync();
|
||||||
forward.sync();
|
forward.sync();
|
||||||
shadow.sync();
|
shadow.sync();
|
||||||
// velocity.sync();
|
}
|
||||||
|
|
||||||
|
void end_sync()
|
||||||
|
{
|
||||||
|
deferred.end_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
PassMain::Sub *material_add(Object *ob,
|
PassMain::Sub *material_add(Object *ob,
|
||||||
@ -222,7 +296,7 @@ class PipelineModule {
|
|||||||
{
|
{
|
||||||
switch (pipeline_type) {
|
switch (pipeline_type) {
|
||||||
case MAT_PIPE_DEFERRED_PREPASS:
|
case MAT_PIPE_DEFERRED_PREPASS:
|
||||||
// return deferred.prepass_add(blender_mat, gpumat, false);
|
return deferred.prepass_add(blender_mat, gpumat, false);
|
||||||
case MAT_PIPE_FORWARD_PREPASS:
|
case MAT_PIPE_FORWARD_PREPASS:
|
||||||
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
||||||
return forward.prepass_transparent_add(ob, blender_mat, gpumat);
|
return forward.prepass_transparent_add(ob, blender_mat, gpumat);
|
||||||
@ -230,7 +304,7 @@ class PipelineModule {
|
|||||||
return forward.prepass_opaque_add(blender_mat, gpumat, false);
|
return forward.prepass_opaque_add(blender_mat, gpumat, false);
|
||||||
|
|
||||||
case MAT_PIPE_DEFERRED_PREPASS_VELOCITY:
|
case MAT_PIPE_DEFERRED_PREPASS_VELOCITY:
|
||||||
// return deferred.prepass_add(blender_mat, gpumat, true);
|
return deferred.prepass_add(blender_mat, gpumat, true);
|
||||||
case MAT_PIPE_FORWARD_PREPASS_VELOCITY:
|
case MAT_PIPE_FORWARD_PREPASS_VELOCITY:
|
||||||
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
||||||
return forward.prepass_transparent_add(ob, blender_mat, gpumat);
|
return forward.prepass_transparent_add(ob, blender_mat, gpumat);
|
||||||
@ -238,7 +312,7 @@ class PipelineModule {
|
|||||||
return forward.prepass_opaque_add(blender_mat, gpumat, true);
|
return forward.prepass_opaque_add(blender_mat, gpumat, true);
|
||||||
|
|
||||||
case MAT_PIPE_DEFERRED:
|
case MAT_PIPE_DEFERRED:
|
||||||
// return deferred.material_add(blender_mat, gpumat);
|
return deferred.material_add(blender_mat, gpumat);
|
||||||
case MAT_PIPE_FORWARD:
|
case MAT_PIPE_FORWARD:
|
||||||
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
||||||
return forward.material_transparent_add(ob, blender_mat, gpumat);
|
return forward.material_transparent_add(ob, blender_mat, gpumat);
|
||||||
|
@ -86,6 +86,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
|
|||||||
return "eevee_film_comp";
|
return "eevee_film_comp";
|
||||||
case FILM_CRYPTOMATTE_POST:
|
case FILM_CRYPTOMATTE_POST:
|
||||||
return "eevee_film_cryptomatte_post";
|
return "eevee_film_cryptomatte_post";
|
||||||
|
case DEFERRED_LIGHT:
|
||||||
|
return "eevee_deferred_light";
|
||||||
case HIZ_DEBUG:
|
case HIZ_DEBUG:
|
||||||
return "eevee_hiz_debug";
|
return "eevee_hiz_debug";
|
||||||
case HIZ_UPDATE:
|
case HIZ_UPDATE:
|
||||||
@ -241,6 +243,11 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* WORKAROUND: Needed because node_tree isn't present in test shaders. */
|
||||||
|
if (pipeline_type == MAT_PIPE_DEFERRED) {
|
||||||
|
info.define("MAT_RENDER_PASS_SUPPORT");
|
||||||
|
}
|
||||||
|
|
||||||
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
|
||||||
info.define("MAT_TRANSPARENT");
|
info.define("MAT_TRANSPARENT");
|
||||||
/* Transparent material do not have any velocity specific pipeline. */
|
/* Transparent material do not have any velocity specific pipeline. */
|
||||||
|
@ -30,6 +30,8 @@ enum eShaderType {
|
|||||||
FILM_COMP,
|
FILM_COMP,
|
||||||
FILM_CRYPTOMATTE_POST,
|
FILM_CRYPTOMATTE_POST,
|
||||||
|
|
||||||
|
DEFERRED_LIGHT,
|
||||||
|
|
||||||
DEBUG_SURFELS,
|
DEBUG_SURFELS,
|
||||||
|
|
||||||
DOF_BOKEH_LUT,
|
DOF_BOKEH_LUT,
|
||||||
|
@ -123,8 +123,7 @@ void ShadingView::render()
|
|||||||
/* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */
|
/* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */
|
||||||
inst_.lights.set_view(render_view_new_, extent_);
|
inst_.lights.set_view(render_view_new_, extent_);
|
||||||
|
|
||||||
// inst_.pipelines.deferred.render(
|
inst_.pipelines.deferred.render(render_view_new_, prepass_fb_, combined_fb_, extent_);
|
||||||
// render_view_, rt_buffer_opaque_, rt_buffer_refract_, depth_tx_, combined_tx_);
|
|
||||||
|
|
||||||
// inst_.lightprobes.draw_cache_display();
|
// inst_.lightprobes.draw_cache_display();
|
||||||
|
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Compute light objects lighting contribution using Gbuffer data.
|
||||||
|
*
|
||||||
|
* Output light either directly to the radiance buffers or to temporary radiance accumulation
|
||||||
|
* buffer that will be processed by other deferred lighting passes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
|
||||||
|
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||||
|
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||||
|
|
||||||
|
float depth = texelFetch(hiz_tx, ivec2(gl_FragCoord.xy), 0).r;
|
||||||
|
vec3 P = get_world_space_from_depth(uvcoordsvar.xy, depth);
|
||||||
|
|
||||||
|
/* TODO(fclem): High precision derivative. */
|
||||||
|
vec3 Ng = safe_normalize(cross(dFdx(P), dFdy(P)));
|
||||||
|
vec3 V = cameraVec(P);
|
||||||
|
float vP_z = dot(cameraForward, P) - dot(cameraForward, cameraPos);
|
||||||
|
|
||||||
|
vec4 gbuffer_0_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 0), 0);
|
||||||
|
vec4 gbuffer_1_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 1), 0);
|
||||||
|
|
||||||
|
ClosureReflection reflection_data;
|
||||||
|
reflection_data.N = gbuffer_normal_unpack(gbuffer_0_packed.xy);
|
||||||
|
reflection_data.roughness = gbuffer_0_packed.z;
|
||||||
|
|
||||||
|
ClosureDiffuse diffuse_data;
|
||||||
|
diffuse_data.N = gbuffer_normal_unpack(gbuffer_1_packed.xy);
|
||||||
|
/* These are only set for SSS case. */
|
||||||
|
diffuse_data.sss_radius = vec3(0.0);
|
||||||
|
diffuse_data.sss_id = 0u;
|
||||||
|
float thickness = 0.0;
|
||||||
|
|
||||||
|
bool is_refraction = gbuffer_is_refraction(gbuffer_1_packed);
|
||||||
|
if (is_refraction) {
|
||||||
|
/* Still evaluate the diffuse light so that dithered SSS / Refraction combination still
|
||||||
|
* produces a complete diffuse light buffer that will be correctly convolved by the SSSS.
|
||||||
|
* The refraction pixels will just set the diffuse radiance to 0. */
|
||||||
|
}
|
||||||
|
else if (false /* TODO */) {
|
||||||
|
vec4 gbuffer_2_packed = texelFetch(gbuffer_closure_tx, ivec3(texel, 2), 0);
|
||||||
|
diffuse_data.sss_radius = gbuffer_sss_radii_unpack(gbuffer_2_packed.xyz);
|
||||||
|
diffuse_data.sss_id = gbuffer_object_id_unorm16_unpack(gbuffer_2_packed.w);
|
||||||
|
thickness = gbuffer_thickness_pack(gbuffer_1_packed.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 diffuse_light = vec3(0.0);
|
||||||
|
vec3 reflection_light = vec3(0.0);
|
||||||
|
|
||||||
|
light_eval(
|
||||||
|
diffuse_data, reflection_data, P, Ng, V, vP_z, thickness, diffuse_light, reflection_light);
|
||||||
|
|
||||||
|
if (is_last_eval_pass) {
|
||||||
|
/* Apply color and output lighting to render-passes. */
|
||||||
|
vec4 color_0_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 0), 0);
|
||||||
|
vec4 color_1_packed = texelFetch(gbuffer_color_tx, ivec3(texel, 1), 0);
|
||||||
|
|
||||||
|
reflection_data.color = gbuffer_color_unpack(color_0_packed);
|
||||||
|
diffuse_data.color = gbuffer_color_unpack(color_1_packed);
|
||||||
|
|
||||||
|
if (is_refraction) {
|
||||||
|
diffuse_data.color = vec3(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
reflection_light *= reflection_data.color;
|
||||||
|
diffuse_light *= diffuse_data.color;
|
||||||
|
/* Add radiance to light pass. */
|
||||||
|
imageStore(
|
||||||
|
rp_light_img, ivec3(texel, RENDER_PASS_LAYER_DIFFUSE_LIGHT), vec4(diffuse_light, 1.0));
|
||||||
|
imageStore(
|
||||||
|
rp_light_img, ivec3(texel, RENDER_PASS_LAYER_SPECULAR_LIGHT), vec4(reflection_light, 1.0));
|
||||||
|
/* Add radiance to combined pass. */
|
||||||
|
out_radiance = vec4(diffuse_light + reflection_light, 0.0);
|
||||||
|
out_transmittance = vec4(1.0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Store lighting for next deferred pass. */
|
||||||
|
|
||||||
|
/* Output diffuse light along with object ID for sub-surface screen space processing. */
|
||||||
|
vec4 diffuse_radiance;
|
||||||
|
diffuse_radiance.xyz = diffuse_light;
|
||||||
|
diffuse_radiance.w = gbuffer_object_id_f16_pack(diffuse_data.sss_id);
|
||||||
|
imageStore(out_diffuse_light_img, texel, diffuse_radiance);
|
||||||
|
|
||||||
|
imageStore(out_specular_light_img, texel, vec4(reflection_light, 0.0));
|
||||||
|
|
||||||
|
/* Final radiance will be amended by the last pass.
|
||||||
|
* This should do nothing as color write should be disabled in this case. */
|
||||||
|
out_radiance = vec4(0.0);
|
||||||
|
out_transmittance = vec4(0.0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* G-buffer: Packing and upacking of G-buffer data.
|
||||||
|
*
|
||||||
|
* See #GBuffer for a breakdown of the G-buffer layout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||||
|
|
||||||
|
vec2 gbuffer_normal_pack(vec3 N)
|
||||||
|
{
|
||||||
|
N /= length_manhattan(N);
|
||||||
|
N.xy = (N.z >= 0.0) ? N.xy : ((1.0 - abs(N.yx)) * sign(N.xy));
|
||||||
|
N.xy = N.xy * 0.5 + 0.5;
|
||||||
|
return N.xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 gbuffer_normal_unpack(vec2 N_packed)
|
||||||
|
{
|
||||||
|
N_packed = N_packed * 2.0 - 1.0;
|
||||||
|
vec3 N = vec3(N_packed.x, N_packed.y, 1.0 - abs(N_packed.x) - abs(N_packed.y));
|
||||||
|
float t = clamp(-N.z, 0.0, 1.0);
|
||||||
|
N.x += (N.x >= 0.0) ? -t : t;
|
||||||
|
N.y += (N.y >= 0.0) ? -t : t;
|
||||||
|
return normalize(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
float gbuffer_ior_pack(float ior)
|
||||||
|
{
|
||||||
|
return (ior > 1.0) ? (1.0 - 0.5 / ior) : (0.5 * ior);
|
||||||
|
}
|
||||||
|
|
||||||
|
float gbuffer_ior_unpack(float ior_packed)
|
||||||
|
{
|
||||||
|
return (ior_packed > 0.5) ? (-1.0 / (ior_packed * 2.0 + 2.0)) : (2.0 * ior_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
float gbuffer_thickness_pack(float thickness)
|
||||||
|
{
|
||||||
|
/* TODO(fclem): Something better. */
|
||||||
|
return gbuffer_ior_pack(thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
float gbuffer_thickness_unpack(float thickness_packed)
|
||||||
|
{
|
||||||
|
/* TODO(fclem): Something better. */
|
||||||
|
return gbuffer_ior_unpack(thickness_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 gbuffer_sss_radii_pack(vec3 sss_radii)
|
||||||
|
{
|
||||||
|
/* TODO(fclem): Something better. */
|
||||||
|
return vec3(
|
||||||
|
gbuffer_ior_pack(sss_radii.x), gbuffer_ior_pack(sss_radii.y), gbuffer_ior_pack(sss_radii.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 gbuffer_sss_radii_unpack(vec3 sss_radii_packed)
|
||||||
|
{
|
||||||
|
/* TODO(fclem): Something better. */
|
||||||
|
return vec3(gbuffer_ior_unpack(sss_radii_packed.x),
|
||||||
|
gbuffer_ior_unpack(sss_radii_packed.y),
|
||||||
|
gbuffer_ior_unpack(sss_radii_packed.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 gbuffer_color_pack(vec3 color)
|
||||||
|
{
|
||||||
|
float max_comp = max(color.x, max(color.y, color.z));
|
||||||
|
/* Store 2bit exponent inside Alpha. Allows values up to 8 with some color degradation.
|
||||||
|
* Above 8, the result will be clampped when writing the data to the output buffer. */
|
||||||
|
float exponent = (max_comp > 1) ? ((max_comp > 2) ? ((max_comp > 4) ? 3.0 : 2.0) : 1.0) : 0.0;
|
||||||
|
/* TODO(fclem): Could try dithering to avoid banding artifacts on higher exponents. */
|
||||||
|
return vec4(color / exp2(exponent), exponent / 3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 gbuffer_color_unpack(vec4 color_packed)
|
||||||
|
{
|
||||||
|
float exponent = color_packed.a * 3.0;
|
||||||
|
return color_packed.rgb * exp2(exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
float gbuffer_object_id_unorm16_pack(uint object_id)
|
||||||
|
{
|
||||||
|
return float(object_id & 0xFFFFu) / float(0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint gbuffer_object_id_unorm16_unpack(float object_id_packed)
|
||||||
|
{
|
||||||
|
return uint(object_id_packed * float(0xFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
float gbuffer_object_id_f16_pack(uint object_id)
|
||||||
|
{
|
||||||
|
/* TODO(fclem): Make use of all the 16 bits in a half float.
|
||||||
|
* This here only correctly represent values up to 1024. */
|
||||||
|
return float(object_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint gbuffer_object_id_f16_unpack(float object_id_packed)
|
||||||
|
{
|
||||||
|
return uint(object_id_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gbuffer_is_refraction(vec4 gbuffer)
|
||||||
|
{
|
||||||
|
return gbuffer.w < 1.0;
|
||||||
|
}
|
@ -29,14 +29,16 @@ bool closure_select(float weight, inout float total_weight, inout float r)
|
|||||||
float x = weight / total_weight;
|
float x = weight / total_weight;
|
||||||
bool chosen = (r < x);
|
bool chosen = (r < x);
|
||||||
/* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within
|
/* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within
|
||||||
* that interval, so you remapping to [0,1] again to explore this space of probability. */
|
* that interval, so remapping to [0,1] again to explore this space of probability. */
|
||||||
r = (chosen) ? (r / x) : ((r - x) / (1.0 - x));
|
r = (chosen) ? (r / x) : ((r - x) / (1.0 - x));
|
||||||
return chosen;
|
return chosen;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SELECT_CLOSURE(destination, random, candidate) \
|
#define SELECT_CLOSURE(destination, random, candidate) \
|
||||||
if (closure_select(candidate.weight, destination.weight, random)) { \
|
if (closure_select(candidate.weight, destination.weight, random)) { \
|
||||||
|
float tmp = destination.weight; \
|
||||||
destination = candidate; \
|
destination = candidate; \
|
||||||
|
destination.weight = tmp; \
|
||||||
}
|
}
|
||||||
|
|
||||||
float g_closure_rand;
|
float g_closure_rand;
|
||||||
|
@ -82,7 +82,7 @@ void main()
|
|||||||
{
|
{
|
||||||
vec2 screen_uv = gl_FragCoord.xy / vec2(fb_resolution);
|
vec2 screen_uv = gl_FragCoord.xy / vec2(fb_resolution);
|
||||||
|
|
||||||
float opaque_depth = texelFetch(hiz_tx, int2(gl_FragCoord.xy), fb_lod).r;
|
float opaque_depth = texelFetch(hiz_tx, ivec2(gl_FragCoord.xy), fb_lod).r;
|
||||||
vec3 ws_opaque = get_world_space_from_depth(screen_uv, opaque_depth);
|
vec3 ws_opaque = get_world_space_from_depth(screen_uv, opaque_depth);
|
||||||
|
|
||||||
vec3 ws_near_plane = get_world_space_from_depth(screen_uv, 0);
|
vec3 ws_near_plane = get_world_space_from_depth(screen_uv, 0);
|
||||||
|
@ -3,17 +3,136 @@
|
|||||||
* Deferred lighting evaluation: Lighting is evaluated in a separate pass.
|
* Deferred lighting evaluation: Lighting is evaluated in a separate pass.
|
||||||
*
|
*
|
||||||
* Outputs shading parameter per pixel using a randomized set of BSDFs.
|
* Outputs shading parameter per pixel using a randomized set of BSDFs.
|
||||||
**/
|
* Some render-pass are written during this pass.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||||
|
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||||
|
|
||||||
|
vec4 closure_to_rgba(Closure cl)
|
||||||
|
{
|
||||||
|
vec4 out_color;
|
||||||
|
out_color.rgb = g_emission;
|
||||||
|
out_color.a = saturate(1.0 - avg(g_transmittance));
|
||||||
|
|
||||||
|
/* Reset for the next closure tree. */
|
||||||
|
closure_weights_reset();
|
||||||
|
|
||||||
|
return out_color;
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
init_globals();
|
init_globals();
|
||||||
|
|
||||||
|
float noise = utility_tx_fetch(utility_tx, gl_FragCoord.xy, UTIL_BLUE_NOISE_LAYER).r;
|
||||||
|
g_closure_rand = fract(noise + sampling_rng_1D_get(SAMPLING_CLOSURE));
|
||||||
|
|
||||||
|
fragment_displacement();
|
||||||
|
|
||||||
nodetree_surface();
|
nodetree_surface();
|
||||||
|
|
||||||
|
g_holdout = saturate(g_holdout);
|
||||||
|
|
||||||
|
out_transmittance = vec4(1.0 - g_holdout);
|
||||||
|
float transmittance_mono = saturate(avg(g_transmittance));
|
||||||
|
|
||||||
|
float thickness = nodetree_thickness();
|
||||||
|
|
||||||
|
g_diffuse_data.color *= g_diffuse_data.weight;
|
||||||
|
g_reflection_data.color *= g_reflection_data.weight;
|
||||||
|
g_refraction_data.color *= g_refraction_data.weight;
|
||||||
|
|
||||||
|
/* TODO(fclem): This feels way too complex for what is it. */
|
||||||
|
bool has_any_bsdf_weight = g_diffuse_data.weight != 0.0 || g_reflection_data.weight != 0.0 ||
|
||||||
|
g_refraction_data.weight != 0.0;
|
||||||
|
vec3 out_normal = has_any_bsdf_weight ? vec3(0.0) : g_data.N;
|
||||||
|
out_normal += g_diffuse_data.N * g_diffuse_data.weight;
|
||||||
|
out_normal += g_reflection_data.N * g_reflection_data.weight;
|
||||||
|
out_normal += g_refraction_data.N * g_refraction_data.weight;
|
||||||
|
out_normal = safe_normalize(out_normal);
|
||||||
|
|
||||||
|
vec3 specular_color = g_reflection_data.color + g_refraction_data.color;
|
||||||
|
|
||||||
|
/* ----- Render Passes output ----- */
|
||||||
|
|
||||||
|
ivec2 out_texel = ivec2(gl_FragCoord.xy);
|
||||||
|
#ifdef MAT_RENDER_PASS_SUPPORT /* Needed because node_tree isn't present in test shaders. */
|
||||||
|
/* Some render pass can be written during the gbuffer pass. Light passes are written later. */
|
||||||
|
vec4 cryptomatte_output = vec4(cryptomatte_object_buf[resource_id], node_tree.crypto_hash, 0.0);
|
||||||
|
imageStore(rp_cryptomatte_img, out_texel, cryptomatte_output);
|
||||||
|
imageStore(rp_normal_img, out_texel, vec4(out_normal, 1.0));
|
||||||
|
/* TODO(fclem): For now, just don't do anything. In the future all render passes should be in an
|
||||||
|
* array texture and have a UBO with indirection to the correct layer. */
|
||||||
|
// imageStore(rp_diffuse_color_img, out_texel, vec4(g_diffuse_data.color, 1.0));
|
||||||
|
imageStore(rp_specular_color_img, out_texel, vec4(specular_color, 1.0));
|
||||||
|
imageStore(rp_emission_img, out_texel, vec4(g_emission, 1.0));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ----- GBuffer output ----- */
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
/* Reflection. */
|
||||||
|
vec4 out_reflect = vec4(gbuffer_normal_pack(g_reflection_data.N),
|
||||||
|
g_reflection_data.roughness,
|
||||||
|
g_reflection_data.roughness);
|
||||||
|
imageStore(out_gbuff_closure_img, ivec3(out_texel, 0), out_reflect);
|
||||||
|
|
||||||
|
vec4 color = gbuffer_color_pack(g_reflection_data.color);
|
||||||
|
imageStore(out_gbuff_color_img, ivec3(out_texel, 0), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO(fclem) other RNG. */
|
||||||
|
float refract_rand = fract(g_closure_rand * 6.1803398875);
|
||||||
|
float combined_weight = g_refraction_data.weight + g_diffuse_data.weight;
|
||||||
|
bool output_refraction = combined_weight > 0.0 &&
|
||||||
|
(refract_rand * combined_weight) < g_refraction_data.weight;
|
||||||
|
if (output_refraction) {
|
||||||
|
/* Refraction. */
|
||||||
|
vec4 closure;
|
||||||
|
closure.xy = gbuffer_normal_pack(g_refraction_data.N);
|
||||||
|
closure.z = g_refraction_data.roughness;
|
||||||
|
closure.w = gbuffer_ior_pack(g_refraction_data.ior);
|
||||||
|
/* Clamp to just bellow 1 to be able to distinguish between refraction and diffuse.
|
||||||
|
* Ceiling value is chosen by the storage format (16bit UNORM). */
|
||||||
|
closure.w = min(closure.w, float(0xFFFFu - 1u) / float(0xFFFFu));
|
||||||
|
imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure);
|
||||||
|
|
||||||
|
vec4 color = gbuffer_color_pack(g_refraction_data.color);
|
||||||
|
imageStore(out_gbuff_color_img, ivec3(out_texel, 1), color);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Diffuse. */
|
||||||
|
vec4 closure;
|
||||||
|
closure.xy = gbuffer_normal_pack(g_diffuse_data.N);
|
||||||
|
closure.z = gbuffer_thickness_pack(thickness);
|
||||||
|
/* Used to detect the refraction case. Could be used for roughness. */
|
||||||
|
closure.w = 1.0;
|
||||||
|
imageStore(out_gbuff_closure_img, ivec3(out_texel, 1), closure);
|
||||||
|
|
||||||
|
vec4 color = gbuffer_color_pack(g_diffuse_data.color);
|
||||||
|
imageStore(out_gbuff_color_img, ivec3(out_texel, 1), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
/* SubSurface Scattering. */
|
||||||
|
vec4 closure;
|
||||||
|
closure.xyz = gbuffer_sss_radii_pack(g_diffuse_data.sss_radius);
|
||||||
|
closure.w = gbuffer_object_id_unorm16_pack(g_diffuse_data.sss_id);
|
||||||
|
imageStore(out_gbuff_closure_img, ivec3(out_texel, 2), closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----- Radiance output ----- */
|
||||||
|
|
||||||
|
/* Only output emission during the gbuffer pass. */
|
||||||
|
out_radiance = vec4(g_emission, 0.0);
|
||||||
|
out_radiance.rgb *= 1.0 - g_holdout;
|
||||||
|
|
||||||
|
out_transmittance.rgb = g_transmittance;
|
||||||
|
out_transmittance.a = saturate(avg(g_transmittance));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "eevee_defines.hh"
|
||||||
|
#include "gpu_shader_create_info.hh"
|
||||||
|
|
||||||
|
#define image_out(slot, qualifier, format, name) \
|
||||||
|
image(slot, format, qualifier, ImageType::FLOAT_2D, name, Frequency::PASS)
|
||||||
|
#define image_array_out(slot, qualifier, format, name) \
|
||||||
|
image(slot, format, qualifier, ImageType::FLOAT_2D_ARRAY, name, Frequency::PASS)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specific deferred pass accumulate the computed lighting to either:
|
||||||
|
* - a split diffuse / specular temporary light buffer.
|
||||||
|
* or to
|
||||||
|
* - the combined pass & the light render-pass (if needed).
|
||||||
|
*
|
||||||
|
* This is in order to minimize the number of blending step.
|
||||||
|
*/
|
||||||
|
GPU_SHADER_CREATE_INFO(eevee_deferred_base)
|
||||||
|
/* Early fragment test is needed to avoid processing fragments without correct GBuffer data. */
|
||||||
|
.early_fragment_test(true)
|
||||||
|
/* Select which output to write to. */
|
||||||
|
.push_constant(Type::BOOL, "is_last_eval_pass")
|
||||||
|
/* Combined pass output. */
|
||||||
|
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
|
||||||
|
.fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
|
||||||
|
/* Light pass output. */
|
||||||
|
.image_array_out(RBUFS_LIGHT_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_light_img")
|
||||||
|
/* Chaining to next pass. */
|
||||||
|
.image_out(2, Qualifier::READ_WRITE, GPU_RGBA16F, "out_diffuse_light_img")
|
||||||
|
.image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "out_specular_light_img");
|
||||||
|
|
||||||
|
GPU_SHADER_CREATE_INFO(eevee_deferred_light)
|
||||||
|
.fragment_source("eevee_deferred_light_frag.glsl")
|
||||||
|
.sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx")
|
||||||
|
.sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_color_tx")
|
||||||
|
.additional_info("eevee_shared",
|
||||||
|
"eevee_utility_texture",
|
||||||
|
"eevee_light_data",
|
||||||
|
"eevee_shadow_data",
|
||||||
|
"eevee_deferred_base",
|
||||||
|
"eevee_hiz_data",
|
||||||
|
"draw_view",
|
||||||
|
"draw_fullscreen")
|
||||||
|
.do_static_compilation(true);
|
||||||
|
|
||||||
|
#undef image_array_out
|
@ -88,11 +88,11 @@ GPU_SHADER_CREATE_INFO(eevee_aov_out)
|
|||||||
|
|
||||||
GPU_SHADER_CREATE_INFO(eevee_render_pass_out)
|
GPU_SHADER_CREATE_INFO(eevee_render_pass_out)
|
||||||
.define("MAT_RENDER_PASS_SUPPORT")
|
.define("MAT_RENDER_PASS_SUPPORT")
|
||||||
.image_out(RBUFS_NORMAL_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_normal_img")
|
.image_out(RBUFS_NORMAL_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_normal_img")
|
||||||
.image_array_out(RBUFS_LIGHT_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_light_img")
|
.image_array_out(RBUFS_LIGHT_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_light_img")
|
||||||
.image_out(RBUFS_DIFF_COLOR_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_color_img")
|
.image_out(RBUFS_DIFF_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_diffuse_color_img")
|
||||||
.image_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img")
|
.image_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_specular_color_img")
|
||||||
.image_out(RBUFS_EMISSION_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img");
|
.image_out(RBUFS_EMISSION_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_emission_img");
|
||||||
|
|
||||||
GPU_SHADER_CREATE_INFO(eevee_cryptomatte_out)
|
GPU_SHADER_CREATE_INFO(eevee_cryptomatte_out)
|
||||||
.storage_buf(CRYPTOMATTE_BUF_SLOT, Qualifier::READ, "vec2", "cryptomatte_object_buf[]")
|
.storage_buf(CRYPTOMATTE_BUF_SLOT, Qualifier::READ, "vec2", "cryptomatte_object_buf[]")
|
||||||
@ -101,23 +101,29 @@ GPU_SHADER_CREATE_INFO(eevee_cryptomatte_out)
|
|||||||
GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
|
GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
|
||||||
.vertex_out(eevee_surf_iface)
|
.vertex_out(eevee_surf_iface)
|
||||||
/* NOTE: This removes the possibility of using gl_FragDepth. */
|
/* NOTE: This removes the possibility of using gl_FragDepth. */
|
||||||
// .early_fragment_test(true)
|
.early_fragment_test(true)
|
||||||
/* Direct output. */
|
/* Direct output. (Emissive, Holdout) */
|
||||||
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
|
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
|
||||||
.fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
|
.fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
|
||||||
/* Gbuffer. */
|
/* Everything is stored inside a two layered target, one for each format. This is to fit the
|
||||||
// .image_out(0, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_transmit_color")
|
* limitation of the number of images we can bind on a single shader. */
|
||||||
// .image_out(1, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_transmit_data")
|
.image_array_out(GBUF_CLOSURE_SLOT, Qualifier::WRITE, GPU_RGBA16, "out_gbuff_closure_img")
|
||||||
// .image_out(2, Qualifier::WRITE, GPU_RGBA16F, "gbuff_transmit_normal")
|
.image_array_out(GBUF_COLOR_SLOT, Qualifier::WRITE, GPU_RGB10_A2, "out_gbuff_color_img")
|
||||||
// .image_out(3, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_reflection_color")
|
/* Render-passes need to be declared manually to avoid overlap with the G-buffer which reuse
|
||||||
// .image_out(4, Qualifier::WRITE, GPU_RGBA16F, "gbuff_reflection_normal")
|
* some of binding points. */
|
||||||
// .image_out(5, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_emission")
|
.image_out(RBUFS_NORMAL_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_normal_img")
|
||||||
/* Render-passes. */
|
// .image_array_out(RBUFS_LIGHT_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_light_img")
|
||||||
// .image_out(6, Qualifier::READ_WRITE, GPU_RGBA16F, "rpass_volume_light")
|
/* TODO(fclem): Merge all render-pass into the same texture array. */
|
||||||
|
// .image_out(RBUFS_DIFF_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_diffuse_color_img")
|
||||||
|
.image_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_specular_color_img")
|
||||||
|
.image_out(RBUFS_EMISSION_SLOT, Qualifier::WRITE, GPU_RGBA16F, "rp_emission_img")
|
||||||
.fragment_source("eevee_surf_deferred_frag.glsl")
|
.fragment_source("eevee_surf_deferred_frag.glsl")
|
||||||
.additional_info("eevee_camera",
|
.additional_info("eevee_camera",
|
||||||
"eevee_utility_texture",
|
"eevee_utility_texture",
|
||||||
"eevee_sampling_data",
|
"eevee_sampling_data",
|
||||||
|
/* Added manually to avoid overlap. */
|
||||||
|
// "eevee_render_pass_out",
|
||||||
|
"eevee_cryptomatte_out",
|
||||||
"eevee_aov_out");
|
"eevee_aov_out");
|
||||||
|
|
||||||
GPU_SHADER_CREATE_INFO(eevee_surf_forward)
|
GPU_SHADER_CREATE_INFO(eevee_surf_forward)
|
||||||
|
@ -206,7 +206,8 @@ void DRW_texture_pool_reset(DRWTexturePool *pool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BLI_assert(pool->tmp_tex_acquired.is_empty());
|
BLI_assert_msg(pool->tmp_tex_acquired.is_empty(),
|
||||||
|
"Missing a TextureFromPool.release() before end of draw.");
|
||||||
for (GPUTexture *tmp_tex : pool->tmp_tex_pruned) {
|
for (GPUTexture *tmp_tex : pool->tmp_tex_pruned) {
|
||||||
GPU_texture_free(tmp_tex);
|
GPU_texture_free(tmp_tex);
|
||||||
}
|
}
|
||||||
|
@ -603,6 +603,7 @@ list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
|
|||||||
|
|
||||||
set(SRC_SHADER_CREATE_INFOS
|
set(SRC_SHADER_CREATE_INFOS
|
||||||
../draw/engines/basic/shaders/infos/basic_depth_info.hh
|
../draw/engines/basic/shaders/infos/basic_depth_info.hh
|
||||||
|
../draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh
|
||||||
../draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh
|
../draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh
|
||||||
../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh
|
../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh
|
||||||
../draw/engines/eevee_next/shaders/infos/eevee_hiz_info.hh
|
../draw/engines/eevee_next/shaders/infos/eevee_hiz_info.hh
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
/* Float Math */
|
/* Float Math */
|
||||||
|
|
||||||
|
/* WORKAROUND: To be removed once we port all code to use gpu_shader_math_base_lib.glsl. */
|
||||||
|
#ifndef GPU_SHADER_MATH_BASE_LIB_GLSL
|
||||||
|
|
||||||
float safe_divide(float a, float b)
|
float safe_divide(float a, float b)
|
||||||
{
|
{
|
||||||
return (b != 0.0) ? a / b : 0.0;
|
return (b != 0.0) ? a / b : 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* fmod function compatible with OSL (copy from OSL/dual.h) */
|
/* fmod function compatible with OSL (copy from OSL/dual.h) */
|
||||||
float compatible_fmod(float a, float b)
|
float compatible_fmod(float a, float b)
|
||||||
{
|
{
|
||||||
if (b != 0.0f) {
|
if (b != 0.0) {
|
||||||
int N = int(a / b);
|
int N = int(a / b);
|
||||||
return a - N * b;
|
return a - N * b;
|
||||||
}
|
}
|
||||||
return 0.0f;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float compatible_pow(float x, float y)
|
float compatible_pow(float x, float y)
|
||||||
@ -59,11 +64,16 @@ vec3 wrap(vec3 a, vec3 b, vec3 c)
|
|||||||
return vec3(wrap(a.x, b.x, c.x), wrap(a.y, b.y, c.y), wrap(a.z, b.z, c.z));
|
return vec3(wrap(a.x, b.x, c.x), wrap(a.y, b.y, c.y), wrap(a.z, b.z, c.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* WORKAROUND: To be removed once we port all code to use gpu_shader_math_base_lib.glsl. */
|
||||||
|
#ifndef GPU_SHADER_MATH_BASE_LIB_GLSL
|
||||||
|
|
||||||
float hypot(float x, float y)
|
float hypot(float x, float y)
|
||||||
{
|
{
|
||||||
return sqrt(x * x + y * y);
|
return sqrt(x * x + y * y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
int floor_to_int(float x)
|
int floor_to_int(float x)
|
||||||
{
|
{
|
||||||
return int(floor(x));
|
return int(floor(x));
|
||||||
@ -76,6 +86,9 @@ int quick_floor(float x)
|
|||||||
|
|
||||||
/* Vector Math */
|
/* Vector Math */
|
||||||
|
|
||||||
|
/* WORKAROUND: To be removed once we port all code to use gpu_shader_math_base_lib.glsl. */
|
||||||
|
#ifndef GPU_SHADER_MATH_BASE_LIB_GLSL
|
||||||
|
|
||||||
vec2 safe_divide(vec2 a, vec2 b)
|
vec2 safe_divide(vec2 a, vec2 b)
|
||||||
{
|
{
|
||||||
return vec2(safe_divide(a.x, b.x), safe_divide(a.y, b.y));
|
return vec2(safe_divide(a.x, b.x), safe_divide(a.y, b.y));
|
||||||
@ -107,6 +120,8 @@ vec4 safe_divide(vec4 a, float b)
|
|||||||
return (b != 0.0) ? a / b : vec4(0.0);
|
return (b != 0.0) ? a / b : vec4(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
vec3 compatible_fmod(vec3 a, vec3 b)
|
vec3 compatible_fmod(vec3 a, vec3 b)
|
||||||
{
|
{
|
||||||
return vec3(compatible_fmod(a.x, b.x), compatible_fmod(a.y, b.y), compatible_fmod(a.z, b.z));
|
return vec3(compatible_fmod(a.x, b.x), compatible_fmod(a.y, b.y), compatible_fmod(a.z, b.z));
|
||||||
|
Loading…
Reference in New Issue
Block a user