Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c654
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c119
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h55
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c90
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c62
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c32
-rw-r--r--source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl13
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl37
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c4
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c2
-rw-r--r--source/blender/draw/engines/image/image_private.h2
-rw-r--r--source/blender/draw/tests/shaders_test.cc2
16 files changed, 1030 insertions, 56 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 2de6ee1f57d..a6cc9fddd69 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -80,6 +80,7 @@ set(SRC
engines/image/image_engine.c
engines/image/image_shader.c
engines/eevee/eevee_bloom.c
+ engines/eevee/eevee_cryptomatte.c
engines/eevee/eevee_data.c
engines/eevee/eevee_depth_of_field.c
engines/eevee/eevee_effects.c
@@ -250,6 +251,7 @@ data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/renderpass_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/cryptomatte_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/surface_frag.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
new file mode 100644
index 00000000000..44ff86b3333
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -0,0 +1,654 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup EEVEE
+ *
+ * This file implements Cryptomatte for EEVEE. Cryptomatte is used to extract mattes using
+ * information already available at render time. See
+ * https://raw.githubusercontent.com/Psyop/Cryptomatte/master/specification/IDmattes_poster.pdf
+ * for reference to the cryptomatte specification.
+ *
+ * The challenge with cryptomatte in EEVEE is the merging and sorting of the samples.
+ * User can enable up to 3 cryptomatte layers (Object, Material and Asset).
+ *
+ * Process
+ *
+ * - Cryptomatte sample: Rendering of a cryptomatte sample is stored in a GPUBuffer. The buffer
+ * holds a single float per pixel per number of active cryptomatte layers. The float is the
+ * cryptomatte hash of each layer. After drawing the cryptomatte sample the intermediate result is
+ * downloaded to a CPU buffer (`cryptomatte_download_buffer`).
+ *
+ * Accurate mode
+ *
+ * There are two accuracy modes. The difference between the two is the number of render samples
+ * they take into account to create the render passes. When accurate mode is off the number of
+ * levels is used as the number of cryptomatte samples to take. When accuracy mode is on the number
+ * of render samples is used.
+ *
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_cryptomatte.h"
+
+#include "GPU_batch.h"
+
+#include "RE_pipeline.h"
+
+#include "BLI_alloca.h"
+#include "BLI_math_bits.h"
+#include "BLI_rect.h"
+
+#include "DNA_hair_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
+
+#include "eevee_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Data Management cryptomatte accum buffer
+ * \{ */
+
+BLI_INLINE eViewLayerCryptomatteFlags eevee_cryptomatte_active_layers(const ViewLayer *view_layer)
+{
+ const eViewLayerCryptomatteFlags cryptomatte_layers = view_layer->cryptomatte_flag &
+ VIEW_LAYER_CRYPTOMATTE_ALL;
+ return cryptomatte_layers;
+}
+
+/* The number of cryptomatte layers that are enabled */
+BLI_INLINE int eevee_cryptomatte_layers_count(const ViewLayer *view_layer)
+{
+ const eViewLayerCryptomatteFlags cryptomatte_layers = eevee_cryptomatte_active_layers(
+ view_layer);
+ return count_bits_i(cryptomatte_layers);
+}
+
+/* The number of render result passes are needed to store a single cryptomatte layer. Per
+ * renderpass 2 cryptomatte samples can be stored. */
+BLI_INLINE int eevee_cryptomatte_passes_per_layer(const ViewLayer *view_layer)
+{
+ const int num_cryptomatte_levels = view_layer->cryptomatte_levels;
+ const int num_cryptomatte_passes = (num_cryptomatte_levels + 1) / 2;
+ return num_cryptomatte_passes;
+}
+
+BLI_INLINE int eevee_cryptomatte_layer_stride(const ViewLayer *view_layer)
+{
+ return view_layer->cryptomatte_levels;
+}
+
+BLI_INLINE int eevee_cryptomatte_layer_offset(const ViewLayer *view_layer, const int layer)
+{
+ return view_layer->cryptomatte_levels * layer;
+}
+
+BLI_INLINE int eevee_cryptomatte_pixel_stride(const ViewLayer *view_layer)
+{
+ return eevee_cryptomatte_layer_stride(view_layer) * eevee_cryptomatte_layers_count(view_layer);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Init Renderpasses
+ * \{ */
+
+void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ /* Cryptomatte is only rendered for final image renders */
+ if (!DRW_state_is_image_render()) {
+ return;
+ }
+ if (eevee_cryptomatte_active_layers(view_layer) != 0) {
+ g_data->render_passes |= EEVEE_RENDER_PASS_CRYPTOMATTE;
+ g_data->cryptomatte_accurate_mode = (view_layer->cryptomatte_flag &
+ VIEW_LAYER_CRYPTOMATTE_ACCURATE) != 0;
+ }
+}
+
+void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
+ EEVEE_Data *vedata,
+ int UNUSED(tot_samples))
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PrivateData *g_data = vedata->stl->g_data;
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = draw_ctx->view_layer;
+
+ const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer);
+ eGPUTextureFormat format = (num_cryptomatte_layers == 1) ?
+ GPU_R32F :
+ (num_cryptomatte_layers == 2) ? GPU_RG32F : GPU_RGBA32F;
+ const float *viewport_size = DRW_viewport_size_get();
+ const int buffer_size = viewport_size[0] * viewport_size[1];
+
+ if (g_data->cryptomatte_accum_buffer == NULL) {
+ g_data->cryptomatte_accum_buffer = MEM_calloc_arrayN(
+ sizeof(EEVEE_CryptomatteSample),
+ buffer_size * eevee_cryptomatte_pixel_stride(view_layer),
+ __func__);
+ /* Download buffer should store a float per active cryptomatte layer. */
+ g_data->cryptomatte_download_buffer = MEM_malloc_arrayN(
+ sizeof(float), buffer_size * num_cryptomatte_layers, __func__);
+ }
+
+ DRW_texture_ensure_fullscreen_2d(&txl->cryptomatte, format, 0);
+ GPU_framebuffer_ensure_config(&fbl->cryptomatte_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(txl->cryptomatte),
+ });
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Populate Cache
+ * \{ */
+
+void EEVEE_cryptomatte_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0) {
+ DRW_PASS_CREATE(psl->cryptomatte_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+ }
+}
+
+static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *UNUSED(sldata),
+ Object *ob,
+ Material *material,
+ bool is_hair)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = draw_ctx->view_layer;
+ const eViewLayerCryptomatteFlags cryptomatte_layers = eevee_cryptomatte_active_layers(
+ view_layer);
+ float cryptohash[4] = {0.0f};
+
+ EEVEE_PassList *psl = vedata->psl;
+ int layer_offset = 0;
+ if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) {
+ uint32_t cryptomatte_hash = BKE_cryptomatte_object_hash(ob);
+ float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash);
+ cryptohash[layer_offset] = cryptomatte_color_value;
+ layer_offset++;
+ }
+ if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) {
+ uint32_t cryptomatte_hash = BKE_cryptomatte_material_hash(material);
+ float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash);
+ cryptohash[layer_offset] = cryptomatte_color_value;
+ layer_offset++;
+ }
+ if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) {
+ uint32_t cryptomatte_hash = BKE_cryptomatte_asset_hash(ob);
+ float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash);
+ cryptohash[layer_offset] = cryptomatte_color_value;
+ layer_offset++;
+ }
+
+ DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_cryptomatte_sh_get(is_hair),
+ psl->cryptomatte_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "cryptohash", cryptohash);
+
+ return grp;
+}
+
+static void eevee_cryptomatte_hair_cache_populate(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Object *ob,
+ ParticleSystem *psys,
+ ModifierData *md,
+ Material *material)
+{
+ DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create(
+ vedata, sldata, ob, material, true);
+ DRW_shgroup_hair_create_sub(ob, psys, md, grp);
+}
+
+void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Object *ob)
+{
+ BLI_assert(ob->type == OB_HAIR);
+ Hair *hair = ob->data;
+ Material *material = hair->mat ? hair->mat[HAIR_MATERIAL_NR - 1] : NULL;
+ eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, NULL, NULL, material);
+}
+
+void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (ob->type == OB_MESH) {
+ if (ob != draw_ctx->object_edit) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+ if (draw_as != PART_DRAW_PATH) {
+ continue;
+ }
+ Mesh *mesh = ob->data;
+ Material *material = part->omat - 1 < mesh->totcol ? NULL : mesh->mat[part->omat - 1];
+ eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, psys, md, material);
+ }
+ }
+ }
+}
+
+void EEVEE_cryptomatte_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = draw_ctx->view_layer;
+ const eViewLayerCryptomatteFlags cryptomatte_layers = eevee_cryptomatte_active_layers(
+ view_layer);
+
+ if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) {
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
+ struct GPUBatch **geoms = DRW_cache_object_surface_material_get(
+ ob, gpumat_array, materials_len);
+ if (geoms) {
+ for (int i = 0; i < materials_len; i++) {
+ struct GPUBatch *geom = geoms[i];
+ if (geom == NULL) {
+ continue;
+ }
+ Material *material = BKE_object_material_get(ob, i + 1);
+ DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create(
+ vedata, sldata, ob, material, false);
+ DRW_shgroup_call(grp, geom, ob);
+ }
+ }
+ }
+ else {
+ GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create(
+ vedata, sldata, ob, false, NULL);
+ DRW_shgroup_call(grp, geom, ob);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Accumulate Samples
+ * \{ */
+
+/* Downloads cryptomatte sample buffer from the GPU and integrate the samples with the accumulated
+ * cryptomatte samples. */
+static void eevee_cryptomatte_download_buffer(EEVEE_Data *vedata, GPUFrameBuffer *framebuffer)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = draw_ctx->view_layer;
+ const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer);
+ const int num_levels = view_layer->cryptomatte_levels;
+ const float *viewport_size = DRW_viewport_size_get();
+ const int buffer_size = viewport_size[0] * viewport_size[1];
+
+ EEVEE_CryptomatteSample *accum_buffer = g_data->cryptomatte_accum_buffer;
+ float *download_buffer = g_data->cryptomatte_download_buffer;
+
+ BLI_assert(accum_buffer);
+ BLI_assert(download_buffer);
+
+ GPU_framebuffer_read_color(framebuffer,
+ 0,
+ 0,
+ viewport_size[0],
+ viewport_size[1],
+ num_cryptomatte_layers,
+ 0,
+ GPU_DATA_FLOAT,
+ download_buffer);
+
+ /* Integrate download buffer into the accum buffer.
+ * The download buffer contains upto 3 floats per pixel (one float per cryptomatte layer.
+ *
+ * NOTE: here we deviate from the cryptomatte standard. During integration the standard always
+ * sort the samples by its weight to make sure that samples with the lowest weight
+ * are discarded first. In our case the weight of each sample is always 1 as we don't have
+ * subsamples and apply the coverage during the post processing. When there is no room for new
+ * samples the new samples has a weight of 1 and will always be discarded. */
+ int download_pixel_index = 0;
+ int accum_pixel_index = 0;
+ int accum_pixel_stride = eevee_cryptomatte_pixel_stride(view_layer);
+ for (int pixel_index = 0; pixel_index < buffer_size; pixel_index++) {
+ for (int layer = 0; layer < num_cryptomatte_layers; layer++) {
+ const int layer_offset = eevee_cryptomatte_layer_offset(view_layer, layer);
+ float download_hash = download_buffer[download_pixel_index++];
+ for (int level = 0; level < num_levels; level++) {
+ EEVEE_CryptomatteSample *sample = &accum_buffer[accum_pixel_index + layer_offset + level];
+ if (sample->hash == download_hash) {
+ sample->weight += 1.0f;
+ break;
+ }
+ /* We test against weight as hash 0.0f is used for samples hitting the world background. */
+ if (sample->weight == 0.0f) {
+ sample->hash = download_hash;
+ sample->weight = 1.0f;
+ break;
+ }
+ }
+ }
+ accum_pixel_index += accum_pixel_stride;
+ }
+}
+
+void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_PassList *psl = vedata->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = draw_ctx->view_layer;
+ const int cryptomatte_levels = view_layer->cryptomatte_levels;
+ const int current_sample = effects->taa_current_sample;
+
+ /* In accurate mode all render samples are evaluated. In inaccurate mode this is limited to the
+ * number of cryptomatte levels. This will reduce the overhead of downloading the GPU buffer and
+ * integrating it into the accum buffer. */
+ if (g_data->cryptomatte_accurate_mode || current_sample < cryptomatte_levels) {
+ static float clear_color[4] = {0.0};
+ GPU_framebuffer_bind(fbl->cryptomatte_fb);
+ GPU_framebuffer_clear_color(fbl->cryptomatte_fb, clear_color);
+ DRW_draw_pass(psl->cryptomatte_ps);
+
+ eevee_cryptomatte_download_buffer(vedata, fbl->cryptomatte_fb);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Render Passes
+ * \{ */
+
+/* Register the render passes needed for cryptomatte
+ * normally this is done in `EEVEE_render_update_passes`, but it has been placed here to keep
+ * related code side-by-side for clarity. */
+void EEVEE_cryptomatte_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
+{
+ char cryptomatte_pass_name[MAX_NAME];
+ const short num_passes = eevee_cryptomatte_passes_per_layer(view_layer);
+ if ((view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) {
+ for (short pass = 0; pass < num_passes; pass++) {
+ BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, "CryptoObject%02d", pass);
+ RE_engine_register_pass(
+ engine, scene, view_layer, cryptomatte_pass_name, 4, "RGBA", SOCK_RGBA);
+ }
+ }
+ if ((view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) {
+ for (short pass = 0; pass < num_passes; pass++) {
+ BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, "CryptoMaterial%02d", pass);
+ RE_engine_register_pass(
+ engine, scene, view_layer, cryptomatte_pass_name, 4, "RGBA", SOCK_RGBA);
+ }
+ }
+ if ((view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) {
+ for (short pass = 0; pass < num_passes; pass++) {
+ BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, "CryptoAsset%02d", pass);
+ RE_engine_register_pass(
+ engine, scene, view_layer, cryptomatte_pass_name, 4, "RGBA", SOCK_RGBA);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Construct Render Result
+ * \{ */
+
+/* Compare function for cryptomatte samples. Samples with the highest weight will be at the
+ * beginning of the list. */
+static int eevee_cryptomatte_sample_cmp_reverse(const void *a_, const void *b_)
+{
+ const EEVEE_CryptomatteSample *a = a_;
+ const EEVEE_CryptomatteSample *b = b_;
+ if (a->weight < b->weight) {
+ return 1;
+ }
+ if (a->weight > b->weight) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Post process the weights. The accumulated weights buffer adds one to each weight per sample.
+ * During post processing ensure that the total of weights per sample is between 0 and 1. */
+static void eevee_cryptomatte_postprocess_weights(EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = draw_ctx->view_layer;
+ const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer);
+ const int num_levels = view_layer->cryptomatte_levels;
+ const float *viewport_size = DRW_viewport_size_get();
+ const int buffer_size = viewport_size[0] * viewport_size[1];
+
+ EEVEE_CryptomatteSample *accum_buffer = g_data->cryptomatte_accum_buffer;
+ BLI_assert(accum_buffer);
+ int accum_pixel_index = 0;
+ int accum_pixel_stride = eevee_cryptomatte_pixel_stride(view_layer);
+
+ for (int pixel_index = 0; pixel_index < buffer_size;
+ pixel_index++, accum_pixel_index += accum_pixel_stride) {
+ for (int layer = 0; layer < num_cryptomatte_layers; layer++) {
+ const int layer_offset = eevee_cryptomatte_layer_offset(view_layer, layer);
+ /* Calculate the total weight of the sample. */
+ float total_weight = 0.0f;
+ for (int level = 0; level < num_levels; level++) {
+ EEVEE_CryptomatteSample *sample = &accum_buffer[accum_pixel_index + layer_offset + level];
+ total_weight += sample->weight;
+ }
+ BLI_assert(total_weight > 0.0f);
+
+ float total_weight_inv = 1.0f / total_weight;
+ for (int level = 0; level < num_levels; level++) {
+ EEVEE_CryptomatteSample *sample = &accum_buffer[accum_pixel_index + layer_offset + level];
+ /* Remove background samples. These samples were used to determine the correct weight
+ * but won't be part of the final result. */
+ if (sample->hash == 0.0f) {
+ sample->weight = 0.0f;
+ }
+ sample->weight *= total_weight_inv;
+ }
+
+ /* Sort accum buffer by coverage of each sample. */
+ qsort(&accum_buffer[accum_pixel_index + layer_offset],
+ num_levels,
+ sizeof(EEVEE_CryptomatteSample),
+ eevee_cryptomatte_sample_cmp_reverse);
+ }
+ }
+}
+
+/* Extract cryptomatte layer from the cryptomatte_accum_buffer to render passes. */
+static void eevee_cryptomatte_extract_render_passes(
+ RenderLayer *rl,
+ const char *viewname,
+ const char *render_pass_name_format,
+ EEVEE_CryptomatteSample *accum_buffer,
+ /* number of render passes per cryptomatte layer. */
+ const int num_cryptomatte_passes,
+ const int num_cryptomatte_levels,
+ const int accum_pixel_stride,
+ const int layer_stride,
+ const int layer_index,
+ const int rect_width,
+ const int rect_height,
+ const int rect_offset_x,
+ const int rect_offset_y,
+ const int viewport_width)
+{
+ char cryptomatte_pass_name[MAX_NAME];
+ /* A pass can store 2 levels. Technically the last pass can have a single level if the number of
+ * levels is an odd number. This parameter counts the number of levels it has processed. */
+ int levels_done = 0;
+ for (int pass = 0; pass < num_cryptomatte_passes; pass++) {
+ /* Each pass holds 2 cryptomatte samples. */
+ const int pass_offset = pass * 2;
+ BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, render_pass_name_format, pass);
+ RenderPass *rp_object = RE_pass_find_by_name(rl, cryptomatte_pass_name, viewname);
+ for (int y = 0; y < rect_height; y++) {
+ for (int x = 0; x < rect_width; x++) {
+ const int accum_buffer_offset = (rect_offset_x + x +
+ (rect_offset_y + y) * viewport_width) *
+ accum_pixel_stride +
+ layer_index * layer_stride + pass_offset;
+ const int render_pass_offset = (y * rect_width + x) * 4;
+ rp_object->rect[render_pass_offset] = accum_buffer[accum_buffer_offset].hash;
+ rp_object->rect[render_pass_offset + 1] = accum_buffer[accum_buffer_offset].weight;
+ if (levels_done + 1 < num_cryptomatte_levels) {
+ rp_object->rect[render_pass_offset + 2] = accum_buffer[accum_buffer_offset + 1].hash;
+ rp_object->rect[render_pass_offset + 3] = accum_buffer[accum_buffer_offset + 1].weight;
+ }
+ else {
+ rp_object->rect[render_pass_offset + 2] = 0.0f;
+ rp_object->rect[render_pass_offset + 3] = 0.0f;
+ }
+ }
+ }
+ levels_done++;
+ }
+}
+
+void EEVEE_cryptomatte_render_result(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *UNUSED(sldata))
+{
+ EEVEE_PrivateData *g_data = vedata->stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = draw_ctx->view_layer;
+ const eViewLayerCryptomatteFlags cryptomatte_layers = view_layer->cryptomatte_flag &
+ VIEW_LAYER_CRYPTOMATTE_ALL;
+
+ eevee_cryptomatte_postprocess_weights(vedata);
+
+ const int rect_width = BLI_rcti_size_x(rect);
+ const int rect_height = BLI_rcti_size_y(rect);
+ const int rect_offset_x = vedata->stl->g_data->overscan_pixels + rect->xmin;
+ const int rect_offset_y = vedata->stl->g_data->overscan_pixels + rect->ymin;
+ const float *viewport_size = DRW_viewport_size_get();
+ const int viewport_width = viewport_size[0];
+ EEVEE_CryptomatteSample *accum_buffer = g_data->cryptomatte_accum_buffer;
+ BLI_assert(accum_buffer);
+ const int num_cryptomatte_levels = view_layer->cryptomatte_levels;
+ const int num_cryptomatte_passes = eevee_cryptomatte_passes_per_layer(view_layer);
+ const int layer_stride = eevee_cryptomatte_layer_stride(view_layer);
+ const int accum_pixel_stride = eevee_cryptomatte_pixel_stride(view_layer);
+
+ int layer_index = 0;
+ if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) {
+ eevee_cryptomatte_extract_render_passes(rl,
+ viewname,
+ "CryptoObject%02d",
+ accum_buffer,
+ num_cryptomatte_passes,
+ num_cryptomatte_levels,
+ accum_pixel_stride,
+ layer_stride,
+ layer_index,
+ rect_width,
+ rect_height,
+ rect_offset_x,
+ rect_offset_y,
+ viewport_width);
+ layer_index++;
+ }
+ if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) {
+ eevee_cryptomatte_extract_render_passes(rl,
+ viewname,
+ "CryptoMaterial%02d",
+ accum_buffer,
+ num_cryptomatte_passes,
+ num_cryptomatte_levels,
+ accum_pixel_stride,
+ layer_stride,
+ layer_index,
+ rect_width,
+ rect_height,
+ rect_offset_x,
+ rect_offset_y,
+ viewport_width);
+ layer_index++;
+ }
+ if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) {
+ eevee_cryptomatte_extract_render_passes(rl,
+ viewname,
+ "CryptoAsset%02d",
+ accum_buffer,
+ num_cryptomatte_passes,
+ num_cryptomatte_levels,
+ accum_pixel_stride,
+ layer_stride,
+ layer_index,
+ rect_width,
+ rect_height,
+ rect_offset_x,
+ rect_offset_y,
+ viewport_width);
+ layer_index++;
+ }
+}
+
+/** \} */
+
+void EEVEE_cryptomatte_free(EEVEE_Data *vedata)
+{
+ EEVEE_PrivateData *g_data = vedata->stl->g_data;
+ MEM_SAFE_FREE(g_data->cryptomatte_accum_buffer);
+ MEM_SAFE_FREE(g_data->cryptomatte_download_buffer);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 5c4ee015c86..47068d0b843 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -240,6 +240,9 @@ void EEVEE_view_layer_data_free(void *storage)
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_light);
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.emit);
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.environment);
+ for (int aov_index = 0; aov_index < MAX_AOVS; aov_index++) {
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]);
+ }
if (sldata->material_cache) {
BLI_memblock_destroy(sldata->material_cache, NULL);
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index 7d1f40ba5d8..f233b0fda96 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -570,6 +570,8 @@ static void eevee_render_to_image(void *vedata,
EEVEE_motion_blur_data_free(&ved->stl->effects->motion_blur);
if (RE_engine_test_break(engine)) {
+ /* Cryptomatte buffers are freed during render_read_result */
+ EEVEE_cryptomatte_free(vedata);
return;
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 58f182ecf8d..c7a8f7729eb 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -244,31 +244,31 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
/* Create RenderPass UBO */
if (sldata->renderpass_ubo.combined == NULL) {
EEVEE_RenderPassData data;
- data = (EEVEE_RenderPassData){true, true, true, true, true, false, false};
+ data = (EEVEE_RenderPassData){true, true, true, true, true, false, false, false, 0};
sldata->renderpass_ubo.combined = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.combined");
- data = (EEVEE_RenderPassData){true, false, false, false, false, true, false};
+ data = (EEVEE_RenderPassData){true, false, false, false, false, true, false, false, 0};
sldata->renderpass_ubo.diff_color = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.diff_color");
- data = (EEVEE_RenderPassData){true, true, false, false, false, false, false};
+ data = (EEVEE_RenderPassData){true, true, false, false, false, false, false, false, 0};
sldata->renderpass_ubo.diff_light = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.diff_light");
- data = (EEVEE_RenderPassData){false, false, true, false, false, false, false};
+ data = (EEVEE_RenderPassData){false, false, true, false, false, false, false, false, 0};
sldata->renderpass_ubo.spec_color = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.spec_color");
- data = (EEVEE_RenderPassData){false, false, true, true, false, false, false};
+ data = (EEVEE_RenderPassData){false, false, true, true, false, false, false, false, 0};
sldata->renderpass_ubo.spec_light = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.spec_light");
- data = (EEVEE_RenderPassData){false, false, false, false, true, false, false};
+ data = (EEVEE_RenderPassData){false, false, false, false, true, false, false, false, 0};
sldata->renderpass_ubo.emit = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.emit");
- data = (EEVEE_RenderPassData){true, true, true, true, true, false, true};
+ data = (EEVEE_RenderPassData){true, true, true, true, true, false, true, false, 0};
sldata->renderpass_ubo.environment = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.environment");
}
@@ -276,6 +276,51 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
/* Used combined pass by default. */
g_data->renderpass_ubo = sldata->renderpass_ubo.combined;
+ {
+ g_data->num_aovs_used = 0;
+ if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) {
+ EEVEE_RenderPassData data = {true, true, true, true, true, false, false, true, 0};
+ if (stl->g_data->aov_hash == EEVEE_AOV_HASH_ALL) {
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ int aov_index = 0;
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) != 0) {
+ continue;
+ }
+ if (aov_index == MAX_AOVS) {
+ break;
+ }
+ data.renderPassAOVActive = EEVEE_renderpasses_aov_hash(aov);
+ if (sldata->renderpass_ubo.aovs[aov_index]) {
+ GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[aov_index], &data);
+ }
+ else {
+ sldata->renderpass_ubo.aovs[aov_index] = GPU_uniformbuf_create_ex(
+ sizeof(data), &data, "renderpass_ubo.aovs");
+ }
+ aov_index++;
+ }
+ g_data->num_aovs_used = aov_index;
+ }
+ else {
+ /* Rendering a single AOV in the 3d viewport */
+ data.renderPassAOVActive = stl->g_data->aov_hash;
+ if (sldata->renderpass_ubo.aovs[0]) {
+ GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[0], &data);
+ }
+ else {
+ sldata->renderpass_ubo.aovs[0] = GPU_uniformbuf_create_ex(
+ sizeof(data), &data, "renderpass_ubo.aovs");
+ }
+ g_data->num_aovs_used = 1;
+ }
+ }
+ /* Free AOV UBO's that are not in use. */
+ for (int aov_index = g_data->num_aovs_used; aov_index < MAX_AOVS; aov_index++) {
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]);
+ }
+ }
+
/* HACK: EEVEE_material_get can create a new context. This can only be
* done when there is no active framebuffer. We do this here otherwise
* `EEVEE_renderpasses_output_init` will fail. It cannot be done in
@@ -949,6 +994,11 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear);
}
+ if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
+ for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
+ material_renderpass_init(fbl, &txl->aov_surface_accum[aov_index], texture_format, do_clear);
+ }
+ }
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear);
@@ -960,6 +1010,7 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
DRWPass *renderpass,
+ DRWPass *renderpass2,
EEVEE_PrivateData *pd,
GPUTexture *output_tx,
struct GPUUniformBuf *renderpass_option_ubo)
@@ -969,6 +1020,9 @@ static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
pd->renderpass_ubo = renderpass_option_ubo;
DRW_draw_pass(renderpass);
+ if (renderpass2) {
+ DRW_draw_pass(renderpass2);
+ }
GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx);
}
@@ -983,38 +1037,69 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
if (fbl->material_accum_fb != NULL) {
DRWPass *material_accum_ps = psl->material_accum_ps;
+ DRWPass *background_accum_ps = psl->background_accum_ps;
if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
material_renderpass_accumulate(
- fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.environment);
+ fbl, background_accum_ps, NULL, pd, txl->env_accum, sldata->renderpass_ubo.environment);
}
if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) {
material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
+ fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->diff_color_accum,
+ sldata->renderpass_ubo.diff_color);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->diff_light_accum,
+ sldata->renderpass_ubo.diff_light);
if (effects->enabled_effects & EFFECT_SSS) {
EEVEE_subsurface_output_accumulate(sldata, vedata);
}
}
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->spec_color_accum,
+ sldata->renderpass_ubo.spec_color);
}
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->spec_light_accum,
+ sldata->renderpass_ubo.spec_light);
if (effects->enabled_effects & EFFECT_SSR) {
EEVEE_reflection_output_accumulate(sldata, vedata);
}
}
+ if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
+ for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ background_accum_ps,
+ pd,
+ txl->aov_surface_accum[aov_index],
+ sldata->renderpass_ubo.aovs[aov_index]);
+ }
+ }
+ /* Free unused aov textures. */
+ for (int aov_index = pd->num_aovs_used; aov_index < MAX_AOVS; aov_index++) {
+ DRW_TEXTURE_FREE_SAFE(txl->aov_surface_accum[aov_index]);
+ }
/* Restore default. */
pd->renderpass_ubo = sldata->renderpass_ubo.combined;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f5cef8f3c25..a6a480ca967 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -53,6 +53,7 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
+#define MAX_AOVS 64
// #define DEBUG_SHADOW_DISTRIBUTION
@@ -163,7 +164,10 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d)
#define EEVEE_RENDERPASSES_MATERIAL \
(EEVEE_RENDER_PASS_EMIT | EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_DIFFUSE_LIGHT | \
EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_SPECULAR_LIGHT | \
- EEVEE_RENDER_PASS_ENVIRONMENT)
+ EEVEE_RENDER_PASS_ENVIRONMENT | EEVEE_RENDER_PASS_AOV)
+#define EEVEE_AOV_HASH_ALL -1
+#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1
+#define MAX_CRYPTOMATTE_LAYERS 3
/* Material shader variations */
enum {
@@ -293,6 +297,7 @@ typedef struct EEVEE_PassList {
/* Renderpass Accumulation. */
struct DRWPass *material_accum_ps;
struct DRWPass *background_accum_ps;
+ struct DRWPass *cryptomatte_ps;
struct DRWPass *depth_ps;
struct DRWPass *depth_cull_ps;
@@ -325,6 +330,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP];
struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1];
struct GPUFrameBuffer *bloom_pass_accum_fb;
+ struct GPUFrameBuffer *cryptomatte_fb;
struct GPUFrameBuffer *shadow_accum_fb;
struct GPUFrameBuffer *ssr_accum_fb;
struct GPUFrameBuffer *sss_blur_fb;
@@ -376,10 +382,12 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *diff_light_accum;
struct GPUTexture *spec_color_accum;
struct GPUTexture *spec_light_accum;
+ struct GPUTexture *aov_surface_accum[MAX_AOVS];
struct GPUTexture *emit_accum;
struct GPUTexture *bloom_accum;
struct GPUTexture *ssr_accum;
struct GPUTexture *shadow_accum;
+ struct GPUTexture *cryptomatte;
struct GPUTexture *refract_color;
struct GPUTexture *taa_history;
@@ -430,7 +438,9 @@ typedef struct EEVEE_RenderPassData {
int renderPassEmit;
int renderPassSSSColor;
int renderPassEnvironment;
- int _pad[1];
+ int renderPassAOV;
+ int renderPassAOVActive;
+ int _pad[3];
} EEVEE_RenderPassData;
/* ************ LIGHT UBO ************* */
@@ -860,6 +870,7 @@ typedef struct EEVEE_ViewLayerData {
struct GPUUniformBuf *spec_color;
struct GPUUniformBuf *spec_light;
struct GPUUniformBuf *emit;
+ struct GPUUniformBuf *aovs[MAX_AOVS];
} renderpass_ubo;
/* Common Uniform Buffer */
@@ -904,6 +915,11 @@ typedef struct EEVEE_WorldEngineData {
DrawData dd;
} EEVEE_WorldEngineData;
+typedef struct EEVEE_CryptomatteSample {
+ float hash;
+ float weight;
+} EEVEE_CryptomatteSample;
+
/* *********************************** */
typedef struct EEVEE_Data {
@@ -959,6 +975,12 @@ typedef struct EEVEE_PrivateData {
/* Renderpasses */
/* Bitmask containing the active render_passes */
eViewLayerEEVEEPassType render_passes;
+ int aov_hash;
+ int num_aovs_used;
+ bool cryptomatte_accurate_mode;
+ EEVEE_CryptomatteSample *cryptomatte_accum_buffer;
+ float *cryptomatte_download_buffer;
+
/* Uniform references that are referenced inside the `renderpass_pass`. They are updated
* to reuse the drawing pass and the shading group. */
int renderpass_type;
@@ -1111,6 +1133,7 @@ struct GPUShader *EEVEE_shaders_effect_ambient_occlusion_layer_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_screen_raytrace_sh_get(EEVEE_SSRShaderOptions options);
struct GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void);
+struct GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair);
struct GPUShader *EEVEE_shaders_shadow_sh_get(void);
struct GPUShader *EEVEE_shaders_shadow_accum_sh_get(void);
struct GPUShader *EEVEE_shaders_subsurface_first_pass_sh_get(void);
@@ -1215,6 +1238,30 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata);
void EEVEE_bloom_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples);
void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/* eevee_cryptomatte.c */
+void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata);
+void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ int tot_samples);
+void EEVEE_cryptomatte_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_cryptomatte_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob);
+void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Object *ob);
+void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Object *ob);
+void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_cryptomatte_update_passes(struct RenderEngine *engine,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
+void EEVEE_cryptomatte_render_result(struct RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata);
+void EEVEE_cryptomatte_free(EEVEE_Data *vedata);
+
/* eevee_occlusion.c */
int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata,
@@ -1284,10 +1331,12 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
bool post_effect);
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type);
+ eViewLayerEEVEEPassType renderpass_type,
+ int aov_index);
void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata);
bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata);
+int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
/* eevee_temporal_sampling.c */
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 504e4e1d336..2b2ff2e5c90 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -191,6 +191,7 @@ void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_subsurface_cache_init(sldata, vedata);
EEVEE_temporal_sampling_cache_init(sldata, vedata);
EEVEE_volumes_cache_init(sldata, vedata);
+ EEVEE_cryptomatte_cache_init(sldata, vedata);
}
/* Used by light cache. in this case engine is NULL. */
@@ -200,9 +201,15 @@ void EEVEE_render_cache(void *vedata,
struct Depsgraph *depsgraph)
{
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_Data *data = vedata;
+ EEVEE_StorageList *stl = data->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
bool cast_shadow = false;
+ const bool do_cryptomatte = (engine != NULL) &&
+ ((g_data->render_passes & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0);
+
eevee_id_update(vedata, &ob->id);
if (pinfo->vis_data.collection) {
@@ -227,14 +234,23 @@ void EEVEE_render_cache(void *vedata,
const int ob_visibility = DRW_object_visibility_in_active_context(ob);
if (ob_visibility & OB_VISIBLE_PARTICLES) {
EEVEE_particle_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
+ if (do_cryptomatte) {
+ EEVEE_cryptomatte_particle_hair_cache_populate(data, sldata, ob);
+ }
}
if (ob_visibility & OB_VISIBLE_SELF) {
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
+ if (do_cryptomatte) {
+ EEVEE_cryptomatte_cache_populate(data, sldata, ob);
+ }
}
else if (ob->type == OB_HAIR) {
EEVEE_object_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
+ if (do_cryptomatte) {
+ EEVEE_cryptomatte_object_hair_cache_populate(data, sldata, ob);
+ }
}
else if (ob->type == OB_VOLUME) {
Scene *scene = DEG_get_evaluated_scene(depsgraph);
@@ -301,7 +317,7 @@ static void eevee_render_result_normal(RenderLayer *rl,
}
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_NORMAL) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -321,7 +337,7 @@ static void eevee_render_result_z(RenderLayer *rl,
}
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_Z) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata);
}
@@ -334,7 +350,7 @@ static void eevee_render_result_mist(RenderLayer *rl,
EEVEE_ViewLayerData *sldata)
{
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_MIST) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata);
}
@@ -347,7 +363,7 @@ static void eevee_render_result_shadow(RenderLayer *rl,
EEVEE_ViewLayerData *sldata)
{
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_SHADOW) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_SHADOW, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -360,7 +376,7 @@ static void eevee_render_result_occlusion(RenderLayer *rl,
EEVEE_ViewLayerData *sldata)
{
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AO) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -378,7 +394,7 @@ static void eevee_render_result_bloom(RenderLayer *rl,
}
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_BLOOM) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_BLOOM, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -386,7 +402,7 @@ static void eevee_render_result_bloom(RenderLayer *rl,
#define EEVEE_RENDER_RESULT_MATERIAL_PASS(pass_name, eevee_pass_type) \
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_##eevee_pass_type) != 0) { \
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type); \
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type, 0); \
eevee_render_color_result( \
rl, viewname, rect, RE_PASSNAME_##pass_name, 3, vedata->fbl->renderpass_fb, vedata); \
}
@@ -462,8 +478,49 @@ static void eevee_render_result_volume_transmittance(RenderLayer *rl,
EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_TRANSMITTANCE, VOLUME_TRANSMITTANCE)
}
+static void eevee_render_result_aovs(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata)
+{
+ if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ int aov_index = 0;
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) != 0) {
+ continue;
+ }
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AOV, aov_index);
+ switch (aov->type) {
+ case AOV_TYPE_COLOR:
+ eevee_render_color_result(
+ rl, viewname, rect, aov->name, 4, vedata->fbl->renderpass_fb, vedata);
+ break;
+ case AOV_TYPE_VALUE:
+ eevee_render_color_result(
+ rl, viewname, rect, aov->name, 1, vedata->fbl->renderpass_fb, vedata);
+ }
+ aov_index++;
+ }
+ }
+}
+
#undef EEVEE_RENDER_RESULT_MATERIAL_PASS
+static void eevee_render_result_cryptomatte(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata)
+{
+ if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0) {
+ EEVEE_cryptomatte_render_result(rl, viewname, rect, vedata, sldata);
+ }
+ EEVEE_cryptomatte_free(vedata);
+}
+
static void eevee_render_draw_background(EEVEE_Data *vedata)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
@@ -641,6 +698,8 @@ void EEVEE_render_read_result(EEVEE_Data *vedata,
eevee_render_result_bloom(rl, viewname, rect, vedata, sldata);
eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata);
eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_aovs(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_cryptomatte(rl, viewname, rect, vedata, sldata);
}
void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
@@ -675,6 +734,23 @@ void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *v
CHECK_PASS_EEVEE(VOLUME_TRANSMITTANCE, SOCK_RGBA, 3, "RGB");
CHECK_PASS_EEVEE(BLOOM, SOCK_RGBA, 3, "RGB");
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) != 0) {
+ continue;
+ }
+ switch (aov->type) {
+ case AOV_TYPE_COLOR:
+ RE_engine_register_pass(engine, scene, view_layer, aov->name, 4, "RGBA", SOCK_RGBA);
+ break;
+ case AOV_TYPE_VALUE:
+ RE_engine_register_pass(engine, scene, view_layer, aov->name, 1, "X", SOCK_FLOAT);
+ break;
+ default:
+ break;
+ }
+ }
+ EEVEE_cryptomatte_update_passes(engine, scene, view_layer);
+
#undef CHECK_PASS_LEGACY
#undef CHECK_PASS_EEVEE
}
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index be73225b348..e7a03c678a8 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -27,6 +27,7 @@
#include "BKE_global.h" /* for G.debug_value */
+#include "BLI_hash.h"
#include "BLI_string_utils.h"
#include "DEG_depsgraph_query.h"
@@ -36,12 +37,13 @@
typedef enum eRenderPassPostProcessType {
PASS_POST_UNDEFINED = 0,
PASS_POST_ACCUMULATED_COLOR = 1,
- PASS_POST_ACCUMULATED_LIGHT = 2,
- PASS_POST_ACCUMULATED_VALUE = 3,
- PASS_POST_DEPTH = 4,
- PASS_POST_AO = 5,
- PASS_POST_NORMAL = 6,
- PASS_POST_TWO_LIGHT_BUFFERS = 7,
+ PASS_POST_ACCUMULATED_COLOR_ALPHA = 2,
+ PASS_POST_ACCUMULATED_LIGHT = 3,
+ PASS_POST_ACCUMULATED_VALUE = 4,
+ PASS_POST_DEPTH = 5,
+ PASS_POST_AO = 6,
+ PASS_POST_NORMAL = 7,
+ PASS_POST_TWO_LIGHT_BUFFERS = 8,
} eRenderPassPostProcessType;
/* bitmask containing all renderpasses that need post-processing */
@@ -70,6 +72,15 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
}
+/* Calculate the hash for an AOV. The least significant bit is used to store the AOV
+ * type the rest of the bits are used for the name hash. */
+int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov)
+{
+ int hash = BLI_hash_string(aov->name);
+ SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK);
+ return hash;
+}
+
void EEVEE_renderpasses_init(EEVEE_Data *vedata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -81,10 +92,24 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata)
if (v3d) {
const Scene *scene = draw_ctx->scene;
eViewLayerEEVEEPassType render_pass = v3d->shading.render_pass;
+ g_data->aov_hash = 0;
+
if (render_pass == EEVEE_RENDER_PASS_BLOOM &&
((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
render_pass = EEVEE_RENDER_PASS_COMBINED;
}
+ if (render_pass == EEVEE_RENDER_PASS_AOV) {
+ ViewLayerAOV *aov = BLI_findstring(
+ &view_layer->aovs, v3d->shading.aov_name, offsetof(ViewLayerAOV, name));
+ if (aov != NULL) {
+ g_data->aov_hash = EEVEE_renderpasses_aov_hash(aov);
+ }
+ else {
+ /* AOV not found in view layer. */
+ render_pass = EEVEE_RENDER_PASS_COMBINED;
+ }
+ }
+
g_data->render_passes = render_pass;
}
else {
@@ -110,11 +135,16 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata)
ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT)
#undef ENABLE_FROM_LEGACY
+ if (DRW_state_is_image_render() && !BLI_listbase_is_empty(&view_layer->aovs)) {
+ enabled_render_passes |= EEVEE_RENDER_PASS_AOV;
+ g_data->aov_hash = EEVEE_AOV_HASH_ALL;
+ }
+
g_data->render_passes = (enabled_render_passes & EEVEE_RENDERPASSES_ALL) |
EEVEE_RENDER_PASS_COMBINED;
}
-
EEVEE_material_renderpasses_init(vedata);
+ EEVEE_cryptomatte_renderpasses_init(vedata);
}
void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
@@ -174,6 +204,11 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
DRW_TEXTURE_FREE_SAFE(txl->renderpass);
GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb);
}
+
+ /* Cryptomatte doesn't use the GPU shader for post processing */
+ if ((g_data->render_passes & (EEVEE_RENDER_PASS_CRYPTOMATTE)) != 0) {
+ EEVEE_cryptomatte_output_init(sldata, vedata, tot_samples);
+ }
}
void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
@@ -216,7 +251,8 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
* After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type)
+ eViewLayerEEVEEPassType renderpass_type,
+ int aov_index)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
@@ -311,6 +347,11 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
}
break;
}
+ case EEVEE_RENDER_PASS_AOV: {
+ g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR_ALPHA;
+ g_data->renderpass_input = txl->aov_surface_accum[aov_index];
+ break;
+ }
case EEVEE_RENDER_PASS_BLOOM: {
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
g_data->renderpass_input = txl->bloom_accum;
@@ -350,6 +391,9 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
(EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_VOLUME_SCATTER)) != 0) {
EEVEE_volumes_output_accumulate(sldata, vedata);
}
+ if ((render_pass & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0) {
+ EEVEE_cryptomatte_output_accumulate(sldata, vedata);
+ }
}
else {
if ((render_pass & EEVEE_RENDER_PASS_BLOOM) != 0 &&
@@ -392,7 +436,7 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
if (is_valid) {
- EEVEE_renderpasses_postprocess(sldata, vedata, render_pass);
+ EEVEE_renderpasses_postprocess(sldata, vedata, render_pass, 0);
GPU_framebuffer_bind(dfbl->default_fb);
DRW_transform_none(txl->renderpass);
}
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index f46a98ed845..7a277c18f01 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -121,6 +121,7 @@ static struct {
/* Render Passes */
struct GPUShader *postprocess_sh;
+ struct GPUShader *cryptomatte_sh[2];
/* Screen Space Reflection */
struct GPUShader *ssr_sh[SSR_MAX_SHADER];
@@ -186,6 +187,7 @@ extern char datatoc_btdf_lut_frag_glsl[];
extern char datatoc_closure_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_common_utiltex_lib_glsl[];
+extern char datatoc_cryptomatte_frag_glsl[];
extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_default_frag_glsl[];
extern char datatoc_lookdev_world_frag_glsl[];
@@ -695,6 +697,34 @@ GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Cryptomatte
+ * \{ */
+
+GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
+{
+ const int index = is_hair ? 1 : 0;
+ if (e_data.cryptomatte_sh[index] == NULL) {
+ DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, SHADER_DEFINES);
+
+ if (is_hair) {
+ BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
+ }
+ else {
+ BLI_dynstr_append(ds, "#define MESH_SHADER\n");
+ }
+ char *defines = BLI_dynstr_get_cstring(ds);
+ e_data.cryptomatte_sh[index] = DRW_shader_create_with_shaderlib(
+ datatoc_surface_vert_glsl, NULL, datatoc_cryptomatte_frag_glsl, e_data.lib, defines);
+ BLI_dynstr_free(ds);
+ MEM_freeN(defines);
+ }
+ return e_data.cryptomatte_sh[index];
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Screen Raytrace
* \{ */
@@ -1428,6 +1458,8 @@ void EEVEE_shaders_free(void)
DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh);
+ DRW_SHADER_FREE_SAFE(e_data.cryptomatte_sh[0]);
+ DRW_SHADER_FREE_SAFE(e_data.cryptomatte_sh[1]);
for (int i = 0; i < 2; i++) {
DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[i]);
diff --git a/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl b/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl
new file mode 100644
index 00000000000..1e499dbf991
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl
@@ -0,0 +1,7 @@
+uniform vec4 cryptohash;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = cryptohash;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
index 36cf3cecf40..3e0a5e76d00 100644
--- a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
@@ -1,3 +1,4 @@
+#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1
/* ---------------------------------------------------------------------- */
/** \name Resources
@@ -12,6 +13,8 @@ layout(std140) uniform renderpass_block
bool renderPassEmit;
bool renderPassSSSColor;
bool renderPassEnvironment;
+ bool renderPassAOV;
+ int renderPassAOVActive;
};
/** \} */
@@ -40,4 +43,14 @@ vec3 render_pass_emission_mask(vec3 emission_light)
return renderPassEmit ? emission_light : vec3(0.0);
}
+bool render_pass_aov_is_color()
+{
+ return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0;
+}
+
+int render_pass_aov_hash()
+{
+ return renderPassAOVActive & ~EEVEE_AOV_HASH_COLOR_TYPE_MASK;
+}
+
/** \} */
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
index 89a411bc7cb..eb6ca4b9de8 100644
--- a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
@@ -4,12 +4,13 @@
#define PASS_POST_UNDEFINED 0
#define PASS_POST_ACCUMULATED_COLOR 1
-#define PASS_POST_ACCUMULATED_LIGHT 2
-#define PASS_POST_ACCUMULATED_VALUE 3
-#define PASS_POST_DEPTH 4
-#define PASS_POST_AO 5
-#define PASS_POST_NORMAL 6
-#define PASS_POST_TWO_LIGHT_BUFFERS 7
+#define PASS_POST_ACCUMULATED_COLOR_ALPHA 2
+#define PASS_POST_ACCUMULATED_LIGHT 3
+#define PASS_POST_ACCUMULATED_VALUE 4
+#define PASS_POST_DEPTH 5
+#define PASS_POST_AO 6
+#define PASS_POST_NORMAL 7
+#define PASS_POST_TWO_LIGHT_BUFFERS 8
uniform int postProcessType;
uniform int currentSample;
@@ -55,7 +56,7 @@ vec3 safe_divide_even_color(vec3 a, vec3 b)
void main()
{
- vec3 color;
+ vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
ivec2 texel = ivec2(gl_FragCoord.xy);
if (postProcessType == PASS_POST_DEPTH) {
@@ -66,11 +67,11 @@ void main()
else {
depth = -get_view_z_from_depth(depth);
}
- color = vec3(depth);
+ color.rgb = vec3(depth);
}
else if (postProcessType == PASS_POST_AO) {
float ao_accum = texelFetch(inputBuffer, texel, 0).r;
- color = vec3(min(1.0, ao_accum / currentSample));
+ color.rgb = vec3(min(1.0, ao_accum / currentSample));
}
else if (postProcessType == PASS_POST_NORMAL) {
float depth = texelFetch(depthBuffer, texel, 0).r;
@@ -80,35 +81,39 @@ void main()
if (depth != 1.0 && any(notEqual(encoded_normal, vec2(0.0)))) {
vec3 decoded_normal = normal_decode(texelFetch(inputBuffer, texel, 0).rg, vec3(0.0));
vec3 world_normal = mat3(ViewMatrixInverse) * decoded_normal;
- color = world_normal;
+ color.rgb = world_normal;
}
else {
- color = vec3(0.0);
+ color.rgb = vec3(0.0);
}
}
else if (postProcessType == PASS_POST_ACCUMULATED_VALUE) {
float accumulated_value = texelFetch(inputBuffer, texel, 0).r;
- color = vec3(accumulated_value / currentSample);
+ color.rgb = vec3(accumulated_value / currentSample);
}
else if (postProcessType == PASS_POST_ACCUMULATED_COLOR) {
vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb;
+ color.rgb = (accumulated_color / currentSample);
+ }
+ else if (postProcessType == PASS_POST_ACCUMULATED_COLOR_ALPHA) {
+ vec4 accumulated_color = texelFetch(inputBuffer, texel, 0);
color = (accumulated_color / currentSample);
}
else if (postProcessType == PASS_POST_ACCUMULATED_LIGHT) {
vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb;
vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb;
- color = safe_divide_even_color(accumulated_light, accumulated_color);
+ color.rgb = safe_divide_even_color(accumulated_light, accumulated_color);
}
else if (postProcessType == PASS_POST_TWO_LIGHT_BUFFERS) {
vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb +
texelFetch(inputSecondLightBuffer, texel, 0).rgb;
vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb;
- color = safe_divide_even_color(accumulated_light, accumulated_color);
+ color.rgb = safe_divide_even_color(accumulated_light, accumulated_color);
}
else {
/* Output error color: Unknown how to post process this pass. */
- color = vec3(1.0, 0.0, 1.0);
+ color.rgb = vec3(1.0, 0.0, 1.0);
}
- fragColor = vec4(color, 1.0);
+ fragColor = color;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 368530fde05..519b015a6ad 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -252,7 +252,7 @@ void GPENCIL_cache_init(void *ved)
pd->do_fast_drawing = false;
pd->obact = draw_ctx->obact;
- if (pd->obact && pd->obact->type == OB_GPENCIL) {
+ if (pd->obact && pd->obact->type == OB_GPENCIL && !(pd->draw_depth_only)) {
/* Check if active object has a temp stroke data. */
bGPdata *gpd = (bGPdata *)pd->obact->data;
if (gpd->runtime.sbuffer_used > 0) {
@@ -498,7 +498,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
bool hide_onion = gpl && gpf && gpf->runtime.onion_id != 0 &&
((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0);
- if (hide_material || (!show_stroke && !show_fill) || only_lines || hide_onion) {
+ if (hide_material || (!show_stroke && !show_fill) || (only_lines && hide_onion) || hide_onion) {
return;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index d01aaaed8b0..cb65fbd6ae7 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -95,7 +95,7 @@ static DRWShadingGroup *gpencil_vfx_pass_create(const char *name,
static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx->radius[0] == 0.0f && fx->radius[1] == 0.0f) {
+ if ((fx->samples == 0.0f) || (fx->radius[0] == 0.0f && fx->radius[1] == 0.0f)) {
return;
}
diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/image/image_private.h
index ad7ff78cb41..d5821cc5d70 100644
--- a/source/blender/draw/engines/image/image_private.h
+++ b/source/blender/draw/engines/image/image_private.h
@@ -43,7 +43,7 @@ typedef struct IMAGE_PrivateData {
void *lock;
struct ImBuf *ibuf;
struct Image *image;
- struct DRWView* view;
+ struct DRWView *view;
struct GPUTexture *texture;
bool owns_texture;
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index 39d8e45cc19..d365f76aabe 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -332,6 +332,8 @@ TEST_F(DrawTest, eevee_glsl_shaders_static)
EXPECT_NE(EEVEE_shaders_probe_grid_fill_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_planar_downsample_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_renderpasses_post_process_sh_get(), nullptr);
+ EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(false), nullptr);
+ EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_shadow_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_shadow_accum_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_subsurface_first_pass_sh_get(), nullptr);