Eevee: Refactor Shadow System

- Use only one 2d texture array to store all shadowmaps.
- Allow to change shadow maps resolution.
- Do not output radial distance when rendering shadowmaps. This will allow fast rendering of shadowmaps when we will drop the use of geometry shaders.
This commit is contained in:
Clément Foucault 2017-09-01 15:59:01 +02:00
parent 5b026486e4
commit 8b7a83a868
16 changed files with 289 additions and 303 deletions

View File

@ -154,8 +154,6 @@ data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_store_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_store_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_store_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_direct_lib.glsl SRC)

View File

@ -39,15 +39,11 @@ static void eevee_scene_layer_data_free(void *storage)
DRW_UBO_FREE_SAFE(sldata->light_ubo);
DRW_UBO_FREE_SAFE(sldata->shadow_ubo);
DRW_UBO_FREE_SAFE(sldata->shadow_render_ubo);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_map_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_fb);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cube_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_color_cube_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cube_pool);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_map_pool);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cascade_pool);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_target_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_store_fb);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
BLI_freelistN(&sldata->shadow_casters);
/* Probes */

View File

@ -811,7 +811,7 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
if (grp != NULL) {
DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
DRW_shgroup_uniform_buffer(grp, "shadowCubes", &sldata->shadow_depth_cube_pool);
DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool);
DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);

View File

@ -309,6 +309,9 @@ static void EEVEE_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDPr
BKE_collection_engine_property_add_bool(props, "motion_blur_enable", false);
BKE_collection_engine_property_add_int(props, "motion_blur_samples", 8);
BKE_collection_engine_property_add_float(props, "motion_blur_shutter", 1.0f);
BKE_collection_engine_property_add_int(props, "shadow_method", SHADOW_ESM);
BKE_collection_engine_property_add_int(props, "shadow_size", 512);
}
static const DrawEngineDataSize EEVEE_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);

View File

@ -42,11 +42,6 @@ typedef struct EEVEE_ShadowCubeData {
float viewprojmat[6][4][4];
} EEVEE_ShadowCubeData;
typedef struct EEVEE_ShadowMapData {
short light_id, shadow_id;
float viewprojmat[4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
} EEVEE_ShadowMapData;
typedef struct EEVEE_ShadowCascadeData {
short light_id, shadow_id;
float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
@ -60,14 +55,13 @@ typedef struct ShadowCaster {
static struct {
struct GPUShader *shadow_sh;
struct GPUShader *shadow_store_sh;
struct GPUShader *shadow_store_cube_sh;
struct GPUShader *shadow_store_cascade_sh;
} e_data = {NULL}; /* Engine data */
extern char datatoc_shadow_vert_glsl[];
extern char datatoc_shadow_geom_glsl[];
extern char datatoc_shadow_frag_glsl[];
extern char datatoc_shadow_store_vert_glsl[];
extern char datatoc_shadow_store_geom_glsl[];
extern char datatoc_shadow_store_frag_glsl[];
/* *********** FUNCTIONS *********** */
@ -75,15 +69,18 @@ extern char datatoc_shadow_store_frag_glsl[];
void EEVEE_lights_init(EEVEE_SceneLayerData *sldata)
{
const unsigned int shadow_ubo_size = sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
sizeof(EEVEE_ShadowMap) * MAX_SHADOW_MAP +
sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
const DRWContextState *draw_ctx = DRW_context_state_get();
SceneLayer *scene_layer = draw_ctx->scene_layer;
IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
if (!e_data.shadow_sh) {
e_data.shadow_sh = DRW_shader_create(
datatoc_shadow_vert_glsl, datatoc_shadow_geom_glsl, datatoc_shadow_frag_glsl, NULL);
e_data.shadow_store_sh = DRW_shader_create(
datatoc_shadow_store_vert_glsl, datatoc_shadow_store_geom_glsl, datatoc_shadow_store_frag_glsl, NULL);
e_data.shadow_store_cube_sh = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, NULL);
e_data.shadow_store_cascade_sh = DRW_shader_create_fullscreen(datatoc_shadow_store_frag_glsl, "#define CSM");
}
if (!sldata->lamps) {
@ -92,23 +89,58 @@ void EEVEE_lights_init(EEVEE_SceneLayerData *sldata)
sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
}
int sh_method = BKE_collection_engine_property_value_get_int(props, "shadow_method");
int sh_size = BKE_collection_engine_property_value_get_int(props, "shadow_size");
UNUSED_VARS(sh_method);
EEVEE_LampsInfo *linfo = sldata->lamps;
if (linfo->shadow_size != sh_size) {
BLI_assert((sh_size > 0) && (sh_size <= 8192));
DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
linfo->shadow_size = sh_size;
linfo->shadow_render_data.stored_texel_size = 1.0 / (float)linfo->shadow_size;
/* Compute adequate size for the cubemap render target.
* The 3.0f factor is here to make sure there is no under sampling between
* the octahedron mapping and the cubemap. */
int new_cube_target_size = (int)ceil(sqrt((float)(sh_size * sh_size) / 6.0f) * 3.0f);
CLAMP(new_cube_target_size, 1, 4096);
if (linfo->shadow_cube_target_size != new_cube_target_size) {
linfo->shadow_cube_target_size = new_cube_target_size;
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
linfo->shadow_render_data.cube_texel_size = 1.0 / (float)linfo->shadow_cube_target_size;
}
}
}
void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
linfo->num_light = linfo->num_cube = linfo->num_map = linfo->num_cascade = 0;
linfo->num_light = linfo->num_cube = linfo->num_cascade = linfo->num_shadow = 0;
memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
memset(linfo->shadow_map_ref, 0, sizeof(linfo->shadow_map_ref));
memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
{
psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_sh, psl->shadow_cube_store_pass);
DRW_shgroup_uniform_buffer(grp, "shadowCube", &sldata->shadow_color_cube_target);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_cube_sh, psl->shadow_cube_store_pass);
DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cube_target);
DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
{
psl->shadow_cascade_store_pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_cascade_sh, psl->shadow_cascade_store_pass);
DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cascade_target);
DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
@ -118,7 +150,7 @@ void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
}
{
psl->shadow_cascade_pass = DRW_pass_create("Shadow Cascade Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
psl->shadow_cascade_pass = DRW_pass_create("Shadow Cascade Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
}
/* Reset shadow casters list */
@ -147,19 +179,19 @@ void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
#if 1 /* TODO Waiting for notified refresh. only on scene change. Else too much perf cost. */
if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) {
if (la->type == LA_SUN && linfo->num_cascade < MAX_SHADOW_CASCADE) {
#if 0 /* TODO filter cascaded shadow map */
led->storage = MEM_mallocN(sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData");
((EEVEE_ShadowCascadeData *)led->storage)->shadow_id = linfo->num_cascade;
((EEVEE_ShadowCascadeData *)led->storage)->shadow_id = linfo->num_shadow;
linfo->shadow_cascade_ref[linfo->num_cascade] = ob;
linfo->num_cascade++;
#endif
linfo->num_shadow += MAX_CASCADE_NUM;
}
else if ((la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA)
&& linfo->num_cube < MAX_SHADOW_CUBE) {
led->storage = MEM_mallocN(sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData");
((EEVEE_ShadowCubeData *)led->storage)->shadow_id = linfo->num_cube;
((EEVEE_ShadowCubeData *)led->storage)->shadow_id = linfo->num_shadow;
linfo->shadow_cube_ref[linfo->num_cube] = ob;
linfo->num_cube++;
linfo->num_shadow += 1;
}
}
@ -226,70 +258,58 @@ void EEVEE_lights_cache_shcaster_material_add(
void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
DRWTextureFormat shadow_pool_format;
/* Setup enough layers. */
/* Free textures if number mismatch. */
if (linfo->num_cube != linfo->cache_num_cube) {
DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cube_pool);
if ((linfo->num_shadow != linfo->cache_num_shadow) ||
(linfo->num_cube != linfo->cache_num_cube) ||
(linfo->num_cascade != linfo->cache_num_cascade))
{
DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
linfo->cache_num_cube = linfo->num_cube;
linfo->cache_num_cascade = linfo->num_cascade;
linfo->cache_num_shadow = linfo->num_shadow;
linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE;
}
if (linfo->num_map != linfo->cache_num_map) {
DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_map_pool);
linfo->cache_num_map = linfo->num_map;
}
if (linfo->num_cascade != linfo->cache_num_cascade) {
DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cascade_pool);
linfo->cache_num_cascade = linfo->num_cascade;
/* TODO Variance Shadow Map */
shadow_pool_format = DRW_TEX_R_32;
if (!sldata->shadow_cube_target) {
/* TODO render everything on the same 2d render target using clip planes and no Geom Shader. */
/* Cubemaps */
sldata->shadow_cube_target = DRW_texture_create_cube(linfo->shadow_cube_target_size, DRW_TEX_DEPTH_24, 0, NULL);
}
/* Initialize Textures Arrays first so DRW_framebuffer_init just bind them. */
if (!sldata->shadow_depth_cube_target) {
/* Render Cubemap */
sldata->shadow_depth_cube_target = DRW_texture_create_cube(512, DRW_TEX_DEPTH_24, 0, NULL);
sldata->shadow_color_cube_target = DRW_texture_create_cube(512, DRW_TEX_R_32, DRW_TEX_FILTER, NULL);
if (sldata->shadow_cube_fb) {
DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_depth_cube_target, 0, 0);
DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_color_cube_target, 0, 0);
}
}
if (!sldata->shadow_depth_cube_pool) {
/* Cubemap / octahedral map pool */
/* TODO Cubemap array */
sldata->shadow_depth_cube_pool = DRW_texture_create_2D_array(
512, 512, max_ff(1, linfo->num_cube), DRW_TEX_R_16,
DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
if (sldata->shadow_cube_fb) {
DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_depth_cube_pool, 0, 0);
}
}
if (!sldata->shadow_depth_map_pool) {
sldata->shadow_depth_map_pool = DRW_texture_create_2D_array(
512, 512, max_ff(1, linfo->num_map), DRW_TEX_DEPTH_24,
DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
if (sldata->shadow_map_fb) {
DRW_framebuffer_texture_attach(sldata->shadow_map_fb, sldata->shadow_depth_map_pool, 0, 0);
}
}
if (!sldata->shadow_depth_cascade_pool) {
sldata->shadow_depth_cascade_pool = DRW_texture_create_2D_array(
512, 512, max_ff(1, linfo->num_cascade * MAX_CASCADE_NUM), DRW_TEX_DEPTH_24,
DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
if (sldata->shadow_cascade_fb) {
DRW_framebuffer_texture_attach(sldata->shadow_cascade_fb, sldata->shadow_depth_map_pool, 0, 0);
}
if (!sldata->shadow_cascade_target) {
/* CSM */
sldata->shadow_cascade_target = DRW_texture_create_2D_array(
linfo->shadow_size, linfo->shadow_size, MAX_CASCADE_NUM, DRW_TEX_DEPTH_24, 0, NULL);
}
DRWFboTexture tex_cube_target[2] = {
{&sldata->shadow_depth_cube_target, DRW_TEX_DEPTH_24, 0},
{&sldata->shadow_color_cube_target, DRW_TEX_R_16, DRW_TEX_FILTER}};
DRW_framebuffer_init(&sldata->shadow_cube_target_fb, &draw_engine_eevee_type, 512, 512, tex_cube_target, 2);
/* Initialize Textures Array first so DRW_framebuffer_init just bind them. */
if (!sldata->shadow_pool) {
/* All shadows fit in this array */
sldata->shadow_pool = DRW_texture_create_2D_array(
linfo->shadow_size, linfo->shadow_size, max_ff(1, linfo->num_cube + linfo->num_cascade),
shadow_pool_format, DRW_TEX_FILTER, NULL);
}
DRWFboTexture tex_cube = {&sldata->shadow_depth_cube_pool, DRW_TEX_R_16, DRW_TEX_FILTER};
DRW_framebuffer_init(&sldata->shadow_cube_fb, &draw_engine_eevee_type, 512, 512, &tex_cube, 1);
/* Render FB */
DRWFboTexture tex_cascade = {&sldata->shadow_cube_target, DRW_TEX_DEPTH_24, 0};
DRW_framebuffer_init(&sldata->shadow_target_fb, &draw_engine_eevee_type,
linfo->shadow_size, linfo->shadow_size,
&tex_cascade, 1);
DRWFboTexture tex_cascade = {&sldata->shadow_depth_cascade_pool, DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE};
DRW_framebuffer_init(&sldata->shadow_cascade_fb, &draw_engine_eevee_type, 512, 512, &tex_cascade, 1);
/* Storage FB */
DRWFboTexture tex_pool = {&sldata->shadow_pool, shadow_pool_format, DRW_TEX_FILTER};
DRW_framebuffer_init(&sldata->shadow_store_fb, &draw_engine_eevee_type,
linfo->shadow_size, linfo->shadow_size,
&tex_pool, 1);
/* Restore */
DRW_framebuffer_texture_detach(sldata->shadow_cube_target);
/* Update Lamps UBOs. */
EEVEE_lights_update(sldata);
@ -397,31 +417,6 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La
evli->shadowid = (float)(evsmp->shadow_id);
}
static void eevee_shadow_map_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
{
float viewmat[4][4], projmat[4][4];
EEVEE_ShadowMapData *evsmp = (EEVEE_ShadowMapData *)led->storage;
EEVEE_Light *evli = linfo->light_data + evsmp->light_id;
EEVEE_ShadowMap *evsh = linfo->shadow_map_data + evsmp->shadow_id;
Lamp *la = (Lamp *)ob->data;
invert_m4_m4(viewmat, ob->obmat);
normalize_v3(viewmat[0]);
normalize_v3(viewmat[1]);
normalize_v3(viewmat[2]);
float wsize = la->shadow_frustum_size;
orthographic_m4(projmat, -wsize, wsize, -wsize, wsize, la->clipsta, la->clipend);
mul_m4_m4m4(evsmp->viewprojmat, projmat, viewmat);
mul_m4_m4m4(evsh->shadowmat, texcomat, evsmp->viewprojmat);
evsh->bias = 0.005f * la->bias;
evli->shadowid = (float)(MAX_SHADOW_CUBE + evsmp->shadow_id);
}
#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
static void frustum_min_bounding_sphere(const float corners[8][4], float r_center[3], float *r_radius)
@ -589,10 +584,10 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
mul_m4_m4m4(evsh->shadowmat[c], texcomat, evscp->viewprojmat[c]);
/* TODO modify bias depending on the cascade radius */
evsh->bias[c] = 0.005f * la->bias;
evsh->bias = 0.005f * la->bias;
}
evli->shadowid = (float)(MAX_SHADOW_CUBE + MAX_SHADOW_MAP + evscp->shadow_id);
evli->shadowid = (float)(MAX_SHADOW_CUBE + evscp->shadow_id);
}
/* Used for checking if object is inside the shadow volume. */
@ -718,11 +713,6 @@ void EEVEE_lights_update(EEVEE_SceneLayerData *sldata)
delete_pruned_shadowcaster(led);
}
for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
eevee_shadow_map_setup(ob, linfo, led);
}
for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
eevee_shadow_cascade_setup(ob, linfo, led);
@ -738,7 +728,7 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
EEVEE_LampsInfo *linfo = sldata->lamps;
Object *ob;
int i;
float clear_color[4] = {FLT_MAX, FLT_MAX, FLT_MAX, 0.0f};
float clear_col[4] = {FLT_MAX};
/* Cube Shadow Maps */
/* Render each shadow to one layer of the array */
@ -750,8 +740,10 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
srd->layer = i;
srd->exponent = la->bleedexp;
srd->shadow_samples_ct = 32.0f;
srd->shadow_inv_samples_ct = 1.0f / srd->shadow_samples_ct;
srd->clip_near = la->clipsta;
srd->clip_far = la->clipend;
copy_v3_v3(srd->position, ob->obmat[3]);
for (int j = 0; j < 6; j++) {
float tmp[4][4];
@ -762,15 +754,17 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
copy_m4_m4(srd->shadowmat[j], evscd->viewprojmat[j]);
}
DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
DRW_framebuffer_bind(sldata->shadow_cube_target_fb);
DRW_framebuffer_clear(true, true, false, clear_color, 1.0f);
DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cube_target, 0, 0);
DRW_framebuffer_bind(sldata->shadow_target_fb);
DRW_framebuffer_clear(true, true, false, clear_col, 1.0f);
/* Render shadow cube */
DRW_draw_pass(psl->shadow_cube_pass);
/* Push it to shadowmap array */
DRW_framebuffer_bind(sldata->shadow_cube_fb);
DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, i, 0);
DRW_framebuffer_bind(sldata->shadow_store_fb);
DRW_draw_pass(psl->shadow_cube_store_pass);
led->need_update = false;
@ -778,21 +772,7 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
}
linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
#if 0
/* Standard Shadow Maps */
DRW_framebuffer_bind(fbl->shadow_map_fb);
DRW_framebuffer_clear(false, true, false, NULL, 1.0);
/* Render each shadow to one layer of the array */
for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
EEVEE_ShadowMapData *evsmd = (EEVEE_ShadowMapData *)led->storage;
linfo->layer = i;
copy_m4_m4(linfo->shadowmat, evsmd->viewprojmat);
DRW_draw_pass(vedata->psl->shadow_pass);
}
#endif
DRW_framebuffer_texture_detach(sldata->shadow_cube_target);
/* Cascaded Shadow Maps */
// DRW_framebuffer_bind(fbl->shadow_cascade_fb);
@ -817,5 +797,6 @@ void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
void EEVEE_lights_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_store_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh);
}

View File

@ -58,7 +58,6 @@
"#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\n" \
"#define MAX_LIGHT " STRINGIFY(MAX_LIGHT) "\n" \
"#define MAX_SHADOW_CUBE " STRINGIFY(MAX_SHADOW_CUBE) "\n" \
"#define MAX_SHADOW_MAP " STRINGIFY(MAX_SHADOW_MAP) "\n" \
"#define MAX_SHADOW_CASCADE " STRINGIFY(MAX_SHADOW_CASCADE) "\n" \
"#define MAX_CASCADE_NUM " STRINGIFY(MAX_CASCADE_NUM) "\n" \
SHADER_IRRADIANCE
@ -370,8 +369,7 @@ static void add_standard_uniforms(
DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool);
DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool);
DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
DRW_shgroup_uniform_buffer(shgrp, "shadowCubes", &sldata->shadow_depth_cube_pool);
DRW_shgroup_uniform_buffer(shgrp, "shadowCascades", &sldata->shadow_depth_cascade_pool);
DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool);
DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2);
if (refract_depth != NULL) {

View File

@ -36,7 +36,6 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_PLANAR 16 /* TODO : find size by dividing UBO max size by grid data size */
#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
#define MAX_SHADOW_CUBE 42 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW_MAP 64
#define MAX_SHADOW_CASCADE 8
#define MAX_CASCADE_NUM 4
#define MAX_BLOOM_STEP 16
@ -78,12 +77,19 @@ enum {
VAR_MAT_REFRACT = (1 << 12),
};
/* Shadow Technique */
enum {
SHADOW_ESM = 1,
SHADOW_VSM = 2,
};
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
struct DRWPass *shadow_cube_pass;
struct DRWPass *shadow_cube_store_pass;
struct DRWPass *shadow_cascade_pass;
struct DRWPass *shadow_cascade_store_pass;
/* Probes */
struct DRWPass *probe_background;
@ -206,24 +212,22 @@ typedef struct EEVEE_ShadowCube {
float near, far, bias, exp;
} EEVEE_ShadowCube;
typedef struct EEVEE_ShadowMap {
float shadowmat[4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */
float near, far, bias, pad;
} EEVEE_ShadowMap;
typedef struct EEVEE_ShadowCascade {
float shadowmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */
float split[4];
float bias[4];
float near, far, bias, pad;
} EEVEE_ShadowCascade;
typedef struct EEVEE_ShadowRender {
float shadowmat[6][4][4]; /* World->Lamp->NDC : used to render the shadow map. 6 frustrum for cubemap shadow */
float shadowmat[6][4][4]; /* World->Lamp->NDC : used to render the shadow map. 6 frustum for cubemap shadow */
float viewmat[6][4][4]; /* World->Lamp : used to render the shadow map. 6 viewmat for cubemap shadow */
float position[3];
float pad;
int layer;
float exponent;
float position[3], pad;
float cube_texel_size;
float stored_texel_size;
float clip_near;
float clip_far;
float shadow_samples_ct;
float shadow_inv_samples_ct;
} EEVEE_ShadowRender;
/* ************ VOLUME DATA ************ */
@ -237,20 +241,20 @@ typedef struct EEVEE_VolumetricsInfo {
typedef struct EEVEE_LampsInfo {
int num_light, cache_num_light;
int num_cube, cache_num_cube;
int num_map, cache_num_map;
int num_cascade, cache_num_cascade;
int num_shadow, cache_num_shadow;
int update_flag;
int shadow_size, shadow_method;
int shadow_cube_target_size;
/* List of lights in the scene. */
/* XXX This is fragile, can get out of sync quickly. */
struct Object *light_ref[MAX_LIGHT];
struct Object *shadow_cube_ref[MAX_SHADOW_CUBE];
struct Object *shadow_map_ref[MAX_SHADOW_MAP];
struct Object *shadow_cascade_ref[MAX_SHADOW_CASCADE];
/* UBO Storage : data used by UBO */
struct EEVEE_Light light_data[MAX_LIGHT];
struct EEVEE_ShadowRender shadow_render_data;
struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
struct EEVEE_ShadowMap shadow_map_data[MAX_SHADOW_MAP];
struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
} EEVEE_LampsInfo;
@ -401,17 +405,14 @@ typedef struct EEVEE_SceneLayerData {
struct GPUUniformBuffer *light_ubo;
struct GPUUniformBuffer *shadow_ubo;
struct GPUUniformBuffer *shadow_render_ubo;
struct GPUUniformBuffer *shadow_samples_ubo;
struct GPUFrameBuffer *shadow_cube_target_fb;
struct GPUFrameBuffer *shadow_cube_fb;
struct GPUFrameBuffer *shadow_map_fb;
struct GPUFrameBuffer *shadow_cascade_fb;
struct GPUFrameBuffer *shadow_target_fb;
struct GPUFrameBuffer *shadow_store_fb;
struct GPUTexture *shadow_depth_cube_target;
struct GPUTexture *shadow_color_cube_target;
struct GPUTexture *shadow_depth_cube_pool;
struct GPUTexture *shadow_depth_map_pool;
struct GPUTexture *shadow_depth_cascade_pool;
struct GPUTexture *shadow_cube_target;
struct GPUTexture *shadow_cascade_target;
struct GPUTexture *shadow_pool;
struct ListBase shadow_casters; /* Shadow casters gathered during cache iteration */

View File

@ -19,8 +19,12 @@ layout(std140) uniform shadow_render_block {
mat4 ShadowMatrix[6];
mat4 FaceViewMatrix[6];
vec4 lampPosition;
int layer;
float exponent;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float shadowSampleCount;
float shadowInvSampleCount;
};
flat in int shFace; /* Shadow layer we are rendering to. */
@ -72,23 +76,6 @@ struct ShadowCubeData {
vec4 near_far_bias_exp;
};
/* convenience aliases */
#define sh_cube_near near_far_bias_exp.x
#define sh_cube_far near_far_bias_exp.y
#define sh_cube_bias near_far_bias_exp.z
#define sh_cube_exp near_far_bias_exp.w
struct ShadowMapData {
mat4 shadowmat;
vec4 near_far_bias;
};
/* convenience aliases */
#define sh_map_near near_far_bias.x
#define sh_map_far near_far_bias.y
#define sh_map_bias near_far_bias.z
#ifndef MAX_CASCADE_NUM
#define MAX_CASCADE_NUM 4
#endif
@ -97,9 +84,15 @@ struct ShadowCascadeData {
mat4 shadowmat[MAX_CASCADE_NUM];
/* arrays of float are not aligned so use vec4 */
vec4 split_distances;
vec4 bias;
vec4 near_far_bias_exp;
};
/* convenience aliases */
#define sh_cube_near near_far_bias_exp.x
#define sh_cube_far near_far_bias_exp.y
#define sh_cube_bias near_far_bias_exp.z
#define sh_cube_exp near_far_bias_exp.w
/* ------- Convenience functions --------- */
vec3 mul(mat3 m, vec3 v) { return m * v; }
@ -114,6 +107,7 @@ vec3 project_point(mat4 m, vec3 v) {
float min_v2(vec2 v) { return min(v.x, v.y); }
float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
float max_v2(vec2 v) { return max(v.x, v.y); }
float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
float saturate(float a) { return clamp(a, 0.0, 1.0); }
vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }

View File

@ -1,10 +1,8 @@
uniform sampler2DArray shadowCubes;
uniform sampler2DArrayShadow shadowCascades;
uniform sampler2DArray shadowTexture;
layout(std140) uniform shadow_block {
ShadowCubeData shadows_cube_data[MAX_SHADOW_CUBE];
ShadowMapData shadows_map_data[MAX_SHADOW_MAP];
ShadowCascadeData shadows_cascade_data[MAX_SHADOW_CASCADE];
};
@ -26,23 +24,25 @@ float shadow_cubemap(float shid, vec4 l_vector)
vec3 cubevec = -l_vector.xyz / l_vector.w;
float dist = l_vector.w - scd.sh_cube_bias;
float z = texture_octahedron(shadowCubes, vec4(cubevec, shid)).r;
float z = texture_octahedron(shadowTexture, vec4(cubevec, shid)).r;
float esm_test = saturate(exp(scd.sh_cube_exp * (z - dist)));
// float sh_test = step(0, z - dist);
float sh_test = step(0, z - dist);
return esm_test;
}
float shadow_cascade(float shid, vec3 W)
{
return 1.0;
#if 0
/* Shadow Cascade */
shid -= (MAX_SHADOW_CUBE + MAX_SHADOW_MAP);
shid -= MAX_SHADOW_CUBE;
ShadowCascadeData smd = shadows_cascade_data[int(shid)];
/* Finding Cascade index */
vec4 z = vec4(-dot(cameraPos - W, cameraForward));
vec4 comp = step(z, smd.split_distances);
vec4 view_z = vec4(-dot(cameraPos - W, cameraForward));
vec4 comp = step(view_z, smd.split_distances);
float cascade = dot(comp, comp);
mat4 shadowmat;
float bias;
@ -68,10 +68,15 @@ float shadow_cascade(float shid, vec3 W)
}
vec4 shpos = shadowmat * vec4(W, 1.0);
shpos.z -= bias * shpos.w;
float dist = shpos.z - bias * shpos.w;
shpos.xyz /= shpos.w;
return texture(shadowCascades, vec4(shpos.xy, shid * float(MAX_CASCADE_NUM) + cascade, shpos.z));
float z = texture(shadowTexture, vec4(shpos.xy, shid * float(MAX_CASCADE_NUM) + cascade, shpos.z)).r;
float esm_test = saturate(exp(smd.sh_cube_exp * (z - dist)));
return esm_test;
#endif
}
float light_visibility(LightData ld, vec3 W, vec4 l_vector)
@ -97,7 +102,7 @@ float light_visibility(LightData ld, vec3 W, vec4 l_vector)
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
/* shadowing */
if (ld.l_shadowid >= (MAX_SHADOW_MAP + MAX_SHADOW_CUBE)) {
if (ld.l_shadowid >= MAX_SHADOW_CUBE) {
vis *= shadow_cascade(ld.l_shadowid, W);
}
else if (ld.l_shadowid >= 0.0) {

View File

@ -62,10 +62,6 @@ float hashed_alpha_threshold(vec3 co)
uniform float alphaThreshold;
#endif
#ifdef SHADOW_SHADER
out vec4 FragColor;
#endif
void main()
{
/* For now do nothing.
@ -86,9 +82,4 @@ void main()
discard;
#endif
#endif
#ifdef SHADOW_SHADER
float dist = distance(lampPosition.xyz, worldPosition.xyz);
FragColor = vec4(dist, 0.0, 0.0, 1.0);
#endif
}

View File

@ -1,17 +1,4 @@
layout(std140) uniform shadow_render_block {
mat4 ShadowMatrix[6];
mat4 FaceViewMatrix[6];
vec4 lampPosition;
int layer;
float exponent;
};
in vec3 worldPosition;
out vec4 FragColor;
void main() {
float dist = distance(lampPosition.xyz, worldPosition.xyz);
FragColor = vec4(dist, 0.0, 0.0, 1.0);
/* Do nothing */
}

View File

@ -3,8 +3,12 @@ layout(std140) uniform shadow_render_block {
mat4 ShadowMatrix[6];
mat4 FaceViewMatrix[6];
vec4 lampPosition;
int layer;
float exponent;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float shadowSampleCount;
float shadowInvSampleCount;
};
layout(triangles) in;

View File

@ -3,11 +3,19 @@ layout(std140) uniform shadow_render_block {
mat4 ShadowMatrix[6];
mat4 FaceViewMatrix[6];
vec4 lampPosition;
int layer;
float exponent;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float shadowSampleCount;
float shadowInvSampleCount;
};
uniform samplerCube shadowCube;
#ifdef CSM
uniform sampler2DArray shadowTexture;
#else
uniform samplerCube shadowTexture;
#endif
out vec4 FragColor;
@ -25,35 +33,31 @@ vec3 octahedral_to_cubemap_proj(vec2 co)
return v;
}
void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B)
void make_orthonormal_basis(vec3 N, float rot, out vec3 T, out vec3 B)
{
vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0);
T = normalize( cross(UpVector, N) );
B = cross(N, T);
vec3 UpVector = (abs(N.z) < max(abs(N.x), abs(N.y))) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 nT = normalize(cross(UpVector, N));
vec3 nB = cross(N, nT);
/* Rotate tangent space */
vec2 dir = vec2(cos(rot * 3.1415 * 2.0), sin(rot * 3.1415 * 2.0));
T = dir.x * nT + dir.y * nB;
B = -dir.y * nT + dir.x * nB;
}
#define NUM_SAMPLE 32
vec2 poisson_disc[32] = vec2[32](
vec2( 0.476, 0.854), vec2(-0.659, -0.670),
vec2( 0.905, -0.270), vec2( 0.215, -0.133),
vec2(-0.595, 0.242), vec2(-0.146, 0.519),
vec2( 0.108, -0.930), vec2( 0.807, 0.449),
float linear_depth(float z)
{
return (nearClip * farClip) / (z * (nearClip - farClip) + farClip);
}
vec2(-0.476, -0.854), vec2( 0.659, 0.670),
vec2(-0.905, 0.270), vec2(-0.215, 0.133),
vec2( 0.595, -0.242), vec2( 0.146, -0.519),
vec2(-0.108, 0.930), vec2(-0.807, -0.449),
vec2(-0.854, 0.476), vec2( 0.670, -0.659),
vec2( 0.270, 0.905), vec2( 0.133, 0.215),
vec2(-0.242, -0.595), vec2(-0.519, -0.146),
vec2( 0.930, 0.108), vec2(-0.449, 0.807),
vec2( 0.854, -0.476), vec2(-0.670, 0.659),
vec2(-0.270, -0.905), vec2(-0.133, -0.215),
vec2( 0.242, 0.595), vec2( 0.519, 0.146),
vec2(-0.930, -0.108), vec2( 0.449, -0.807)
);
float get_cube_radial_distance(vec3 cubevec)
{
float zdepth = texture(shadowTexture, cubevec).r;
float linear_zdepth = linear_depth(zdepth);
cubevec = normalize(abs(cubevec));
float cos_vec = max(cubevec.x, max(cubevec.y, cubevec.z));
return linear_zdepth / cos_vec;
}
/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
float ln_space_prefilter(float w0, float x, float w1, float y)
@ -61,14 +65,66 @@ float ln_space_prefilter(float w0, float x, float w1, float y)
return x + log(w0 + w1 * exp(y - x));
}
void main() {
const vec2 texelSize = vec2(1.0 / 512.0);
const int SAMPLE_NUM = 32;
const float INV_SAMPLE_NUM = 1.0 / float(SAMPLE_NUM);
const vec2 poisson[32] = vec2[32](
vec2(-0.31889129888, 0.945170187163),
vec2(0.0291070069348, 0.993645382622),
vec2(0.453968568675, 0.882119488776),
vec2(-0.59142811398, 0.775098624552),
vec2(0.0672147039953, 0.677233646792),
vec2(0.632546991242, 0.60080388224),
vec2(-0.846282545004, 0.478266943968),
vec2(-0.304563967348, 0.550414788876),
vec2(0.343951542639, 0.482122717676),
vec2(0.903371461134, 0.419225918868),
vec2(-0.566433506581, 0.326544955645),
vec2(-0.0174468029403, 0.345927250589),
vec2(-0.970838848328, 0.131541221423),
vec2(-0.317404956404, 0.102175571059),
vec2(0.309107085158, 0.136502232088),
vec2(0.67009683403, 0.198922062526),
vec2(-0.62544683989, -0.0237682928336),
vec2(0.0, 0.0),
vec2(0.260779995092, -0.192490308513),
vec2(0.555635503398, -0.0918935341973),
vec2(0.989587880961, -0.03629312269),
vec2(-0.93440130633, -0.213478602005),
vec2(-0.615716455579, -0.335329659339),
vec2(0.813589336772, -0.292544036149),
vec2(-0.821106257666, -0.568279197395),
vec2(-0.298092257627, -0.457929494012),
vec2(0.263233114326, -0.515552889911),
vec2(-0.0311374378304, -0.643310533036),
vec2(0.785838482787, -0.615972502555),
vec2(-0.444079211316, -0.836548440017),
vec2(-0.0253421088433, -0.96112294526),
vec2(0.350411908643, -0.89783206142)
);
vec2 uvs = gl_FragCoord.xy * texelSize;
float wang_hash_noise(uint s)
{
uint seed = (uint(gl_FragCoord.x) * 1664525u + uint(gl_FragCoord.y)) + s;
seed = (seed ^ 61u) ^ (seed >> 16u);
seed *= 9u;
seed = seed ^ (seed >> 4u);
seed *= 0x27d4eb2du;
seed = seed ^ (seed >> 15u);
float value = float(seed);
value *= 1.0 / 4294967296.0;
return fract(value);
}
#define ESM
void main() {
vec2 uvs = gl_FragCoord.xy * storedTexelSize;
/* add a 2 pixel border to ensure filtering is correct */
uvs.xy *= 1.0 + texelSize * 2.0;
uvs.xy -= texelSize;
uvs.xy *= 1.0 + storedTexelSize * 2.0;
uvs.xy -= storedTexelSize;
float pattern = 1.0;
@ -86,28 +142,30 @@ void main() {
/* get cubemap vector */
vec3 cubevec = octahedral_to_cubemap_proj(uvs.xy);
/* TODO Can be optimized by groupping fetches
* and by converting to radial distance beforehand. */
#if defined(ESM)
vec3 T, B;
make_orthonormal_basis(cubevec, T, B);
make_orthonormal_basis(cubevec, wang_hash_noise(0u), T, B);
T *= 0.01;
B *= 0.01;
/* get cubemap shadow value */
const float blur_radius = 5.0 / 512.0; /* Totally arbitrary */
const float weight = 1.0 / float(NUM_SAMPLE);
float accum = 0.0;
/* Poisson disc blur in log space. */
vec2 offsetvec = poisson_disc[0].xy * blur_radius;
float depth1 = texture(shadowCube, cubevec + offsetvec.x * T + offsetvec.y * B).r;
float depth1 = get_cube_radial_distance(cubevec + poisson[0].x * T + poisson[0].y * B);
float depth2 = get_cube_radial_distance(cubevec + poisson[1].x * T + poisson[1].y * B);
accum = ln_space_prefilter(INV_SAMPLE_NUM, depth1, INV_SAMPLE_NUM, depth2);
offsetvec = poisson_disc[1].xy * blur_radius;
float depth2 = texture(shadowCube, cubevec + offsetvec.x * T + offsetvec.y * B).r;
accum = ln_space_prefilter(weight, depth1, weight, depth2);
for (int i = 2; i < NUM_SAMPLE; ++i) {
vec2 offsetvec = poisson_disc[i].xy * blur_radius;
depth1 = texture(shadowCube, cubevec + offsetvec.x * T + offsetvec.y * B).r;
accum = ln_space_prefilter(1.0, accum, weight, depth1);
for (int i = 2; i < SAMPLE_NUM; ++i) {
depth1 = get_cube_radial_distance(cubevec + poisson[i].x * T + poisson[i].y * B);
accum = ln_space_prefilter(1.0, accum, INV_SAMPLE_NUM, depth1);
}
FragColor = vec4(accum, accum, accum, 1.0);
FragColor = vec4(accum);
#else /* PCF (no prefilter) */
FragColor = vec4(get_cube_radial_distance(cubevec));
#endif
}

View File

@ -1,24 +0,0 @@
layout(std140) uniform shadow_render_block {
mat4 ShadowMatrix[6];
mat4 FaceViewMatrix[6];
vec4 lampPosition;
int layer;
float exponent;
};
layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;
in vec4 vPos[];
void main() {
gl_Layer = layer;
for (int v = 0; v < 3; ++v) {
gl_Position = vPos[v];
EmitVertex();
}
EndPrimitive();
}

View File

@ -1,8 +0,0 @@
in vec3 pos;
out vec4 vPos;
void main() {
vPos = vec4(pos, 1.0);
}

View File

@ -2222,7 +2222,9 @@ static GPUTextureFormat convert_tex_format(
case DRW_TEX_RGBA_8: *r_channels = 4; return GPU_RGBA8;
case DRW_TEX_RGBA_16: *r_channels = 4; return GPU_RGBA16F;
case DRW_TEX_RGBA_32: *r_channels = 4; return GPU_RGBA32F;
case DRW_TEX_DEPTH_16: *r_channels = 1; return GPU_DEPTH_COMPONENT16;
case DRW_TEX_DEPTH_24: *r_channels = 1; return GPU_DEPTH_COMPONENT24;
case DRW_TEX_DEPTH_32: *r_channels = 1; return GPU_DEPTH_COMPONENT32F;
case DRW_TEX_RGB_11_11_10: *r_channels = 3; return GPU_R11F_G11F_B10F;
default:
BLI_assert(false && "Texture format unsupported as render target!");