diff options
Diffstat (limited to 'source')
80 files changed, 2982 insertions, 1184 deletions
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 1d44604384a..7c5e9af728a 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -339,37 +339,32 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); BLI_path_abs(temp_dir, relbase); - if (BLI_exists(temp_dir)) { - BLI_delete(temp_dir, true, true); - } + BLI_delete(temp_dir, true, true); /* BLI_exists(filepath) is implicit */ + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL); BLI_path_abs(temp_dir, relbase); - if (BLI_exists(temp_dir)) { - BLI_delete(temp_dir, true, true); - } + BLI_delete(temp_dir, true, true); /* BLI_exists(filepath) is implicit */ + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL); BLI_path_abs(temp_dir, relbase); - if (BLI_exists(temp_dir)) { - BLI_delete(temp_dir, true, true); - } + BLI_delete(temp_dir, true, true); /* BLI_exists(filepath) is implicit */ + mds->cache_frame_pause_data = 0; } if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) { flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL); BLI_path_abs(temp_dir, relbase); - if (BLI_exists(temp_dir)) { - BLI_delete(temp_dir, true, true); - } + BLI_delete(temp_dir, true, true); /* BLI_exists(filepath) is implicit */ + mds->cache_frame_pause_noise = 0; } if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) { flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL); BLI_path_abs(temp_dir, relbase); - if (BLI_exists(temp_dir)) { - BLI_delete(temp_dir, true, true); - } + BLI_delete(temp_dir, true, true); /* BLI_exists(filepath) is implicit */ + mds->cache_frame_pause_mesh = 0; } if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) { @@ -378,9 +373,8 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) BLI_path_join( temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL); BLI_path_abs(temp_dir, relbase); - if (BLI_exists(temp_dir)) { - BLI_delete(temp_dir, true, true); - } + BLI_delete(temp_dir, true, true); /* BLI_exists(filepath) is implicit */ + mds->cache_frame_pause_particles = 0; } @@ -388,9 +382,8 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE); BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL); BLI_path_abs(temp_dir, relbase); - if (BLI_exists(temp_dir)) { - BLI_delete(temp_dir, true, true); - } + BLI_delete(temp_dir, true, true); /* BLI_exists(filepath) is implicit */ + mds->cache_frame_pause_guide = 0; } mds->cache_flag = flags; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 500c58095e6..483838ed741 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -140,7 +140,7 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet) { MovieTrackingDopesheetChannel *channel; - /* Free channel's sergments. */ + /* Free channel's segments. */ channel = dopesheet->channels.first; while (channel) { if (channel->segments) { diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 5c20e57181e..3ee22e4ad0a 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -73,6 +73,29 @@ int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_ int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer); #endif +typedef enum eFileAttributes { + FILE_ATTR_READONLY = 1 << 0, /* Read-only or Immutable. */ + FILE_ATTR_HIDDEN = 1 << 1, /* Hidden or invisible. */ + FILE_ATTR_SYSTEM = 1 << 2, /* Used by the Operating System. */ + FILE_ATTR_ARCHIVE = 1 << 3, /* Marked as archived. */ + FILE_ATTR_COMPRESSED = 1 << 4, /* Compressed. */ + FILE_ATTR_ENCRYPTED = 1 << 5, /* Encrypted. */ + FILE_ATTR_RESTRICTED = 1 << 6, /* Protected by OS. */ + FILE_ATTR_TEMPORARY = 1 << 7, /* Used for temporary storage. */ + FILE_ATTR_SPARSE_FILE = 1 << 8, /* Sparse File. */ + FILE_ATTR_OFFLINE = 1 << 9, /* Data is not immediately available. */ + FILE_ATTR_ALIAS = 1 << 10, /* Mac Alias or Windows Lnk. File-based redirection. */ + FILE_ATTR_REPARSE_POINT = 1 << 11, /* File has associated reparse point. */ + FILE_ATTR_SYMLINK = 1 << 12, /* Reference to another file. */ + FILE_ATTR_JUNCTION_POINT = 1 << 13, /* Folder Symlink. */ + FILE_ATTR_MOUNT_POINT = 1 << 14, /* Volume mounted as a folder. */ + FILE_ATTR_HARDLINK = 1 << 15, /* Duplicated directory entry. */ +} eFileAttributes; + +#define FILE_ATTR_ANY_LINK \ + (FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \ + FILE_ATTR_MOUNT_POINT | FILE_ATTR_HARDLINK) + /* Directories */ struct direntry; @@ -83,6 +106,7 @@ bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL(); double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); char *BLI_current_working_dir(char *dir, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +eFileAttributes BLI_file_attributes(const char *path); /* Filelist */ diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 7c481868d64..04b3e8abca2 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -199,6 +199,69 @@ size_t BLI_file_size(const char *path) return stats.st_size; } +eFileAttributes BLI_file_attributes(const char *path) +{ + int ret = 0; + +#ifdef WIN32 + wchar_t wline[FILE_MAXDIR]; + BLI_strncpy_wchar_from_utf8(wline, path, ARRAY_SIZE(wline)); + DWORD attr = GetFileAttributesW(wline); + if (attr & FILE_ATTRIBUTE_READONLY) { + ret |= FILE_ATTR_READONLY; + } + if (attr & FILE_ATTRIBUTE_HIDDEN) { + ret |= FILE_ATTR_HIDDEN; + } + if (attr & FILE_ATTRIBUTE_SYSTEM) { + ret |= FILE_ATTR_SYSTEM; + } + if (attr & FILE_ATTRIBUTE_ARCHIVE) { + ret |= FILE_ATTR_ARCHIVE; + } + if (attr & FILE_ATTRIBUTE_COMPRESSED) { + ret |= FILE_ATTR_COMPRESSED; + } + if (attr & FILE_ATTRIBUTE_ENCRYPTED) { + ret |= FILE_ATTR_ENCRYPTED; + } + if (attr & FILE_ATTRIBUTE_TEMPORARY) { + ret |= FILE_ATTR_TEMPORARY; + } + if (attr & FILE_ATTRIBUTE_SPARSE_FILE) { + ret |= FILE_ATTR_SPARSE_FILE; + } + if (attr & FILE_ATTRIBUTE_OFFLINE) { + ret |= FILE_ATTR_OFFLINE; + } + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + ret |= FILE_ATTR_REPARSE_POINT; + } + +#endif + +#ifdef __APPLE__ + + /* TODO: + * If Hidden (Invisible) set FILE_ATTR_HIDDEN + * If Locked set FILE_ATTR_READONLY + * If Restricted set FILE_ATTR_RESTRICTED + */ + +#endif + +#ifdef __linux__ + + /* TODO: + * If Immutable set FILE_ATTR_READONLY + * If Archived set FILE_ATTR_ARCHIVE + */ + +#endif + + return ret; +} + /** * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails * (most likely doesn't exist or no access). diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2a0c4b5cc51..7267b8adb00 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9770,6 +9770,15 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) /* Skip in undo case. */ if (fd->memfile == NULL) { + /* Note that we cannot recompute usercounts at this point in undo case, we play too much with + * IDs from different memory realms, and Main database is not in a fully valid state yet. + */ + /* Some versioning code does expect some proper userrefcounting, e.g. in conversion from + * groups to collections... We could optimize out that first call when we are reading a + * current version file, but again this is really not a bottle neck currently. so not worth + * it. */ + BKE_main_id_refcount_recompute(bfd->main, false); + /* Yep, second splitting... but this is a very cheap operation, so no big deal. */ blo_split_main(&mainlist, bfd->main); for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) { @@ -9778,11 +9787,9 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) } blo_join_main(&mainlist); - /* Note that we cannot recompute usercounts at this point in undo case, we play too much with - * IDs from different memory realms, and Main database is not in a fully valid state yet. - */ - /* Also, this does not take into account old, deprecated data, so we have to do it after - * `do_versions_after_linking()`. */ + /* And we have to compute those userrefcounts again, as `do_versions_after_linking()` does + * not always properly handle user counts, and/or that function does not take into account + * old, deprecated data. */ BKE_main_id_refcount_recompute(bfd->main, false); /* After all data has been read and versioned, uses LIB_TAG_NEW. */ @@ -11478,6 +11485,13 @@ static void library_link_end(Main *mainl, mainl = NULL; /* blo_join_main free's mainl, cant use anymore */ lib_link_all(*fd, mainvar); + + /* Some versioning code does expect some proper userrefcounting, e.g. in conversion from + * groups to collections... We could optimize out that first call when we are reading a + * current version file, but again this is really not a bottle neck currently. so not worth + * it. */ + BKE_main_id_refcount_recompute(mainvar, false); + BKE_collections_after_lib_link(mainvar); /* Yep, second splitting... but this is a very cheap operation, so no big deal. */ @@ -11499,7 +11513,7 @@ static void library_link_end(Main *mainl, mainvar = (*fd)->mainlist->first; MEM_freeN((*fd)->mainlist); - /* This does not take into account old, deprecated data, so we have to do it after + /* This does not take into account old, deprecated data, so we also have to do it after * `do_versions_after_linking()`. */ BKE_main_id_refcount_recompute(mainvar, false); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 44eaf5bef90..836d8f85c93 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -28,6 +28,8 @@ #include <stdio.h> #include <stdlib.h> #include <cstring> /* required for STREQ later on. */ +#include <deque> +#include <unordered_set> #include "MEM_guardedalloc.h" @@ -119,6 +121,9 @@ extern "C" { namespace DEG { +using std::deque; +using std::unordered_set; + /* ***************** */ /* Relations Builder */ @@ -1330,48 +1335,6 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) /* create the driver's relations to targets */ build_driver(id, fcu); - /* Special case for array drivers: we can not multithread them because - * of the way how they work internally: animation system will write the - * whole array back to RNA even when changing individual array value. - * - * Some tricky things here: - * - array_index is -1 for single channel drivers, meaning we only have - * to do some magic when array_index is not -1. - * - We do relation from next array index to a previous one, so we don't - * have to deal with array index 0. - * - * TODO(sergey): Avoid liner lookup somehow. */ - if (fcu->array_index > 0) { - FCurve *fcu_prev = nullptr; - LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { - /* Writing to different RNA paths is */ - const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - if (!STREQ(fcu_candidate->rna_path, rna_path)) { - continue; - } - /* We only do relation from previous fcurve to previous one. */ - if (fcu_candidate->array_index >= fcu->array_index) { - continue; - } - /* Choose fcurve with highest possible array index. */ - if (fcu_prev == nullptr || fcu_candidate->array_index > fcu_prev->array_index) { - fcu_prev = fcu_candidate; - } - } - if (fcu_prev != nullptr) { - OperationKey prev_driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu_prev->rna_path ? fcu_prev->rna_path : "", - fcu_prev->array_index); - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - add_relation(prev_driver_key, driver_key, "Driver Order"); - } - } /* prevent driver from occurring before own animation... */ if (adt->action || adt->nla_tracks.first) { @@ -1488,7 +1451,11 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) } else { /* If it's not a Bone, handle the generic single dependency case. */ - add_relation(driver_key, property_entry_key, "Driver -> Driven Property"); + Node *node_to = get_node(property_entry_key); + if (node_to != nullptr) { + add_relation(driver_key, property_entry_key, "Driver -> Driven Property"); + } + /* Similar to the case with f-curves, driver might drive a nested * data-block, which means driver execution should wait for that * data-block to be copied. */ @@ -2707,6 +2674,116 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) #endif } +static bool is_reachable(const Node *const from, const Node *const to) +{ + if (from == to) { + return true; + } + + // Perform a graph walk from 'to' towards its incoming connections. + // Walking from 'from' towards its outgoing connections is 10x slower on the Spring rig. + deque<const Node *> queue; + unordered_set<const Node *> seen; + queue.push_back(to); + while (!queue.empty()) { + // Visit the next node to inspect. + const Node *visit = queue.back(); + queue.pop_back(); + + if (visit == from) { + return true; + } + + // Queue all incoming relations that we haven't seen before. + for (Relation *relation : visit->inlinks) { + const Node *prev_node = relation->from; + if (seen.insert(prev_node).second) { + queue.push_back(prev_node); + } + } + } + return false; +} + +void DepsgraphRelationBuilder::build_driver_relations() +{ + for (IDNode *id_node : graph_->id_nodes) { + build_driver_relations(id_node); + } +} + +void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node) +{ + /* Add relations between drivers that write to the same datablock. + * + * This prevents threading issues when two separate RNA properties write to + * the same memory address. For example: + * - Drivers on individual array elements, as the animation system will write + * the whole array back to RNA even when changing individual array value. + * - Drivers on RNA properties that map to a single bit flag. Changing the RNA + * value will write the entire int containing the bit, in a non-thread-safe + * way. + */ + ID *id_orig = id_node->id_orig; + AnimData *adt = BKE_animdata_from_id(id_orig); + if (adt == nullptr) { + return; + } + + // Mapping from RNA prefix -> set of driver evaluation nodes: + typedef vector<Node *> DriverGroup; + typedef map<string, DriverGroup> DriverGroupMap; + DriverGroupMap driver_groups; + + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + // Get the RNA path except the part after the last dot. + char *last_dot = strrchr(fcu->rna_path, '.'); + string rna_prefix; + if (last_dot != nullptr) { + rna_prefix = string(fcu->rna_path, last_dot); + } + + // Insert this driver node into the group belonging to the RNA prefix. + OperationKey driver_key( + id_orig, NodeType::PARAMETERS, OperationCode::DRIVER, fcu->rna_path, fcu->array_index); + Node *node_driver = get_node(driver_key); + driver_groups[rna_prefix].push_back(node_driver); + } + + for (pair<string, DriverGroup> prefix_group : driver_groups) { + // For each node in the driver group, try to connect it to another node + // in the same group without creating any cycles. + int num_drivers = prefix_group.second.size(); + for (int from_index = 0; from_index < num_drivers; ++from_index) { + Node *op_from = prefix_group.second[from_index]; + + // Start by trying the next node in the group. + for (int to_offset = 1; to_offset < num_drivers - 1; ++to_offset) { + int to_index = (from_index + to_offset) % num_drivers; + Node *op_to = prefix_group.second[to_index]; + + // Investigate whether this relation would create a dependency cycle. + // Example graph: + // A -> B -> C + // and investigating a potential connection C->A. Because A->C is an + // existing transitive connection, adding C->A would create a cycle. + if (is_reachable(op_to, op_from)) { + continue; + } + + // No need to directly connect this node if there is already a transitive connection. + if (is_reachable(op_from, op_to)) { + break; + } + + add_operation_relation( + op_from->get_exit_operation(), op_to->get_entry_operation(), "Driver Serialisation"); + break; + } + } + } +} + /* **** ID traversal callbacks functions **** */ void DepsgraphRelationBuilder::modifier_walk(void *user_data, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 11eb31c68f6..7da3577a7b5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -302,6 +302,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { virtual void build_copy_on_write_relations(); virtual void build_copy_on_write_relations(IDNode *id_node); + virtual void build_driver_relations(); + virtual void build_driver_relations(IDNode *id_node); template<typename KeyType> OperationNode *find_operation_node(const KeyType &key); diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index a570e042c26..3fe585ff73c 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -251,6 +251,7 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph, relation_builder.begin_build(); relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); relation_builder.build_copy_on_write_relations(); + relation_builder.build_driver_relations(); /* Finalize building. */ graph_build_finalize_common(deg_graph, bmain); /* Finish statistics. */ @@ -284,6 +285,7 @@ void DEG_graph_build_for_render_pipeline(Depsgraph *graph, relation_builder.begin_build(); relation_builder.build_scene_render(scene, view_layer); relation_builder.build_copy_on_write_relations(); + relation_builder.build_driver_relations(); /* Finalize building. */ graph_build_finalize_common(deg_graph, bmain); /* Finish statistics. */ @@ -317,6 +319,7 @@ void DEG_graph_build_for_compositor_preview( relation_builder.build_scene_render(scene, view_layer); relation_builder.build_nodetree(nodetree); relation_builder.build_copy_on_write_relations(); + relation_builder.build_driver_relations(); /* Finalize building. */ graph_build_finalize_common(deg_graph, bmain); /* Finish statistics. */ @@ -458,6 +461,7 @@ void DEG_graph_build_from_ids(Depsgraph *graph, relation_builder.build_id(ids[i]); } relation_builder.build_copy_on_write_relations(); + relation_builder.build_driver_relations(); /* Finalize building. */ graph_build_finalize_common(deg_graph, bmain); /* Finish statistics. */ diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 37fe04e9d8a..07a8bba5023 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -219,6 +219,8 @@ data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SR data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC) +data_to_c_simple(engines/eevee/shaders/shadow_accum_frag.glsl SRC) + data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC) @@ -232,6 +234,7 @@ data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_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/update_noise_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/volumetric_accum_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_geom.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c index c6cc336db56..53465455d57 100644 --- a/source/blender/draw/engines/eevee/eevee_bloom.c +++ b/source/blender/draw/engines/eevee/eevee_bloom.c @@ -40,6 +40,8 @@ static struct { extern char datatoc_effect_bloom_frag_glsl[]; +const bool use_highres = true; + static void eevee_create_shader_bloom(void) { e_data.bloom_blit_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, @@ -179,7 +181,8 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, - bool upsample) + bool upsample, + bool resolve) { struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); @@ -193,6 +196,10 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name, DRW_shgroup_uniform_texture_ref(grp, "baseBuffer", &effects->unf_base_buffer); DRW_shgroup_uniform_float(grp, "sampleScale", &effects->bloom_sample_scale, 1); } + if (resolve) { + DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 1); + DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", true); + } return grp; } @@ -203,6 +210,8 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; + psl->bloom_accum_ps = NULL; + if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { /** Bloom algorithm * @@ -234,29 +243,41 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved * </pre> */ DRWShadingGroup *grp; - const bool use_highres = true; const bool use_antiflicker = true; eevee_create_bloom_pass("Bloom Downsample First", effects, e_data.bloom_downsample_sh[use_antiflicker], &psl->bloom_downsample_first, + false, + false); + eevee_create_bloom_pass("Bloom Downsample", + effects, + e_data.bloom_downsample_sh[0], + &psl->bloom_downsample, + false, false); - eevee_create_bloom_pass( - "Bloom Downsample", effects, e_data.bloom_downsample_sh[0], &psl->bloom_downsample, false); eevee_create_bloom_pass("Bloom Upsample", effects, e_data.bloom_upsample_sh[use_highres], &psl->bloom_upsample, - true); + true, + false); - grp = eevee_create_bloom_pass( - "Bloom Blit", effects, e_data.bloom_blit_sh[use_antiflicker], &psl->bloom_blit, false); + grp = eevee_create_bloom_pass("Bloom Blit", + effects, + e_data.bloom_blit_sh[use_antiflicker], + &psl->bloom_blit, + false, + false); DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1); DRW_shgroup_uniform_float(grp, "clampIntensity", &effects->bloom_clamp, 1); - grp = eevee_create_bloom_pass( - "Bloom Resolve", effects, e_data.bloom_resolve_sh[use_highres], &psl->bloom_resolve, true); - DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 1); + grp = eevee_create_bloom_pass("Bloom Resolve", + effects, + e_data.bloom_resolve_sh[use_highres], + &psl->bloom_resolve, + true, + true); } } @@ -322,6 +343,47 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata) } } +void EEVEE_bloom_output_init(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + uint UNUSED(tot_samples)) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + /* Create FrameBuffer. */ + DRW_texture_ensure_fullscreen_2d(&txl->bloom_accum, GPU_R11F_G11F_B10F, 0); + + GPU_framebuffer_ensure_config(&fbl->bloom_pass_accum_fb, + {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->bloom_accum)}); + + /* Create Pass and shgroup. */ + DRWShadingGroup *grp = eevee_create_bloom_pass("Bloom Accumulate", + effects, + e_data.bloom_resolve_sh[use_highres], + &psl->bloom_accum_ps, + true, + true); + DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", false); +} + +void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + + if (stl->g_data->render_passes & EEVEE_RENDER_PASS_BLOOM) { + GPU_framebuffer_bind(fbl->bloom_pass_accum_fb); + DRW_draw_pass(psl->bloom_accum_ps); + + /* Restore */ + GPU_framebuffer_bind(fbl->main_fb); + } +} + void EEVEE_bloom_free(void) { for (int i = 0; i < 2; i++) { diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index dd70ee1bd4b..e586fc7b1db 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -54,6 +54,9 @@ void EEVEE_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->grid_ubo); DRW_UBO_FREE_SAFE(sldata->planar_ubo); DRW_UBO_FREE_SAFE(sldata->common_ubo); + for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) { + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo[i]); + } } EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index a20921b639f..90bfad45f60 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -170,7 +170,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_subsurface_init(sldata, vedata); /* Force normal buffer creation. */ - if (!minimal && (stl->g_data->render_passes & SCE_PASS_NORMAL) != 0) { + if (!minimal && (stl->g_data->render_passes & EEVEE_RENDER_PASS_NORMAL) != 0) { effects->enabled_effects |= EFFECT_NORMAL_BUFFER; } @@ -333,6 +333,8 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv); DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat); DRW_shgroup_call(grp, quad, NULL); @@ -513,7 +515,7 @@ static void EEVEE_velocity_resolve(EEVEE_Data *vedata) DRW_view_persmat_get(view, effects->velocity_past_persmat, false); } -void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; @@ -541,6 +543,10 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) EEVEE_temporal_sampling_draw(vedata); EEVEE_bloom_draw(vedata); + /* Post effect render passes are done here just after the drawing of the effects and just before + * the swapping of the buffers. */ + EEVEE_renderpasses_output_accumulate(sldata, vedata, true); + /* Save the final texture and framebuffer for final transformation or read. */ effects->final_tx = effects->source_buffer; effects->final_fb = (effects->target_buffer != fbl->main_color_fb) ? fbl->main_fb : diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index e3b50bb2142..f8e68156aa8 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -151,7 +151,8 @@ void EEVEE_cache_populate(void *vedata, Object *ob) static void eevee_cache_finish(void *vedata) { EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_PrivateData *g_data = ((EEVEE_Data *)vedata)->stl->g_data; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_PrivateData *g_data = stl->g_data; const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); @@ -176,6 +177,9 @@ static void eevee_cache_finish(void *vedata) if (g_data->queued_shaders_count != g_data->queued_shaders_count_prev) { g_data->queued_shaders_count_prev = g_data->queued_shaders_count; EEVEE_temporal_sampling_reset(vedata); + /* At this moment the TAA sampling will be redrawn in the next iteration. + * we set the taa_current_sample to 0 so the next iteration will use sample 1 */ + stl->effects->taa_current_sample = 0; } } @@ -307,6 +311,9 @@ static void eevee_draw_scene(void *vedata) /* Volumetrics Resolve Opaque */ EEVEE_volumes_resolve(sldata, vedata); + /* Renderpasses */ + EEVEE_renderpasses_output_accumulate(sldata, vedata, false); + /* Transparent */ /* TODO(fclem): should be its own Framebuffer. * This is needed because dualsource blending only works with 1 color buffer. */ @@ -321,8 +328,6 @@ static void eevee_draw_scene(void *vedata) EEVEE_draw_effects(sldata, vedata); DRW_stats_group_end(); - EEVEE_renderpasses_output_accumulate(sldata, vedata); - DRW_view_set_active(NULL); if (DRW_state_is_image_render() && (stl->effects->enabled_effects & EFFECT_SSR) && @@ -336,7 +341,7 @@ static void eevee_draw_scene(void *vedata) } } - if ((stl->g_data->render_passes & SCE_PASS_COMBINED) > 0) { + if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_COMBINED) != 0) { /* Transfer result to default framebuffer. */ GPU_framebuffer_bind(dfbl->default_fb); DRW_transform_none(stl->effects->final_tx); @@ -416,9 +421,8 @@ static void eevee_render_to_image(void *vedata, const rcti *rect) { const DRWContextState *draw_ctx = DRW_context_state_get(); - EEVEE_render_init(vedata, engine, draw_ctx->depsgraph); - if (RE_engine_test_break(engine)) { + if (!EEVEE_render_init(vedata, engine, draw_ctx->depsgraph)) { return; } diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 7da9af55330..92e36597d99 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -251,6 +251,8 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call(grp, geom, NULL); @@ -272,6 +274,8 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call(grp, geom, NULL); @@ -292,6 +296,8 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call(grp, geom, NULL); @@ -360,6 +366,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call(grp, geom, NULL); break; case GPU_MAT_QUEUED: @@ -403,6 +411,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat /* TODO (fclem) get rid of those UBO. */ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call_procedural_triangles(grp, NULL, cube_len * 2); } @@ -429,6 +439,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2; DRW_shgroup_call_procedural_triangles(shgrp, NULL, tri_count); } @@ -446,6 +458,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_planar_display_sh_get(), psl->probe_display); DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); stl->g_data->planar_display_shgrp = DRW_shgroup_call_buffer_instance( grp, e_data.format_probe_display_planar, DRW_cache_quad_get()); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 1c0a1289ba4..3c793ca0693 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -25,6 +25,7 @@ #include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_alloca.h" +#include "BLI_math_bits.h" #include "BLI_rand.h" #include "BLI_string_utils.h" @@ -101,9 +102,37 @@ extern char datatoc_volumetric_vert_glsl[]; extern char datatoc_volumetric_geom_glsl[]; extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; - extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; +#define DEFAULT_RENDER_PASS_FLAG 0xefffffff + +/* Iterator for render passes. This iteration will only do the material based render passes. it + * will ignore `EEVEE_RENDER_PASS_ENVIRONMENT`. + * + * parameters: + * - `render_passes_` is a bitflag for render_passes that needs to be iterated over. + * - `render_pass_index_` is a parameter name where the index of the render_pass will be available + * during iteration. This index can be used to select the right pass in the `psl`. + * - `render_pass_` is the bitflag of the render_pass of the current iteration. + * + * The `render_pass_index_` parameter needs to be the same for the `RENDER_PASS_ITER_BEGIN` and + * `RENDER_PASS_ITER_END`. + */ +#define RENDER_PASS_ITER_BEGIN(render_passes_, render_pass_index_, render_pass_) \ + const eViewLayerEEVEEPassType __filtered_##render_pass_index_ = render_passes_ & \ + EEVEE_RENDERPASSES_MATERIAL & \ + ~EEVEE_RENDER_PASS_ENVIRONMENT; \ + if (__filtered_##render_pass_index_ != 0) { \ + int render_pass_index_ = 1; \ + for (int bit_##render_pass_ = 0; bit_##render_pass_ < 32; bit_##render_pass_++) { \ + eViewLayerEEVEEPassType render_pass_ = (1 << bit_##render_pass_); \ + if ((__filtered_##render_pass_index_ & render_pass_) != 0) { +#define RENDER_PASS_ITER_END(render_pass_index_) \ + render_pass_index_ += 1; \ + } \ + } \ + } + /* *********** FUNCTIONS *********** */ #if 0 /* Used only to generate the LUT values */ @@ -337,6 +366,39 @@ static char *eevee_get_volume_defines(int options) return str; } +/* Get the default render pass ubo. This is a ubo that enables all bsdf render passes. */ +struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata) +{ + return sldata->renderpass_ubo[0]; +} + +/* Get the render pass ubo for rendering the given render_pass. */ +static struct GPUUniformBuffer *get_render_pass_ubo(EEVEE_ViewLayerData *sldata, + eViewLayerEEVEEPassType render_pass) +{ + int index; + switch (render_pass) { + case EEVEE_RENDER_PASS_DIFFUSE_COLOR: + index = 1; + break; + case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: + index = 2; + break; + case EEVEE_RENDER_PASS_SPECULAR_COLOR: + index = 3; + break; + case EEVEE_RENDER_PASS_SPECULAR_LIGHT: + index = 4; + break; + case EEVEE_RENDER_PASS_EMIT: + index = 5; + break; + default: + index = 0; + break; + } + return sldata->renderpass_ubo[index]; +} /** * ssr_id can be null to disable ssr contribution. */ @@ -349,7 +411,8 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, bool use_glossy, bool use_refract, bool use_ssrefraction, - bool use_alpha_blend) + bool use_alpha_blend, + eViewLayerEEVEEPassType render_pass) { LightCache *lcache = vedata->stl->g_data->light_cache; EEVEE_EffectsInfo *effects = vedata->stl->effects; @@ -360,9 +423,9 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(shgrp, "renderpass_block", get_render_pass_ubo(sldata, render_pass)); DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1); - if (use_diffuse || use_glossy || use_refract) { DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool); @@ -395,6 +458,24 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, } } +/* Add the uniforms for the background shader to `shgrp`. */ +static void add_background_uniforms(DRWShadingGroup *shgrp, + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + DRW_shgroup_uniform_float(shgrp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + /* TODO (fclem): remove those (need to clean the GLSL files). */ + DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block( + shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); +} + static void create_default_shader(int options) { char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_default_frag_glsl); @@ -523,6 +604,9 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + EEVEE_PrivateData *g_data = stl->g_data; + if (!e_data.frag_shader_lib) { /* Shaders */ e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, @@ -600,7 +684,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, datatoc_prepass_frag_glsl, "#define HAIR_SHADER\n" "#define CLIP_PLANES\n"); - MEM_freeN(vert_str); e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); @@ -635,6 +718,66 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, &fbl->update_noise_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE_LAYER(e_data.util_tex, 2)}); } + + { + /* Create RenderPass UBO */ + if (sldata->renderpass_ubo[0] == NULL) { + sldata->renderpass_data[0].renderPassDiffuse = true; + sldata->renderpass_data[0].renderPassDiffuseLight = true; + sldata->renderpass_data[0].renderPassGlossy = true; + sldata->renderpass_data[0].renderPassGlossyLight = true; + sldata->renderpass_data[0].renderPassEmit = true; + sldata->renderpass_data[0].renderPassSSSColor = false; + sldata->renderpass_data[1].renderPassDiffuse = true; + sldata->renderpass_data[1].renderPassDiffuseLight = false; + sldata->renderpass_data[1].renderPassGlossy = false; + sldata->renderpass_data[1].renderPassGlossyLight = false; + sldata->renderpass_data[1].renderPassEmit = false; + sldata->renderpass_data[1].renderPassSSSColor = true; + sldata->renderpass_data[2].renderPassDiffuse = true; + sldata->renderpass_data[2].renderPassDiffuseLight = true; + sldata->renderpass_data[2].renderPassGlossy = false; + sldata->renderpass_data[2].renderPassGlossyLight = false; + sldata->renderpass_data[2].renderPassEmit = false; + sldata->renderpass_data[2].renderPassSSSColor = false; + sldata->renderpass_data[3].renderPassDiffuse = false; + sldata->renderpass_data[3].renderPassDiffuseLight = false; + sldata->renderpass_data[3].renderPassGlossy = true; + sldata->renderpass_data[3].renderPassGlossyLight = false; + sldata->renderpass_data[3].renderPassEmit = false; + sldata->renderpass_data[3].renderPassSSSColor = false; + sldata->renderpass_data[4].renderPassDiffuse = false; + sldata->renderpass_data[4].renderPassDiffuseLight = false; + sldata->renderpass_data[4].renderPassGlossy = true; + sldata->renderpass_data[4].renderPassGlossyLight = true; + sldata->renderpass_data[4].renderPassEmit = false; + sldata->renderpass_data[4].renderPassSSSColor = false; + sldata->renderpass_data[5].renderPassDiffuse = false; + sldata->renderpass_data[5].renderPassDiffuseLight = false; + sldata->renderpass_data[5].renderPassGlossy = false; + sldata->renderpass_data[5].renderPassGlossyLight = false; + sldata->renderpass_data[5].renderPassEmit = true; + sldata->renderpass_data[5].renderPassSSSColor = false; + + for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) { + sldata->renderpass_ubo[i] = DRW_uniformbuffer_create(sizeof(EEVEE_RenderPassData), + &sldata->renderpass_data[i]); + } + } + + /* HACK: EEVEE_material_world_background_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 + * `EEVEE_renderpasses_init` as the `e_data.vertcode` can be uninitialized. + */ + if (g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + struct Scene *scene = draw_ctx->scene; + struct World *wo = scene->world; + if (wo && wo->use_nodes) { + EEVEE_material_world_background_get(scene, wo); + } + } + } } struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, World *wo) @@ -852,7 +995,17 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye } DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, use_blend); + add_standard_uniforms(shgrp, + sldata, + vedata, + &ssr_id, + NULL, + true, + true, + false, + false, + use_blend, + DEFAULT_RENDER_PASS_FLAG); return shgrp; } @@ -894,14 +1047,34 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa if (!is_hair) { DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->default_pass[options]); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false); + add_standard_uniforms(shgrp, + sldata, + vedata, + &ssr_id, + NULL, + true, + true, + false, + false, + false, + DEFAULT_RENDER_PASS_FLAG); } } if (is_hair) { DRWShadingGroup *shgrp = DRW_shgroup_hair_create( ob, psys, md, vedata->psl->default_pass[options], e_data.default_lit[options]); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false); + add_standard_uniforms(shgrp, + sldata, + vedata, + &ssr_id, + NULL, + true, + true, + false, + false, + false, + DEFAULT_RENDER_PASS_FLAG); return shgrp; } else { @@ -909,6 +1082,60 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa } } +static struct DRWShadingGroup *EEVEE_default_render_pass_shading_group_get( + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + bool holdout, + bool use_ssr, + DRWPass *pass, + eViewLayerEEVEEPassType render_pass_flag) +{ + static int ssr_id; + ssr_id = (use_ssr) ? 1 : -1; + int options = VAR_MAT_MESH; + + SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); + + if (e_data.default_lit[options] == NULL) { + create_default_shader(options); + } + + DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); + add_standard_uniforms( + shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); + return shgrp; +} + +static struct DRWShadingGroup *EEVEE_default_hair_render_pass_shading_group_get( + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + Object *ob, + ParticleSystem *psys, + ModifierData *md, + bool holdout, + bool use_ssr, + DRWPass *pass, + eViewLayerEEVEEPassType render_pass_flag) +{ + static int ssr_id; + ssr_id = (use_ssr) ? 1 : -1; + int options = VAR_MAT_MESH | VAR_MAT_HAIR; + + BLI_assert((ob && psys && md)); + + SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); + + if (e_data.default_lit[options] == NULL) { + create_default_shader(options); + } + + DRWShadingGroup *shgrp = DRW_shgroup_hair_create( + ob, psys, md, pass, e_data.default_lit[options]); + add_standard_uniforms( + shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); + return shgrp; +} + void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -945,14 +1172,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) switch (GPU_material_status(gpumat)) { case GPU_MAT_SUCCESS: grp = DRW_shgroup_material_create(gpumat, psl->background_pass); - DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - /* TODO (fclem): remove those (need to clean the GLSL files). */ - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + add_background_uniforms(grp, sldata, vedata); DRW_shgroup_call(grp, geom, NULL); break; case GPU_MAT_QUEUED: @@ -1071,7 +1291,17 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state); shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_diffuse_pass); - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, true, true, false, false, false); + add_standard_uniforms(shgrp, + sldata, + vedata, + NULL, + NULL, + true, + true, + false, + false, + false, + DEFAULT_RENDER_PASS_FLAG); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_diffuse, 1); DRW_shgroup_uniform_float_copy(shgrp, "metallic", 0.0f); DRW_shgroup_uniform_float_copy(shgrp, "specular", 0.5f); @@ -1080,12 +1310,31 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_PASS_CREATE(psl->lookdev_glossy_pass, state); shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_glossy_pass); - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, true, true, false, false, false); + add_standard_uniforms(shgrp, + sldata, + vedata, + NULL, + NULL, + true, + true, + false, + false, + false, + DEFAULT_RENDER_PASS_FLAG); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_chrome, 1); DRW_shgroup_uniform_float_copy(shgrp, "metallic", 1.0f); DRW_shgroup_uniform_float_copy(shgrp, "roughness", 0.0f); DRW_shgroup_call(shgrp, sphere, NULL); } + + { + memset(psl->material_accum_pass, 0, sizeof(psl->material_accum_pass)); + for (int pass_index = 0; pass_index < stl->g_data->render_passes_material_count; + pass_index++) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD; + DRW_PASS_CREATE(psl->material_accum_pass[pass_index], state); + } + } } #define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ @@ -1109,6 +1358,7 @@ typedef struct EeveeMaterialShadingGroups { struct DRWShadingGroup *shading_grp; struct DRWShadingGroup *depth_grp; struct DRWShadingGroup *depth_clip_grp; + struct DRWShadingGroup *material_accum_grp[MAX_MATERIAL_RENDER_PASSES]; } EeveeMaterialShadingGroups; static void material_opaque(Material *ma, @@ -1117,9 +1367,7 @@ static void material_opaque(Material *ma, EEVEE_Data *vedata, struct GPUMaterial **gpumat, struct GPUMaterial **gpumat_depth, - struct DRWShadingGroup **shgrp, - struct DRWShadingGroup **shgrp_depth, - struct DRWShadingGroup **shgrp_depth_clip, + struct EeveeMaterialShadingGroups *shgrps, bool holdout) { EEVEE_EffectsInfo *effects = vedata->stl->effects; @@ -1128,7 +1376,7 @@ static void material_opaque(Material *ma, EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; bool use_diffuse, use_glossy, use_refract; - + bool store_material = true; float *color_p = &ma->r; float *metal_p = &ma->metallic; float *spec_p = &ma->spec; @@ -1143,9 +1391,7 @@ static void material_opaque(Material *ma, EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); if (emsg) { - *shgrp = emsg->shading_grp; - *shgrp_depth = emsg->depth_grp; - *shgrp_depth_clip = emsg->depth_clip_grp; + memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); /* This will have been created already, just perform a lookup. */ *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) : @@ -1156,6 +1402,7 @@ static void material_opaque(Material *ma, return; } + emsg = MEM_callocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups"); if (use_gpumat) { static float error_col[3] = {1.0f, 0.0f, 1.0f}; static float compile_col[3] = {0.5f, 0.5f, 0.5f}; @@ -1179,25 +1426,25 @@ static void material_opaque(Material *ma, status_mat_surface = status_mat_depth; } else if (use_ssrefract) { - *shgrp_depth = DRW_shgroup_material_create( + emsg->depth_grp = DRW_shgroup_material_create( *gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass); - *shgrp_depth_clip = DRW_shgroup_material_create( + emsg->depth_clip_grp = DRW_shgroup_material_create( *gpumat_depth, (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip); } else { - *shgrp_depth = DRW_shgroup_material_create( + emsg->depth_grp = DRW_shgroup_material_create( *gpumat_depth, (do_cull) ? psl->depth_pass_cull : psl->depth_pass); - *shgrp_depth_clip = DRW_shgroup_material_create( + emsg->depth_clip_grp = DRW_shgroup_material_create( *gpumat_depth, (do_cull) ? psl->depth_pass_clip_cull : psl->depth_pass_clip); } - if (*shgrp_depth != NULL) { + if (emsg->depth_grp != NULL) { use_diffuse = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_DIFFUSE); use_glossy = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_GLOSSY); use_refract = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_REFRACT); - add_standard_uniforms(*shgrp_depth, + add_standard_uniforms(emsg->depth_grp, sldata, vedata, NULL, @@ -1206,8 +1453,9 @@ static void material_opaque(Material *ma, use_glossy, use_refract, false, - false); - add_standard_uniforms(*shgrp_depth_clip, + false, + DEFAULT_RENDER_PASS_FLAG); + add_standard_uniforms(emsg->depth_clip_grp, sldata, vedata, NULL, @@ -1216,11 +1464,13 @@ static void material_opaque(Material *ma, use_glossy, use_refract, false, - false); + false, + DEFAULT_RENDER_PASS_FLAG); if (ma->blend_method == MA_BM_CLIP) { - DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1); - DRW_shgroup_uniform_float(*shgrp_depth_clip, "alphaThreshold", &ma->alpha_threshold, 1); + DRW_shgroup_uniform_float(emsg->depth_grp, "alphaThreshold", &ma->alpha_threshold, 1); + DRW_shgroup_uniform_float( + emsg->depth_clip_grp, "alphaThreshold", &ma->alpha_threshold, 1); } } } @@ -1237,14 +1487,14 @@ static void material_opaque(Material *ma, use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - *shgrp = DRW_shgroup_material_create( + emsg->shading_grp = DRW_shgroup_material_create( *gpumat, (use_ssrefract) ? psl->refract_pass : (use_sss) ? ((do_cull) ? psl->sss_pass_cull : psl->sss_pass) : ((do_cull) ? psl->material_pass_cull : psl->material_pass)); - add_standard_uniforms(*shgrp, + add_standard_uniforms(emsg->shading_grp, sldata, vedata, ssr_id, @@ -1253,7 +1503,8 @@ static void material_opaque(Material *ma, use_glossy, use_refract, use_ssrefract, - false); + false, + DEFAULT_RENDER_PASS_FLAG); if (use_sss) { struct GPUTexture *sss_tex_profile = NULL; @@ -1264,7 +1515,7 @@ static void material_opaque(Material *ma, /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ if (e_data.sss_count < 254) { int sss_id = e_data.sss_count + 1; - DRW_shgroup_stencil_mask(*shgrp, sss_id); + DRW_shgroup_stencil_mask(emsg->shading_grp, sss_id); EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile); if (use_translucency) { EEVEE_subsurface_translucency_add_pass( @@ -1278,12 +1529,30 @@ static void material_opaque(Material *ma, } } } + + RENDER_PASS_ITER_BEGIN(stl->g_data->render_passes, render_pass_index, render_pass_flag) + emsg->material_accum_grp[render_pass_index] = DRW_shgroup_material_create( + *gpumat, psl->material_accum_pass[render_pass_index]); + add_standard_uniforms(emsg->material_accum_grp[render_pass_index], + sldata, + vedata, + ssr_id, + &ma->refract_depth, + use_diffuse, + use_glossy, + use_refract, + use_ssrefract, + false, + render_pass_flag); + RENDER_PASS_ITER_END(render_pass_index) + break; } case GPU_MAT_QUEUED: { stl->g_data->queued_shaders_count++; color_p = compile_col; metal_p = spec_p = rough_p = ½ + store_material = false; break; } case GPU_MAT_FAILED: @@ -1295,44 +1564,61 @@ static void material_opaque(Material *ma, } /* Fallback to default shader */ - if (*shgrp == NULL) { + if (emsg->shading_grp == NULL) { bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); - *shgrp = EEVEE_default_shading_group_get( + emsg->shading_grp = EEVEE_default_shading_group_get( sldata, vedata, NULL, NULL, NULL, false, holdout, use_ssr); - DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1); + DRW_shgroup_uniform_vec3(emsg->shading_grp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(emsg->shading_grp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(emsg->shading_grp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(emsg->shading_grp, "roughness", rough_p, 1); + + RENDER_PASS_ITER_BEGIN(stl->g_data->render_passes, render_pass_index, render_pass_flag) + DRWShadingGroup *shgrp = EEVEE_default_render_pass_shading_group_get( + sldata, + vedata, + holdout, + use_ssr, + psl->material_accum_pass[render_pass_index], + render_pass_flag); + + DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); + emsg->material_accum_grp[render_pass_index] = shgrp; + RENDER_PASS_ITER_END(render_pass_index) } /* Fallback default depth prepass */ - if (*shgrp_depth == NULL) { + if (emsg->depth_grp == NULL) { if (use_ssrefract) { - *shgrp_depth = (do_cull) ? stl->g_data->refract_depth_shgrp_cull : - stl->g_data->refract_depth_shgrp; - *shgrp_depth_clip = (do_cull) ? stl->g_data->refract_depth_shgrp_clip_cull : - stl->g_data->refract_depth_shgrp_clip; + emsg->depth_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_cull : + stl->g_data->refract_depth_shgrp; + emsg->depth_clip_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_clip_cull : + stl->g_data->refract_depth_shgrp_clip; } else { - *shgrp_depth = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; - *shgrp_depth_clip = (do_cull) ? stl->g_data->depth_shgrp_clip_cull : - stl->g_data->depth_shgrp_clip; + emsg->depth_grp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; + emsg->depth_clip_grp = (do_cull) ? stl->g_data->depth_shgrp_clip_cull : + stl->g_data->depth_shgrp_clip; } } - emsg = MEM_mallocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups"); - emsg->shading_grp = *shgrp; - emsg->depth_grp = *shgrp_depth; - emsg->depth_clip_grp = *shgrp_depth_clip; - BLI_ghash_insert(material_hash, ma, emsg); + memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); + if (store_material) { + BLI_ghash_insert(material_hash, ma, emsg); + } + else { + MEM_freeN(emsg); + } } static void material_transparent(Material *ma, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUMaterial **gpumat, - struct DRWShadingGroup **shgrp, - struct DRWShadingGroup **shgrp_depth) + struct EeveeMaterialShadingGroups *shgrps) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; @@ -1357,13 +1643,13 @@ static void material_transparent(Material *ma, /* Depth prepass */ if (use_prepass) { - *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); + shgrps->depth_grp = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; - DRW_shgroup_state_disable(*shgrp_depth, all_state); - DRW_shgroup_state_enable(*shgrp_depth, cur_state); + DRW_shgroup_state_disable(shgrps->depth_grp, all_state); + DRW_shgroup_state_enable(shgrps->depth_grp, cur_state); } if (use_gpumat) { @@ -1378,14 +1664,14 @@ static void material_transparent(Material *ma, case GPU_MAT_SUCCESS: { static int ssr_id = -1; /* TODO transparent SSR */ - *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); + shgrps->shading_grp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); bool use_blend = true; bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE); bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - add_standard_uniforms(*shgrp, + add_standard_uniforms(shgrps->shading_grp, sldata, vedata, &ssr_id, @@ -1394,7 +1680,8 @@ static void material_transparent(Material *ma, use_glossy, use_refract, use_ssrefract, - use_blend); + use_blend, + DEFAULT_RENDER_PASS_FLAG); break; } case GPU_MAT_QUEUED: { @@ -1413,13 +1700,13 @@ static void material_transparent(Material *ma, } /* Fallback to default shader */ - if (*shgrp == NULL) { - *shgrp = EEVEE_default_shading_group_create( + if (shgrps->shading_grp == NULL) { + shgrps->shading_grp = EEVEE_default_shading_group_create( sldata, vedata, psl->transparent_pass, false, true, false); - DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1); + DRW_shgroup_uniform_vec3(shgrps->shading_grp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(shgrps->shading_grp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(shgrps->shading_grp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(shgrps->shading_grp, "roughness", rough_p, 1); } cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; @@ -1427,8 +1714,8 @@ static void material_transparent(Material *ma, cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; /* Disable other blend modes and use the one we want. */ - DRW_shgroup_state_disable(*shgrp, all_state); - DRW_shgroup_state_enable(*shgrp, cur_state); + DRW_shgroup_state_disable(shgrps->shading_grp, all_state); + DRW_shgroup_state_enable(shgrps->shading_grp, cur_state); } /* Return correct material or empty default material if slot is empty. */ @@ -1460,10 +1747,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { const int materials_len = DRW_cache_object_material_count_get(ob); - struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len); - struct DRWShadingGroup **shgrp_depth_array = BLI_array_alloca(shgrp_depth_array, - materials_len); - struct DRWShadingGroup **shgrp_depth_clip_array = BLI_array_alloca(shgrp_depth_clip_array, + struct EeveeMaterialShadingGroups *shgrps_array = BLI_array_alloca(shgrps_array, materials_len); struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); @@ -1472,11 +1756,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, for (int i = 0; i < materials_len; i++) { ma_array[i] = eevee_object_material_get(ob, i); + memset(&shgrps_array[i], 0, sizeof(EeveeMaterialShadingGroups)); gpumat_array[i] = NULL; gpumat_depth_array[i] = NULL; - shgrp_array[i] = NULL; - shgrp_depth_array[i] = NULL; - shgrp_depth_clip_array[i] = NULL; if (holdout) { material_opaque(ma_array[i], @@ -1485,9 +1767,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, vedata, &gpumat_array[i], &gpumat_depth_array[i], - &shgrp_array[i], - &shgrp_depth_array[i], - &shgrp_depth_clip_array[i], + &shgrps_array[i], true); continue; } @@ -1502,18 +1782,11 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, vedata, &gpumat_array[i], &gpumat_depth_array[i], - &shgrp_array[i], - &shgrp_depth_array[i], - &shgrp_depth_clip_array[i], + &shgrps_array[i], false); break; case MA_BM_BLEND: - material_transparent(ma_array[i], - sldata, - vedata, - &gpumat_array[i], - &shgrp_array[i], - &shgrp_depth_array[i]); + material_transparent(ma_array[i], sldata, vedata, &gpumat_array[i], &shgrps_array[i]); break; default: BLI_assert(0); @@ -1538,10 +1811,32 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, if (use_sculpt_pbvh) { /* Vcol is not supported in the modes that require PBVH drawing. */ - bool use_vcol = false; - DRW_shgroup_call_sculpt_with_materials(shgrp_array, ob, use_vcol); - DRW_shgroup_call_sculpt_with_materials(shgrp_depth_array, ob, use_vcol); - DRW_shgroup_call_sculpt_with_materials(shgrp_depth_clip_array, ob, use_vcol); + const bool use_vcol = false; + struct DRWShadingGroup **sculpt_shgrps_array = BLI_array_alloca(sculpt_shgrps_array, + materials_len); + for (int i = 0; i < materials_len; i++) { + sculpt_shgrps_array[i] = shgrps_array[i].shading_grp; + } + DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol); + + for (int i = 0; i < materials_len; i++) { + sculpt_shgrps_array[i] = shgrps_array[i].depth_grp; + } + DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol); + for (int i = 0; i < materials_len; i++) { + sculpt_shgrps_array[i] = shgrps_array[i].depth_clip_grp; + } + DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol); + + for (int renderpass_index = 0; + renderpass_index < stl->g_data->render_passes_material_count; + renderpass_index++) { + for (int i = 0; i < materials_len; i++) { + sculpt_shgrps_array[i] = shgrps_array[i].material_accum_grp[renderpass_index]; + } + DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol); + } + /* TODO(fclem): Support shadows in sculpt mode. */ } else if (mat_geom) { @@ -1565,10 +1860,16 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, oedata->ob = ob; oedata->test_data = &sldata->probes->vis_data; } - - ADD_SHGROUP_CALL(shgrp_array[i], ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata); + EeveeMaterialShadingGroups *shgrps = &shgrps_array[i]; + ADD_SHGROUP_CALL(shgrps->shading_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(shgrps->depth_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(shgrps->depth_clip_grp, ob, mat_geom[i], oedata); + for (int renderpass_index = 0; + renderpass_index < stl->g_data->render_passes_material_count; + renderpass_index++) { + ADD_SHGROUP_CALL_SAFE( + shgrps->material_accum_grp[renderpass_index], ob, mat_geom[i], oedata); + } /* Shadow Pass */ struct GPUMaterial *gpumat; @@ -1667,9 +1968,33 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->material_pass, gpumat); if (!use_diffuse && !use_glossy && !use_refract) { - /* FIXME: Small hack to avoid issue when utilTex is needed for + /* HACK: Small hack to avoid issue when utilTex is needed for + * world_normals_get and none of the bsdfs are present. + * This binds utilTex even if not needed. */ + DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); + } + + add_standard_uniforms(shgrp, + sldata, + vedata, + &ssr_id, + NULL, + use_diffuse, + use_glossy, + use_refract, + false, + false, + DEFAULT_RENDER_PASS_FLAG); + + /* Add the hair to all the render_passes that are enabled */ + RENDER_PASS_ITER_BEGIN( + stl->g_data->render_passes, render_pass_index, render_pass_flag) + shgrp = DRW_shgroup_material_hair_create( + ob, psys, md, psl->material_accum_pass[render_pass_index], gpumat); + if (!use_diffuse && !use_glossy && !use_refract) { + /* Small hack to avoid issue when utilTex is needed for * world_normals_get and none of the bsdfs that need it are present. - * This can try to bind utilTex even if not needed. */ + * This binds `utilTex` even if not needed. */ DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); } @@ -1682,7 +2007,10 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, use_glossy, use_refract, false, - false); + false, + render_pass_flag); + RENDER_PASS_ITER_END(render_pass_index) + break; } case GPU_MAT_QUEUED: { @@ -1707,6 +2035,24 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); + + RENDER_PASS_ITER_BEGIN(stl->g_data->render_passes, render_pass_index, render_pass_flag) + shgrp = EEVEE_default_hair_render_pass_shading_group_get( + sldata, + vedata, + ob, + psys, + md, + holdout, + use_ssr, + psl->material_accum_pass[render_pass_index], + render_pass_flag); + + DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); + RENDER_PASS_ITER_END(render_pass_index) } /* Shadows */ @@ -1762,3 +2108,180 @@ void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Pass DRW_draw_pass(psl->material_pass); DRW_draw_pass(psl->material_pass_cull); } + +/* -------------------------------------------------------------------- */ + +/** \name Render Passes + * \{ */ + +void EEVEE_material_renderpasses_init(EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + + /* For diffuse and glossy we calculate the final light + color buffer where we extract the + * light from by dividing by the color buffer. When one the light is requested we also tag + * the color buffer to do the extraction. */ + if (g_data->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + g_data->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR; + } + if (g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + g_data->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR; + } + + /* Calculate the number of material based render passes */ + uint num_render_passes = count_bits_i(stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL); + if ((num_render_passes != 0 && stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) == + 0) { + num_render_passes += 1; + } + stl->g_data->render_passes_material_count = num_render_passes; +} + +void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + EEVEE_FramebufferList *fbl = vedata->fbl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = stl->effects; + + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + /* Create FrameBuffer. */ + + /* Should be enough precision for many samples. */ + const eGPUTextureFormat texture_format_material_accum = (tot_samples > 128) ? GPU_RGBA32F : + GPU_RGBA16F; + const eViewLayerEEVEEPassType render_passes = stl->g_data->render_passes & + EEVEE_RENDERPASSES_MATERIAL; + if (render_passes != 0) { + GPU_framebuffer_ensure_config(&fbl->material_accum_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); + int render_pass_index = ((render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) != 0) ? 0 : 1; + for (int bit = 0; bit < 32; bit++) { + eViewLayerEEVEEPassType bitflag = (1 << bit); + if ((render_passes & bitflag) != 0) { + + DRW_texture_ensure_fullscreen_2d( + &txl->material_accum[render_pass_index], texture_format_material_accum, 0); + + /* Clear texture. */ + if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + GPU_framebuffer_texture_attach( + fbl->material_accum_fb, txl->material_accum[render_pass_index], 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); + GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); + GPU_framebuffer_bind(fbl->main_fb); + GPU_framebuffer_texture_detach(fbl->material_accum_fb, + txl->material_accum[render_pass_index]); + } + render_pass_index++; + } + } + + if ((render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && + (effects->enabled_effects & EFFECT_SSR)) { + EEVEE_reflection_output_init(sldata, vedata, tot_samples); + } + + if (render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + Scene *scene = draw_ctx->scene; + World *wo = scene->world; + + if (wo && wo->use_nodes && wo->nodetree) { + struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); + if (GPU_material_status(gpumat) == GPU_MAT_SUCCESS) { + DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->material_accum_pass[0]); + add_background_uniforms(grp, sldata, vedata); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + } + } + } +} + +void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + + if (fbl->material_accum_fb != NULL) { + for (int renderpass_index = 0; renderpass_index < stl->g_data->render_passes_material_count; + renderpass_index++) { + if (txl->material_accum[renderpass_index] != NULL) { + GPU_framebuffer_texture_attach( + fbl->material_accum_fb, txl->material_accum[renderpass_index], 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); + DRW_draw_pass(psl->material_accum_pass[renderpass_index]); + GPU_framebuffer_bind(fbl->main_fb); + GPU_framebuffer_texture_detach(fbl->material_accum_fb, + txl->material_accum[renderpass_index]); + } + } + if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && + (stl->effects->enabled_effects & EFFECT_SSR)) { + EEVEE_reflection_output_accumulate(sldata, vedata); + } + } +} + +int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + eViewLayerEEVEEPassType renderpass_type) +{ + EEVEE_StorageList *stl = vedata->stl; + + BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL) != 0); + BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL & renderpass_type) != 0); + + /* pass_index 0 is reserved for the environment pass. */ + if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT & renderpass_type) != 0) { + return 0; + } + + /* pass_index 0 is reserved for the environment pass. Other passes start from index 1 */ + int index = 1; + eViewLayerEEVEEPassType active_material_passes = stl->g_data->render_passes & + EEVEE_RENDERPASSES_MATERIAL & + ~EEVEE_RENDER_PASS_ENVIRONMENT; + + for (int bitshift = 0; bitshift < 32; bitshift++) { + eViewLayerEEVEEPassType pass_flag = (1 << bitshift); + if (pass_flag == renderpass_type) { + break; + } + if (active_material_passes & pass_flag) { + index++; + } + } + + return index; +} + +/* Get the pass index that contains the color pass for the given renderpass_type. */ +int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + eViewLayerEEVEEPassType renderpass_type) +{ + BLI_assert( + ELEM(renderpass_type, EEVEE_RENDER_PASS_DIFFUSE_LIGHT, EEVEE_RENDER_PASS_SPECULAR_LIGHT)); + eViewLayerEEVEEPassType color_pass_type; + switch (renderpass_type) { + case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: + color_pass_type = EEVEE_RENDER_PASS_DIFFUSE_COLOR; + break; + case EEVEE_RENDER_PASS_SPECULAR_LIGHT: + color_pass_type = EEVEE_RENDER_PASS_SPECULAR_COLOR; + break; + default: + color_pass_type = 0; + BLI_assert(false); + } + return EEVEE_material_output_pass_index_get(sldata, vedata, color_pass_type); +} +/* \} */ diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index c9b56a6d551..cdcfd64d995 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -114,6 +114,8 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRWShadingGroup *grp = DRW_shgroup_create(e_data.mist_sh, psl->mist_accum_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_vec3(grp, "mistSettings", &g_data->mist_start, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index 6ba518b3a28..be4dfd07ce1 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -170,6 +170,8 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { @@ -207,6 +209,8 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call(grp, quad, NULL); DRW_PASS_CREATE(psl->ao_horizon_search_layer, DRW_STATE_WRITE_COLOR); @@ -215,6 +219,8 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1); DRW_shgroup_call(grp, quad, NULL); @@ -227,6 +233,8 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call(grp, quad, NULL); } } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 7810de289df..7e93892ab3b 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -141,6 +141,13 @@ extern struct DrawEngineType draw_engine_eevee_type; #define MIN_CUBE_LOD_LEVEL 3 #define MAX_PLANAR_LOD_LEVEL 9 +/* All the renderpasses that use the GPUMaterial for accumulation */ +#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) +#define MAX_MATERIAL_RENDER_PASSES 6 +#define MAX_MATERIAL_RENDER_PASSES_UBO 6 /* World shader variations */ enum { VAR_WORLD_BACKGROUND = 0, @@ -198,6 +205,7 @@ typedef struct EEVEE_BoundBox { typedef struct EEVEE_PassList { /* Shadows */ struct DRWPass *shadow_pass; + struct DRWPass *shadow_accum_pass; /* Probes */ struct DRWPass *probe_background; @@ -220,6 +228,7 @@ typedef struct EEVEE_PassList { struct DRWPass *bloom_downsample; struct DRWPass *bloom_upsample; struct DRWPass *bloom_resolve; + struct DRWPass *bloom_accum_ps; struct DRWPass *dof_down; struct DRWPass *dof_scatter; struct DRWPass *dof_resolve; @@ -228,11 +237,11 @@ typedef struct EEVEE_PassList { struct DRWPass *volumetric_scatter_ps; struct DRWPass *volumetric_integration_ps; struct DRWPass *volumetric_resolve_ps; + struct DRWPass *volumetric_accum_ps; struct DRWPass *ssr_raytrace; struct DRWPass *ssr_resolve; struct DRWPass *sss_blur_ps; struct DRWPass *sss_resolve_ps; - struct DRWPass *sss_accum_ps; struct DRWPass *sss_translucency_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; @@ -264,6 +273,7 @@ typedef struct EEVEE_PassList { struct DRWPass *sss_pass_cull; struct DRWPass *material_pass; struct DRWPass *material_pass_cull; + struct DRWPass *material_accum_pass[MAX_MATERIAL_RENDER_PASSES]; struct DRWPass *refract_pass; struct DRWPass *transparent_pass; struct DRWPass *background_pass; @@ -281,6 +291,9 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *bloom_blit_fb; 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 *shadow_accum_fb; + struct GPUFrameBuffer *ssr_accum_fb; struct GPUFrameBuffer *sss_blur_fb; struct GPUFrameBuffer *sss_blit_fb; struct GPUFrameBuffer *sss_resolve_fb; @@ -292,9 +305,11 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *volumetric_fb; struct GPUFrameBuffer *volumetric_scat_fb; struct GPUFrameBuffer *volumetric_integ_fb; + struct GPUFrameBuffer *volumetric_accum_fb; struct GPUFrameBuffer *screen_tracing_fb; struct GPUFrameBuffer *refract_fb; struct GPUFrameBuffer *mist_accum_fb; + struct GPUFrameBuffer *material_accum_fb; struct GPUFrameBuffer *renderpass_fb; struct GPUFrameBuffer *ao_accum_fb; struct GPUFrameBuffer *velocity_resolve_fb; @@ -320,8 +335,11 @@ typedef struct EEVEE_TextureList { struct GPUTexture *color_post; /* R16_G16_B16 */ struct GPUTexture *mist_accum; struct GPUTexture *ao_accum; - struct GPUTexture *sss_dir_accum; - struct GPUTexture *sss_col_accum; + struct GPUTexture *sss_accum; + struct GPUTexture *material_accum[MAX_MATERIAL_RENDER_PASSES]; + struct GPUTexture *bloom_accum; + struct GPUTexture *ssr_accum; + struct GPUTexture *shadow_accum; struct GPUTexture *refract_color; struct GPUTexture *taa_history; @@ -333,6 +351,8 @@ typedef struct EEVEE_TextureList { struct GPUTexture *volume_transmit; struct GPUTexture *volume_scatter_history; struct GPUTexture *volume_transmit_history; + struct GPUTexture *volume_scatter_accum; + struct GPUTexture *volume_transmittance_accum; struct GPUTexture *lookdev_grid_tx; struct GPUTexture *lookdev_cube_tx; @@ -361,6 +381,17 @@ typedef struct EEVEE_StorageList { LightCacheTexture *lookdev_cube_mips; } EEVEE_StorageList; +/* ************ RENDERPASS UBO ************* */ +typedef struct EEVEE_RenderPassData { + int renderPassDiffuse; + int renderPassDiffuseLight; + int renderPassGlossy; + int renderPassGlossyLight; + int renderPassEmit; + int renderPassSSSColor; + int _pad[2]; +} EEVEE_RenderPassData; + /* ************ LIGHT UBO ************* */ typedef struct EEVEE_Light { float position[3], invsqrdist; @@ -408,6 +439,7 @@ BLI_STATIC_ASSERT_ALIGN(EEVEE_Light, 16) BLI_STATIC_ASSERT_ALIGN(EEVEE_Shadow, 16) BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCube, 16) BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCascade, 16) +BLI_STATIC_ASSERT_ALIGN(EEVEE_RenderPassData, 16) BLI_STATIC_ASSERT(sizeof(EEVEE_Shadow) * MAX_SHADOW + sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE + @@ -708,6 +740,10 @@ typedef struct EEVEE_ViewLayerData { struct GPUUniformBuffer *grid_ubo; struct GPUUniformBuffer *planar_ubo; + /* Material Render passes */ + struct EEVEE_RenderPassData renderpass_data[MAX_MATERIAL_RENDER_PASSES_UBO]; + struct GPUUniformBuffer *renderpass_ubo[MAX_MATERIAL_RENDER_PASSES_UBO]; + /* Common Uniform Buffer */ struct EEVEE_CommonUniformBuffer common_data; struct GPUUniformBuffer *common_ubo; @@ -759,6 +795,7 @@ typedef struct EEVEE_Data { typedef struct EEVEE_PrivateData { struct DRWShadingGroup *shadow_shgrp; + struct DRWShadingGroup *shadow_accum_shgrp; struct DRWShadingGroup *depth_shgrp; struct DRWShadingGroup *depth_shgrp_cull; struct DRWShadingGroup *depth_shgrp_clip; @@ -803,12 +840,17 @@ typedef struct EEVEE_PrivateData { /* Renderpasses */ /* Bitmask containing the active render_passes */ - eScenePassType render_passes; + eViewLayerEEVEEPassType render_passes; /* Uniform references that are referenced inside the `renderpass_pass`. They are updated * to reuse the drawing pass and the shading group. */ int renderpass_type; + int renderpass_postprocess; int renderpass_current_sample; GPUTexture *renderpass_input; + GPUTexture *renderpass_col_input; + GPUTexture *renderpass_light_input; + /* The number of active material based render passes */ + uint render_passes_material_count; /** For rendering shadows. */ struct DRWView *cube_views[6]; @@ -860,11 +902,20 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, bool use_hashed_alpha, bool is_shadow); struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma); +struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata); void EEVEE_materials_free(void); void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]); void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]); - +void EEVEE_material_renderpasses_init(EEVEE_Data *vedata); +void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); +void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + eViewLayerEEVEEPassType renderpass_type); +int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + eViewLayerEEVEEPassType renderpass_type); /* eevee_lights.c */ void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]); void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -896,6 +947,8 @@ void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view, int cascade_index); +void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); +void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_shadows_free(void); /* eevee_sampling.c */ @@ -995,6 +1048,8 @@ void EEVEE_depth_of_field_free(void); int EEVEE_bloom_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); 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); void EEVEE_bloom_free(void); /* eevee_occlusion.c */ @@ -1016,6 +1071,11 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_refraction_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_reflection_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_reflection_output_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + uint tot_samples); +void EEVEE_reflection_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); + void EEVEE_screen_raytrace_free(void); /* eevee_subsurface.c */ @@ -1055,10 +1115,12 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata); void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); -void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + bool post_effect); void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - eScenePassType renderpass_type); + eViewLayerEEVEEPassType renderpass_type); void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata); void EEVEE_renderpasses_free(void); @@ -1087,6 +1149,8 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_resolve(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); +void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_free_smoke_textures(void); void EEVEE_volumes_free(void); @@ -1104,7 +1168,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_free(void); /* eevee_render.c */ -void EEVEE_render_init(EEVEE_Data *vedata, +bool EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); void EEVEE_render_cache(void *vedata, diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 063510d51e6..3a5d9e96b80 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -46,7 +46,8 @@ #include "eevee_private.h" -void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph) +/* Return true if init properly. */ +bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph) { EEVEE_Data *vedata = (EEVEE_Data *)ved; EEVEE_StorageList *stl = vedata->stl; @@ -106,7 +107,7 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * max_dim); RE_engine_set_error_message(engine, error_msg); G.is_break = true; - return; + return false; } /* XXX overriding viewport size. Simplify things but is not really 100% safe. */ @@ -168,6 +169,8 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * EEVEE_subsurface_cache_init(sldata, vedata); EEVEE_temporal_sampling_cache_init(sldata, vedata); EEVEE_volumes_cache_init(sldata, vedata); + + return true; } /* Used by light cache. in this case engine is NULL. */ @@ -230,6 +233,9 @@ static void eevee_render_color_result(RenderLayer *rl, EEVEE_Data *vedata) { RenderPass *rp = RE_pass_find_by_name(rl, render_pass_name, viewname); + if (rp == NULL) { + return; + } GPU_framebuffer_bind(framebuffer); GPU_framebuffer_read_color(framebuffer, vedata->stl->g_data->overscan_pixels + rect->xmin, @@ -251,35 +257,6 @@ static void eevee_render_result_combined(RenderLayer *rl, rl, viewname, rect, RE_PASSNAME_COMBINED, 4, vedata->stl->effects->final_fb, vedata); } -static void eevee_render_result_subsurface(RenderLayer *rl, - const char *viewname, - const rcti *rect, - EEVEE_Data *vedata, - EEVEE_ViewLayerData *sldata) -{ - if (vedata->fbl->sss_accum_fb == NULL) { - /* SSS is not enabled. */ - return; - } - - if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_COLOR) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_COLOR); - eevee_render_color_result( - rl, viewname, rect, RE_PASSNAME_SUBSURFACE_COLOR, 3, vedata->fbl->renderpass_fb, vedata); - } - - if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_DIRECT) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_DIRECT); - eevee_render_color_result( - rl, viewname, rect, RE_PASSNAME_SUBSURFACE_DIRECT, 3, vedata->fbl->renderpass_fb, vedata); - } - - if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_INDIRECT) != 0) { - /* Do nothing as all the lighting is in the direct pass. - * TODO : Separate Direct from indirect lighting. */ - } -} - static void eevee_render_result_normal(RenderLayer *rl, const char *viewname, const rcti *rect, @@ -293,8 +270,8 @@ static void eevee_render_result_normal(RenderLayer *rl, return; } - if ((vedata->stl->g_data->render_passes & SCE_PASS_NORMAL) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_NORMAL); + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_NORMAL) != 0) { + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata); } @@ -313,8 +290,8 @@ static void eevee_render_result_z(RenderLayer *rl, return; } - if ((vedata->stl->g_data->render_passes & SCE_PASS_Z) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_Z); + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_Z) != 0) { + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata); } @@ -326,31 +303,142 @@ static void eevee_render_result_mist(RenderLayer *rl, EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata) { - if ((vedata->stl->g_data->render_passes & SCE_PASS_MIST) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_MIST); + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_MIST) != 0) { + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata); } } +static void eevee_render_result_shadow(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + 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_render_color_result( + rl, viewname, rect, RE_PASSNAME_SHADOW, 3, vedata->fbl->renderpass_fb, vedata); + } +} + static void eevee_render_result_occlusion(RenderLayer *rl, const char *viewname, const rcti *rect, EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata) { - if (vedata->fbl->ao_accum_fb == NULL) { + if ((vedata->stl->effects->enabled_effects & EFFECT_GTAO) == 0) { /* AO is not enabled. */ return; } - if ((vedata->stl->g_data->render_passes & SCE_PASS_AO) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_AO); + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AO) != 0) { + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata); } } +static void eevee_render_result_bloom(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + if ((vedata->stl->effects->enabled_effects & EFFECT_BLOOM) == 0) { + /* Bloom is not enabled. */ + return; + } + + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_BLOOM) != 0) { + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM); + eevee_render_color_result( + rl, viewname, rect, RE_PASSNAME_BLOOM, 3, vedata->fbl->renderpass_fb, vedata); + } +} + +#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_render_color_result( \ + rl, viewname, rect, RE_PASSNAME_##pass_name, 3, vedata->fbl->renderpass_fb, vedata); \ + } + +static void eevee_render_result_diffuse_color(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(DIFFUSE_COLOR, DIFFUSE_COLOR) +} + +static void eevee_render_result_diffuse_direct(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(DIFFUSE_DIRECT, DIFFUSE_LIGHT) +} + +static void eevee_render_result_specular_color(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(GLOSSY_COLOR, SPECULAR_COLOR) +} + +static void eevee_render_result_specular_direct(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(GLOSSY_DIRECT, SPECULAR_LIGHT) +} + +static void eevee_render_result_emission(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(EMIT, EMIT) +} + +static void eevee_render_result_environment(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(ENVIRONMENT, ENVIRONMENT) +} + +static void eevee_render_result_volume_scatter(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_SCATTER, VOLUME_SCATTER) +} +static void eevee_render_result_volume_transmittance(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_TRANSMITTANCE, VOLUME_TRANSMITTANCE) +} + +#undef EEVEE_RENDER_RESULT_MATERIAL_PASS + static void eevee_render_draw_background(EEVEE_Data *vedata) { EEVEE_FramebufferList *fbl = vedata->fbl; @@ -508,7 +596,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Volumetrics Resolve Opaque */ EEVEE_volumes_resolve(sldata, vedata); /* Subsurface output, Occlusion output, Mist output */ - EEVEE_renderpasses_output_accumulate(sldata, vedata); + EEVEE_renderpasses_output_accumulate(sldata, vedata, false); /* Transparent */ GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0); GPU_framebuffer_bind(fbl->main_color_fb); @@ -527,9 +615,18 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl } eevee_render_result_combined(rl, viewname, rect, vedata, sldata); - eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata); eevee_render_result_mist(rl, viewname, rect, vedata, sldata); eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata); + eevee_render_result_shadow(rl, viewname, rect, vedata, sldata); + eevee_render_result_diffuse_color(rl, viewname, rect, vedata, sldata); + eevee_render_result_diffuse_direct(rl, viewname, rect, vedata, sldata); + eevee_render_result_specular_color(rl, viewname, rect, vedata, sldata); + eevee_render_result_specular_direct(rl, viewname, rect, vedata, sldata); + eevee_render_result_emission(rl, viewname, rect, vedata, sldata); + eevee_render_result_environment(rl, viewname, rect, vedata, sldata); + 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); /* Restore original viewport size. */ DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]}); @@ -537,29 +634,35 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) { - int type; - RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA); -#define CHECK_PASS(name, channels, chanid) \ +#define CHECK_PASS_LEGACY(name, type, channels, chanid) \ if (view_layer->passflag & (SCE_PASS_##name)) { \ - if (channels == 4) \ - type = SOCK_RGBA; \ - else if (channels == 3) \ - type = SOCK_VECTOR; \ - else \ - type = SOCK_FLOAT; \ + RE_engine_register_pass( \ + engine, scene, view_layer, RE_PASSNAME_##name, channels, chanid, type); \ + } \ + ((void)0) +#define CHECK_PASS_EEVEE(name, type, channels, chanid) \ + if (view_layer->eevee.render_passes & (EEVEE_RENDER_PASS_##name)) { \ RE_engine_register_pass( \ engine, scene, view_layer, RE_PASSNAME_##name, channels, chanid, type); \ } \ ((void)0) - CHECK_PASS(Z, 1, "Z"); - CHECK_PASS(MIST, 1, "Z"); - CHECK_PASS(NORMAL, 3, "XYZ"); - CHECK_PASS(AO, 3, "RGB"); - CHECK_PASS(SUBSURFACE_COLOR, 3, "RGB"); - CHECK_PASS(SUBSURFACE_DIRECT, 3, "RGB"); + CHECK_PASS_LEGACY(Z, SOCK_FLOAT, 1, "Z"); + CHECK_PASS_LEGACY(MIST, SOCK_FLOAT, 1, "Z"); + CHECK_PASS_LEGACY(NORMAL, SOCK_VECTOR, 3, "XYZ"); + CHECK_PASS_LEGACY(SHADOW, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_LEGACY(AO, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_LEGACY(DIFFUSE_COLOR, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_LEGACY(DIFFUSE_DIRECT, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_LEGACY(GLOSSY_COLOR, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_LEGACY(GLOSSY_DIRECT, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_LEGACY(EMIT, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_LEGACY(ENVIRONMENT, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_EEVEE(VOLUME_SCATTER, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_EEVEE(VOLUME_TRANSMITTANCE, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_EEVEE(BLOOM, SOCK_RGBA, 3, "RGB"); #undef CHECK_PASS } diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 44a6c41e170..2f9e8f3d555 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -42,19 +42,35 @@ static struct { struct GPUShader *postprocess_sh; } e_data = {NULL}; /* Engine data */ +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, +} eRenderPassPostProcessType; + /* bitmask containing all renderpasses that need post-processing */ #define EEVEE_RENDERPASSES_WITH_POST_PROCESSING \ - (SCE_PASS_Z | SCE_PASS_MIST | SCE_PASS_NORMAL | SCE_PASS_AO | SCE_PASS_SUBSURFACE_COLOR | \ - SCE_PASS_SUBSURFACE_DIRECT) - -#define EEVEE_RENDERPASSES_SUBSURFACE \ - (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_INDIRECT) + (EEVEE_RENDER_PASS_Z | EEVEE_RENDER_PASS_MIST | EEVEE_RENDER_PASS_NORMAL | \ + EEVEE_RENDER_PASS_AO | EEVEE_RENDER_PASS_BLOOM | EEVEE_RENDER_PASS_VOLUME_SCATTER | \ + EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_SHADOW | \ + EEVEE_RENDERPASSES_MATERIAL) -#define EEVEE_RENDERPASSES_ALL (EEVEE_RENDERPASSES_WITH_POST_PROCESSING | SCE_PASS_COMBINED) +#define EEVEE_RENDERPASSES_ALL \ + (EEVEE_RENDERPASSES_WITH_POST_PROCESSING | EEVEE_RENDER_PASS_COMBINED) -#define EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE (SCE_PASS_Z | SCE_PASS_NORMAL) +#define EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE \ + (EEVEE_RENDER_PASS_Z | EEVEE_RENDER_PASS_NORMAL) -#define EEVEE_RENDERPASSES_COLOR_PASS (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT) +#define EEVEE_RENDERPASSES_COLOR_PASS \ + (EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_EMIT | \ + EEVEE_RENDER_PASS_BLOOM) +#define EEVEE_RENDERPASSES_LIGHT_PASS \ + (EEVEE_RENDER_PASS_DIFFUSE_LIGHT | EEVEE_RENDER_PASS_SPECULAR_LIGHT) bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata) { @@ -75,8 +91,33 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata) g_data->render_passes = v3d->shading.render_pass; } else { - g_data->render_passes = (view_layer->passflag & EEVEE_RENDERPASSES_ALL) | SCE_PASS_COMBINED; + eViewLayerEEVEEPassType enabled_render_passes = view_layer->eevee.render_passes; + +#define ENABLE_FROM_LEGACY(name_legacy, name_eevee) \ + SET_FLAG_FROM_TEST(enabled_render_passes, \ + (view_layer->passflag & SCE_PASS_##name_legacy) != 0, \ + EEVEE_RENDER_PASS_##name_eevee); + + ENABLE_FROM_LEGACY(Z, Z) + ENABLE_FROM_LEGACY(MIST, MIST) + ENABLE_FROM_LEGACY(NORMAL, NORMAL) + ENABLE_FROM_LEGACY(SHADOW, SHADOW) + ENABLE_FROM_LEGACY(AO, AO) + ENABLE_FROM_LEGACY(EMIT, EMIT) + ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT) + ENABLE_FROM_LEGACY(DIFFUSE_COLOR, DIFFUSE_COLOR) + ENABLE_FROM_LEGACY(GLOSSY_COLOR, SPECULAR_COLOR) + ENABLE_FROM_LEGACY(DIFFUSE_DIRECT, DIFFUSE_LIGHT) + ENABLE_FROM_LEGACY(GLOSSY_DIRECT, SPECULAR_LIGHT) + + ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT) + +#undef ENABLE_FROM_LEGACY + g_data->render_passes = (enabled_render_passes & EEVEE_RENDERPASSES_ALL) | + EEVEE_RENDER_PASS_COMBINED; } + + EEVEE_material_renderpasses_init(vedata); } void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, @@ -87,6 +128,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; EEVEE_PrivateData *g_data = stl->g_data; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); @@ -106,33 +148,54 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, /* Should be enough to store the data needs for a single pass. * Some passes will use less, but it is only relevant for final renderings and - * when renderpasses other than `SCE_PASS_COMBINED` are requested */ + * when renderpasses other than `EEVEE_RENDER_PASS_COMBINED` are requested */ DRW_texture_ensure_fullscreen_2d(&txl->renderpass, GPU_RGBA16F, 0); GPU_framebuffer_ensure_config(&fbl->renderpass_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->renderpass)}); - if ((g_data->render_passes & EEVEE_RENDERPASSES_SUBSURFACE) != 0) { - EEVEE_subsurface_output_init(sldata, vedata, tot_samples); + if ((g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL) != 0) { + EEVEE_material_output_init(sldata, vedata, tot_samples); } - if ((g_data->render_passes & SCE_PASS_MIST) != 0) { + if ((g_data->render_passes & EEVEE_RENDER_PASS_MIST) != 0) { EEVEE_mist_output_init(sldata, vedata); } + if ((g_data->render_passes & EEVEE_RENDER_PASS_SHADOW) != 0) { + EEVEE_shadow_output_init(sldata, vedata, tot_samples); + } - if ((g_data->render_passes & SCE_PASS_AO) != 0) { + if ((g_data->render_passes & EEVEE_RENDER_PASS_AO) != 0) { EEVEE_occlusion_output_init(sldata, vedata, tot_samples); } + if ((g_data->render_passes & EEVEE_RENDER_PASS_BLOOM) != 0 && + (effects->enabled_effects & EFFECT_BLOOM) != 0) { + EEVEE_bloom_output_init(sldata, vedata, tot_samples); + } + + if ((g_data->render_passes & + (EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_VOLUME_SCATTER)) != 0) { + EEVEE_volumes_output_init(sldata, vedata, tot_samples); + } + /* Create Pass. */ DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass); /* We set a default texture as not all post processes uses the inputBuffer. */ g_data->renderpass_input = txl->color; + g_data->renderpass_col_input = txl->color; + g_data->renderpass_light_input = txl->color; DRW_shgroup_uniform_texture_ref(grp, "inputBuffer", &g_data->renderpass_input); + DRW_shgroup_uniform_texture_ref(grp, "inputColorBuffer", &g_data->renderpass_col_input); + DRW_shgroup_uniform_texture_ref( + grp, "inputSecondLightBuffer", &g_data->renderpass_light_input); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_int(grp, "currentSample", &g_data->renderpass_current_sample, 1); DRW_shgroup_uniform_int(grp, "renderpassType", &g_data->renderpass_type, 1); + DRW_shgroup_uniform_int(grp, "postProcessType", &g_data->renderpass_postprocess, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { @@ -152,12 +215,13 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, * Only invoke this function for passes that need post-processing. * * After invoking this function the active framebuffer is set to `vedata->fbl->renderpass_fb`. */ -void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), +void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - eScenePassType renderpass_type) + eViewLayerEEVEEPassType renderpass_type) { EEVEE_PassList *psl = vedata->psl; EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_PrivateData *g_data = stl->g_data; EEVEE_EffectsInfo *effects = stl->effects; @@ -165,51 +229,133 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), const int current_sample = effects->taa_current_sample; g_data->renderpass_current_sample = current_sample; g_data->renderpass_type = renderpass_type; + g_data->renderpass_postprocess = PASS_POST_UNDEFINED; switch (renderpass_type) { - case SCE_PASS_AO: { + case EEVEE_RENDER_PASS_Z: { + g_data->renderpass_postprocess = PASS_POST_DEPTH; + break; + } + case EEVEE_RENDER_PASS_AO: { + g_data->renderpass_postprocess = PASS_POST_AO; g_data->renderpass_input = txl->ao_accum; break; } - case SCE_PASS_NORMAL: { + case EEVEE_RENDER_PASS_NORMAL: { + g_data->renderpass_postprocess = PASS_POST_NORMAL; g_data->renderpass_input = effects->ssr_normal_input; break; } - case SCE_PASS_MIST: { + case EEVEE_RENDER_PASS_MIST: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_VALUE; g_data->renderpass_input = txl->mist_accum; break; } - case SCE_PASS_SUBSURFACE_DIRECT: { - g_data->renderpass_input = txl->sss_dir_accum; + case EEVEE_RENDER_PASS_VOLUME_SCATTER: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->volume_scatter_accum; + break; + } + case EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->volume_transmittance_accum; + break; + } + case EEVEE_RENDER_PASS_SHADOW: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_VALUE; + g_data->renderpass_input = txl->shadow_accum; break; } - case SCE_PASS_SUBSURFACE_COLOR: { - g_data->renderpass_input = txl->sss_col_accum; + case EEVEE_RENDER_PASS_DIFFUSE_COLOR: + case EEVEE_RENDER_PASS_SPECULAR_COLOR: + case EEVEE_RENDER_PASS_ENVIRONMENT: + case EEVEE_RENDER_PASS_EMIT: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); + g_data->renderpass_input = txl->material_accum[renderpass_index]; + break; + } + case EEVEE_RENDER_PASS_SPECULAR_LIGHT: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; + int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); + int renderpass_index_color = EEVEE_material_output_color_pass_index_get( + sldata, vedata, renderpass_type); + g_data->renderpass_input = txl->material_accum[renderpass_index]; + g_data->renderpass_col_input = txl->material_accum[renderpass_index_color]; + if ((stl->effects->enabled_effects & EFFECT_SSR) != 0) { + g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS; + g_data->renderpass_light_input = txl->ssr_accum; + } + else { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; + } + break; + } + case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; + int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type); + int renderpass_index_color = EEVEE_material_output_color_pass_index_get( + sldata, vedata, renderpass_type); + g_data->renderpass_input = txl->material_accum[renderpass_index]; + g_data->renderpass_col_input = txl->material_accum[renderpass_index_color]; + if ((stl->effects->enabled_effects & EFFECT_SSS) != 0) { + g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS; + g_data->renderpass_light_input = txl->sss_accum; + } + else { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT; + } + break; + } + case EEVEE_RENDER_PASS_BLOOM: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_input = txl->bloom_accum; + g_data->renderpass_current_sample = 1; break; } default: { break; } } - GPU_framebuffer_bind(vedata->fbl->renderpass_fb); + GPU_framebuffer_bind(fbl->renderpass_fb); DRW_draw_pass(psl->renderpass_pass); } -void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + bool post_effect) { EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - eScenePassType render_pass = stl->g_data->render_passes; + eViewLayerEEVEEPassType render_pass = stl->g_data->render_passes; - if ((render_pass & SCE_PASS_MIST) != 0) { - EEVEE_mist_output_accumulate(sldata, vedata); - } - if ((effects->enabled_effects & EFFECT_SSS) && - (render_pass & EEVEE_RENDERPASSES_SUBSURFACE) != 0) { - EEVEE_subsurface_output_accumulate(sldata, vedata); + if (!post_effect) { + if ((render_pass & EEVEE_RENDER_PASS_MIST) != 0) { + EEVEE_mist_output_accumulate(sldata, vedata); + } + if ((render_pass & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) != 0 && + (effects->enabled_effects & EFFECT_SSS) != 0) { + EEVEE_subsurface_output_accumulate(sldata, vedata); + } + if ((render_pass & EEVEE_RENDER_PASS_AO) != 0) { + EEVEE_occlusion_output_accumulate(sldata, vedata); + } + if ((render_pass & EEVEE_RENDER_PASS_SHADOW) != 0) { + EEVEE_shadow_output_accumulate(sldata, vedata); + } + if ((render_pass & EEVEE_RENDERPASSES_MATERIAL) != 0) { + EEVEE_material_output_accumulate(sldata, vedata); + } + if ((render_pass & + (EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_VOLUME_SCATTER)) != 0) { + EEVEE_volumes_output_accumulate(sldata, vedata); + } } - if ((render_pass & SCE_PASS_AO) != 0) { - EEVEE_occlusion_output_accumulate(sldata, vedata); + else { + if ((render_pass & EEVEE_RENDER_PASS_BLOOM) != 0 && + (effects->enabled_effects & EFFECT_BLOOM) != 0) { + EEVEE_bloom_output_accumulate(sldata, vedata); + } } } @@ -220,7 +366,13 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - eScenePassType render_pass = stl->g_data->render_passes; + + /* We can only draw a single renderpass. Lightpasses also select their color pass (a second + pass). We mask the light pass when a light pass is selected. */ + const eViewLayerEEVEEPassType render_pass = + ((stl->g_data->render_passes & EEVEE_RENDERPASSES_LIGHT_PASS) != 0) ? + (stl->g_data->render_passes & EEVEE_RENDERPASSES_LIGHT_PASS) : + stl->g_data->render_passes; const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); @@ -229,14 +381,14 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_state_is_opengl_render(); UNUSED_VARS(needs_color_transfer); - /* When SSS isn't available, but the pass is requested, we mark it as invalid */ - if ((render_pass & EEVEE_RENDERPASSES_SUBSURFACE) != 0 && - (effects->enabled_effects & EFFECT_SSS) == 0) { + if ((render_pass & EEVEE_RENDER_PASS_BLOOM) != 0 && + (effects->enabled_effects & EFFECT_BLOOM) == 0) { is_valid = false; } /* When SSS isn't available, but the pass is requested, we mark it as invalid */ - if ((render_pass & SCE_PASS_AO) != 0 && (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) == 0) { + if ((render_pass & EEVEE_RENDER_PASS_AO) != 0 && + (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) == 0) { is_valid = false; } @@ -254,7 +406,7 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } else { /* Draw state is not valid for this pass, clear the buffer */ - static float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + static float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; GPU_framebuffer_bind(dfbl->default_fb); GPU_framebuffer_clear_color(dfbl->default_fb, clear_color); } diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 591ca31017c..d231edf1383 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -235,6 +235,8 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); if (!effects->reflection_trace_full) { DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1); } @@ -255,6 +257,8 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1); if ((effects->enabled_effects & EFFECT_GTAO) != 0) { DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); @@ -335,6 +339,43 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v } } +void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + uint tot_samples) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + /* Create FrameBuffer. */ + const eGPUTextureFormat texture_format = (tot_samples > 256) ? GPU_RGBA32F : GPU_RGBA16F; + DRW_texture_ensure_fullscreen_2d(&txl->ssr_accum, texture_format, 0); + + GPU_framebuffer_ensure_config(&fbl->ssr_accum_fb, + {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ssr_accum)}); + + /* Clear texture. */ + if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + GPU_framebuffer_bind(fbl->ssr_accum_fb); + GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear); + } +} + +void EEVEE_reflection_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + + if (stl->g_data->valid_double_buffer) { + GPU_framebuffer_bind(fbl->ssr_accum_fb); + DRW_draw_pass(psl->ssr_resolve); + } +} + void EEVEE_screen_raytrace_free(void) { for (int i = 0; i < SSR_MAX_SHADER; i++) { diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 1776f535237..f5b98d464dd 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -21,6 +21,7 @@ */ #include "BLI_sys_types.h" /* bool */ +#include "BLI_string_utils.h" // #include "BLI_dynstr.h" // #include "BLI_rand.h" @@ -35,11 +36,17 @@ static struct { struct GPUShader *shadow_sh; + struct GPUShader *shadow_accum_sh; } e_data = {NULL}; /* Engine data */ extern char datatoc_shadow_vert_glsl[]; extern char datatoc_shadow_frag_glsl[]; +extern char datatoc_shadow_accum_frag_glsl[]; extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; +extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_lights_lib_glsl[]; +extern char datatoc_raytrace_lib_glsl[]; void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh) { @@ -65,6 +72,18 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata) NULL); } + if (!e_data.shadow_accum_sh) { + char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_raytrace_lib_glsl, + datatoc_lights_lib_glsl, + datatoc_shadow_accum_frag_glsl); + + e_data.shadow_accum_sh = DRW_shader_create_fullscreen(frag_str, SHADER_DEFINES); + MEM_freeN(frag_str); + } + if (!sldata->lights) { sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo"); sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL); @@ -170,6 +189,8 @@ void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); if (alpha_threshold != NULL) { @@ -406,7 +427,75 @@ void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView } } +/* -------------------------------------------------------------------- */ + +/** \name Render Passes + * \{ */ + +void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + uint UNUSED(tot_samples)) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + /* Create FrameBuffer. */ + const eGPUTextureFormat texture_format = GPU_R32F; + DRW_texture_ensure_fullscreen_2d(&txl->shadow_accum, texture_format, 0); + + GPU_framebuffer_ensure_config(&fbl->shadow_accum_fb, + {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->shadow_accum)}); + + /* Clear texture. */ + if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + GPU_framebuffer_bind(fbl->shadow_accum_fb); + GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear); + } + + /* Create Pass and shgroup. */ + DRW_PASS_CREATE(psl->shadow_accum_pass, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ADD_FULL); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_accum_sh, psl->shadow_accum_pass); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); + + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); +} + +void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_PassList *psl = vedata->psl; + + if (fbl->shadow_accum_fb != NULL) { + GPU_framebuffer_bind(fbl->shadow_accum_fb); + DRW_draw_pass(psl->shadow_accum_pass); + + /* Restore */ + GPU_framebuffer_bind(fbl->main_fb); + } +} + +/* \} */ + void EEVEE_shadows_free(void) { DRW_SHADER_FREE_SAFE(e_data.shadow_sh); + DRW_SHADER_FREE_SAFE(e_data.shadow_accum_sh); } diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cascade.c b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c index 32045e12a1c..1fd8d818b33 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows_cascade.c +++ b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c @@ -120,11 +120,6 @@ static void frustum_min_bounding_sphere(const float corners[8][3], #endif } -BLI_INLINE float lerp(float t, float a, float b) -{ - return ((a) + (t) * ((b) - (a))); -} - static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, DRWView *view, @@ -254,11 +249,11 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo, for (int c = 1; c < cascade_nbr; c++) { /* View Space */ - float linear_split = lerp(((float)(c) / (float)cascade_nbr), csm_start, csm_end); - float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr); + float linear_split = interpf(csm_end, csm_start, c / (float)cascade_nbr); + float exp_split = csm_start * powf(csm_end / csm_start, c / (float)cascade_nbr); if (is_persp) { - csm_data->split_start[c] = lerp(cascade_exponent, linear_split, exp_split); + csm_data->split_start[c] = interpf(exp_split, linear_split, cascade_exponent); } else { csm_data->split_start[c] = linear_split; @@ -266,10 +261,10 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo, csm_data->split_end[c - 1] = csm_data->split_start[c]; /* Add some overlap for smooth transition */ - csm_data->split_start[c] = lerp(cascade_fade, - csm_data->split_end[c - 1], - (c > 1) ? csm_data->split_end[c - 2] : - csm_data->split_start[0]); + csm_data->split_start[c] = interpf((c > 1) ? csm_data->split_end[c - 2] : + csm_data->split_start[0], + csm_data->split_end[c - 1], + cascade_fade); /* NDC Space */ { @@ -298,7 +293,8 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo, /* Set last cascade split fade distance into the first split_start. */ float prev_split = (cascade_nbr > 1) ? csm_data->split_end[cascade_nbr - 2] : csm_data->split_start[0]; - csm_data->split_start[0] = lerp(cascade_fade, csm_data->split_end[cascade_nbr - 1], prev_split); + csm_data->split_start[0] = interpf( + prev_split, csm_data->split_end[cascade_nbr - 1], cascade_fade); /* For each cascade */ for (int c = 0; c < cascade_nbr; c++) { diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index e94fc903694..98e799acb5e 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -33,7 +33,7 @@ #include "GPU_extensions.h" static struct { - struct GPUShader *sss_sh[4]; + struct GPUShader *sss_sh[3]; } e_data = {{NULL}}; /* Engine data */ extern char datatoc_common_view_lib_glsl[]; @@ -64,8 +64,7 @@ static void eevee_create_shader_subsurface(void) e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n"); e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"); - e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define RESULT_ACCUM\n"); - e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_translucent_str, + e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_translucent_str, "#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES); MEM_freeN(frag_translucent_str); @@ -85,9 +84,10 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; } -void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); @@ -138,72 +138,64 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance), GPU_ATTACHMENT_TEXTURE(effects->sss_radius)}); + if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) != 0) { + EEVEE_subsurface_output_init(sldata, vedata, 0); + } + else { + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); + txl->sss_accum = NULL; + } } else { /* Cleanup to release memory */ GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_blur_fb); GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb); GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); effects->sss_stencil = NULL; effects->sss_blur = NULL; effects->sss_irradiance = NULL; effects->sss_radius = NULL; + txl->sss_accum = NULL; } } -static void set_shgrp_stencil(void *UNUSED(userData), DRWShadingGroup *shgrp) -{ - DRW_shgroup_stencil_mask(shgrp, 255); -} - void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, - uint tot_samples) + uint UNUSED(tot_samples)) { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - if (effects->enabled_effects & EFFECT_SSS) { - const eGPUTextureFormat texture_format_light = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; - const eGPUTextureFormat texture_format_color = (tot_samples > 512) ? GPU_RGBA32F : GPU_RGBA16F; - DRW_texture_ensure_fullscreen_2d(&txl->sss_dir_accum, texture_format_light, 0); - DRW_texture_ensure_fullscreen_2d(&txl->sss_col_accum, texture_format_color, 0); - - GPUTexture *stencil_tex = effects->sss_stencil; + const eGPUTextureFormat texture_format_light = GPU_RGBA32F; + const bool texture_created = txl->sss_accum == NULL; + DRW_texture_ensure_fullscreen_2d(&txl->sss_accum, texture_format_light, 0); - if (GPU_depth_blitting_workaround()) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - /* Blitting stencil buffer does not work on macOS + Radeon Pro. - * Blit depth instead and use sss_stencil's depth as depth texture, - * and dtxl->depth as stencil mask. */ - stencil_tex = dtxl->depth; - } + GPUTexture *stencil_tex = effects->sss_stencil; - GPU_framebuffer_ensure_config(&fbl->sss_accum_fb, - {GPU_ATTACHMENT_TEXTURE(stencil_tex), - GPU_ATTACHMENT_TEXTURE(txl->sss_dir_accum), - GPU_ATTACHMENT_TEXTURE(txl->sss_col_accum)}); + if (GPU_depth_blitting_workaround()) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + /* Blitting stencil buffer does not work on macOS + Radeon Pro. + * Blit depth instead and use sss_stencil's depth as depth texture, + * and dtxl->depth as stencil mask. */ + stencil_tex = dtxl->depth; + } - /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { - float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - GPU_framebuffer_bind(fbl->sss_accum_fb); - GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear); - } + GPU_framebuffer_ensure_config( + &fbl->sss_accum_fb, + {GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(txl->sss_accum)}); - /* Make the opaque refraction pass mask the sss. */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - DRW_pass_state_set(vedata->psl->refract_pass, state); - DRW_pass_foreach_shgroup(vedata->psl->refract_pass, &set_shgrp_stencil, NULL); - } - else { - /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->sss_dir_accum); - DRW_TEXTURE_FREE_SAFE(txl->sss_col_accum); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); + /* Clear texture. + * Due to the late initialization of the SSS it can happen that the `taa_current_sample` is + * already higher than one. This is noticeable when loading a file that has the diffuse light + * pass in look dev mode active. `texture_created` will make sure that newly created textures + * are cleared. */ + if (DRW_state_is_image_render() || effects->taa_current_sample == 1 || texture_created) { + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_bind(fbl->sss_accum_fb); + GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear); } } @@ -222,7 +214,6 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL; DRW_PASS_CREATE(psl->sss_blur_ps, state); DRW_PASS_CREATE(psl->sss_resolve_ps, state | DRW_STATE_BLEND_ADD); - DRW_PASS_CREATE(psl->sss_accum_ps, state | DRW_STATE_BLEND_ADD); DRW_PASS_CREATE(psl->sss_translucency_ps, state | DRW_STATE_BLEND_ADD); } @@ -245,6 +236,8 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call(grp, quad, NULL); @@ -256,22 +249,10 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call(grp, quad, NULL); - - if ((stl->g_data->render_passes & (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT)) != - 0) { - grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_accum_ps); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); - DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); - DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call(grp, quad, NULL); - } } void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, @@ -287,7 +268,7 @@ void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth; - DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_translucency_ps); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_translucency_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); @@ -298,6 +279,8 @@ void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call(grp, quad, NULL); } @@ -408,11 +391,11 @@ void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEV if (((effects->enabled_effects & EFFECT_SSS) != 0) && (fbl->sss_accum_fb != NULL)) { /* Copy stencil channel, could be avoided (see EEVEE_subsurface_init) */ - GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT); + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_accum_fb, 0, GPU_STENCIL_BIT); /* Only do vertical pass + Resolve */ GPU_framebuffer_bind(fbl->sss_accum_fb); - DRW_draw_pass(psl->sss_accum_ps); + DRW_draw_pass(psl->sss_resolve_ps); /* Restore */ GPU_framebuffer_bind(fbl->main_fb); @@ -424,5 +407,4 @@ void EEVEE_subsurface_free(void) DRW_SHADER_FREE_SAFE(e_data.sss_sh[0]); DRW_SHADER_FREE_SAFE(e_data.sss_sh[1]); DRW_SHADER_FREE_SAFE(e_data.sss_sh[2]); - DRW_SHADER_FREE_SAFE(e_data.sss_sh[3]); } diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index 093a4780a97..bd77279eb4a 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -290,6 +290,8 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data DRW_shgroup_uniform_texture_ref(grp, "colorHistoryBuffer", &txl->taa_history); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); if (effects->enabled_effects & EFFECT_TAA_REPROJECT) { // DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 7026894076a..456673c92fa 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -54,6 +54,7 @@ static struct { struct GPUShader *scatter_with_lights_sh; struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh; + struct GPUShader *volumetric_accum_sh; GPUTexture *depth_src; @@ -73,6 +74,7 @@ extern char datatoc_common_view_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lights_lib_glsl[]; +extern char datatoc_volumetric_accum_frag_glsl[]; extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_geom_glsl[]; extern char datatoc_volumetric_vert_glsl[]; @@ -136,6 +138,8 @@ static void eevee_create_shader_volumes(void) datatoc_volumetric_resolve_frag_glsl, e_data.volumetric_common_lib, NULL); + e_data.volumetric_accum_sh = DRW_shader_create_fullscreen(datatoc_volumetric_accum_frag_glsl, + NULL); float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, color); @@ -359,6 +363,8 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); /* Fix principle volumetric not working with world materials. */ DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); @@ -375,6 +381,8 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* If no world or volume material is present just clear the buffer with this drawcall */ grp = DRW_shgroup_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); } @@ -430,8 +438,12 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); @@ -522,6 +534,8 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); @@ -530,6 +544,8 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter); DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call_procedural_triangles( grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]); @@ -540,6 +556,8 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -729,4 +747,75 @@ void EEVEE_volumes_free(void) DRW_SHADER_FREE_SAFE(e_data.scatter_with_lights_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh); + DRW_SHADER_FREE_SAFE(e_data.volumetric_accum_sh); +} + +/* -------------------------------------------------------------------- */ + +/** \name Render Passes + * \{ */ + +void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = stl->effects; + + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + /* Create FrameBuffer. */ + + /* Should be enough precision for many samples. */ + const eGPUTextureFormat texture_format_accum = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; + DRW_texture_ensure_fullscreen_2d(&txl->volume_scatter_accum, texture_format_accum, 0); + DRW_texture_ensure_fullscreen_2d(&txl->volume_transmittance_accum, texture_format_accum, 0); + + GPU_framebuffer_ensure_config(&fbl->volumetric_accum_fb, + {GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_accum), + GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_accum)}); + + /* Clear texture. */ + if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + GPU_framebuffer_bind(fbl->volumetric_accum_fb); + GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear); + } + + /* Create Pass and shgroup. */ + DRW_PASS_CREATE(psl->volumetric_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); + DRWShadingGroup *grp = NULL; + if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { + grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_accum_ps); + DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); + DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block( + grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); + } + else { + /* There is no volumetrics in the scene. Use a shader to fill the accum textures with a default + * value. */ + grp = DRW_shgroup_create(e_data.volumetric_accum_sh, psl->volumetric_accum_ps); + } + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } + +void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_PassList *psl = vedata->psl; + + if (fbl->volumetric_accum_fb != NULL) { + /* Accum pass */ + GPU_framebuffer_bind(fbl->volumetric_accum_fb); + DRW_draw_pass(psl->volumetric_accum_ps); + + /* Restore */ + GPU_framebuffer_bind(fbl->main_fb); + } +} + +/* \} */ diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index c4f815b5dd4..c3518198805 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -85,6 +85,37 @@ struct ShadowCascadeData { #define sh_shadow_vec shadow_vec_id.xyz #define sh_tex_index shadow_vec_id.w +/* ------ Render Passes ----- */ +layout(std140) uniform renderpass_block +{ + bool renderPassDiffuse; + bool renderPassDiffuseLight; + bool renderPassGlossy; + bool renderPassGlossyLight; + bool renderPassEmit; + bool renderPassSSSColor; +}; + +vec3 render_pass_diffuse_mask(vec3 diffuse_color, vec3 diffuse_light) +{ + return renderPassDiffuse ? (renderPassDiffuseLight ? diffuse_light : diffuse_color) : vec3(0.0); +} + +vec3 render_pass_sss_mask(vec3 sss_color) +{ + return renderPassSSSColor ? sss_color : vec3(0.0); +} + +vec3 render_pass_glossy_mask(vec3 specular_color, vec3 specular_light) +{ + return renderPassGlossy ? (renderPassGlossyLight ? specular_light : specular_color) : vec3(0.0); +} + +vec3 render_pass_emission_mask(vec3 emission_light) +{ + return renderPassEmit ? emission_light : vec3(0.0); +} + /* ------- Convenience functions --------- */ vec3 mul(mat3 m, vec3 v) @@ -833,11 +864,12 @@ void closure_load_sss_data( cl.sss_radius = radius; cl.sss_albedo = sss_albedo; cl.flag |= CLOSURE_SSS_FLAG; + cl.radiance += render_pass_diffuse_mask(sss_albedo, vec3(0)); } else # endif { - cl.radiance += sss_irradiance * sss_albedo; + cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo); } } diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index a031ed193b6..1014b25033a 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -34,7 +34,8 @@ Closure nodetree_exec(void) eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, true, out_diff, out_spec, ssr_spec); Closure cl = CLOSURE_DEFAULT; - cl.radiance = out_spec + out_diff * albedo; + cl.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) + + render_pass_diffuse_mask(albedo, out_diff * albedo); closure_load_ssr_data(ssr_spec, roughness, N, viewCameraVec, 1, cl); #ifdef LOOKDEV diff --git a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl index 299cb2094c1..18f92c0dd33 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl @@ -40,6 +40,7 @@ uniform float sampleScale; /* Step Resolve */ uniform vec3 bloomColor; +uniform bool bloomAddBase; in vec4 uvcoordsvar; @@ -201,9 +202,9 @@ vec4 step_resolve(void) #else vec3 blur = upsample_filter(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize); #endif - vec4 base = textureLod(baseBuffer, uvcoordsvar.xy, 0.0); - vec3 cout = base.rgb + blur * bloomColor; - return vec4(cout, base.a); + vec3 base = bloomAddBase ? textureLod(baseBuffer, uvcoordsvar.xy, 0.0).rgb : vec3(0.0); + vec3 cout = base + blur * bloomColor; + return vec4(cout, 1.0); } void main(void) diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 1241cf0e387..e9da49c9eb9 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -20,13 +20,7 @@ uniform sampler2DArray utilTex; # define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -#ifdef RESULT_ACCUM -/* Render Passes Accumulation */ -layout(location = 0) out vec4 sssDirect; -layout(location = 1) out vec4 sssColor; -#else layout(location = 0) out vec4 sssRadiance; -#endif float get_view_z_from_depth(float depth) { @@ -87,10 +81,7 @@ void main(void) accum += kernel[i].rgb * mix(color, sss_irradiance, s); } -#ifdef RESULT_ACCUM - sssDirect = vec4(accum, 1.0); - sssColor = vec4(texture(sssAlbedo, uvs).rgb, 1.0); -#elif defined(FIRST_PASS) +#if defined(FIRST_PASS) sssRadiance = vec4(accum, 1.0); #else /* SECOND_PASS */ sssRadiance = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0); diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index 6427f02ed25..3b9d0a8f2bc 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -173,19 +173,17 @@ float light_attenuation(LightData ld, vec4 l_vector) return vis; } -float light_visibility(LightData ld, - vec3 W, +float light_shadowing(LightData ld, + vec3 W, #ifndef VOLUMETRICS - vec3 viewPosition, - float tracing_depth, - vec3 true_normal, - float rand_x, - const bool use_contact_shadows, + vec3 viewPosition, + float tracing_depth, + vec3 true_normal, + float rand_x, + const bool use_contact_shadows, #endif - vec4 l_vector) + float vis) { - float vis = light_attenuation(ld, l_vector); - #if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW) /* shadowing */ if (ld.l_shadowid >= 0.0 && vis > 0.001) { @@ -236,6 +234,30 @@ float light_visibility(LightData ld, return vis; } +float light_visibility(LightData ld, + vec3 W, +#ifndef VOLUMETRICS + vec3 viewPosition, + float tracing_depth, + vec3 true_normal, + float rand_x, + const bool use_contact_shadows, +#endif + vec4 l_vector) +{ + float l_atten = light_attenuation(ld, l_vector); + return light_shadowing(ld, + W, +#ifndef VOLUMETRICS + viewPosition, + tracing_depth, + true_normal, + rand_x, + use_contact_shadows, +#endif + l_atten); +} + #ifdef USE_LTC float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector) { 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 35bfb411cb9..5214301bc03 100644 --- a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl @@ -1,15 +1,17 @@ -#define SCE_PASS_Z (1 << 1) -#define SCE_PASS_AO (1 << 6) -#define SCE_PASS_NORMAL (1 << 8) -#define SCE_PASS_MIST (1 << 14) -#define SCE_PASS_SUBSURFACE_DIRECT (1 << 28) -#define SCE_PASS_SUBSURFACE_COLOR (1 << 30) +#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 ACCUMULATED_COLOR_PASSES (SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_COLOR) -#define ACCUMULATED_VALUE_PASSES (SCE_PASS_MIST) -uniform int renderpassType; +uniform int postProcessType; uniform int currentSample; uniform sampler2D inputBuffer; +uniform sampler2D inputSecondLightBuffer; +uniform sampler2D inputColorBuffer; out vec4 fragColor; @@ -17,7 +19,7 @@ void main() { ivec2 texel = ivec2(gl_FragCoord.xy); - if (renderpassType == SCE_PASS_Z) { + if (postProcessType == PASS_POST_DEPTH) { float depth = texelFetch(depthBuffer, texel, 0).r; if (depth == 1.0f) { depth = 1e10; @@ -27,17 +29,15 @@ void main() } fragColor.r = depth; } - - else if (renderpassType == SCE_PASS_AO) { + else if (postProcessType == PASS_POST_AO) { float ao_accum = texelFetch(inputBuffer, texel, 0).r; fragColor = vec4(vec3(min(1.0, ao_accum / currentSample)), 1.0); } - - else if (renderpassType == SCE_PASS_NORMAL) { + else if (postProcessType == PASS_POST_NORMAL) { float depth = texelFetch(depthBuffer, texel, 0).r; vec2 encoded_normal = texelFetch(inputBuffer, texel, 0).rg; - /* decode the normals only when they are valid. otherwise the result buffer will be filled with - * NaN's */ + /* decode the normals only when they are valid. otherwise the result buffer will be filled + * with NaN's */ 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; @@ -47,18 +47,55 @@ void main() fragColor = vec4(0.0, 0.0, 0.0, 1.0); } } - - else if ((renderpassType & ACCUMULATED_VALUE_PASSES) != 0) { + else if (postProcessType == PASS_POST_ACCUMULATED_VALUE) { float accumulated_value = texelFetch(inputBuffer, texel, 0).r; fragColor = vec4(vec3(accumulated_value / currentSample), 1.0); } - - else if ((renderpassType & ACCUMULATED_COLOR_PASSES) != 0) { + else if (postProcessType == PASS_POST_ACCUMULATED_COLOR) { vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb; fragColor = vec4(accumulated_color / currentSample, 1.0); } + else if (postProcessType == PASS_POST_ACCUMULATED_LIGHT) { + vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb; + vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb; + /* Fix INF in the case a color component is 0.0 */ + if (accumulated_color.r == 0.0) { + accumulated_color.r = 1.0; + accumulated_light.r = 0.0; + } + if (accumulated_color.g == 0.0) { + accumulated_color.g = 1.0; + accumulated_light.g = 0.0; + } + if (accumulated_color.b == 0.0) { + accumulated_color.b = 1.0; + accumulated_light.b = 0.0; + } + fragColor = vec4(accumulated_light / accumulated_color, 1.0); + } + 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; + + /* Fix INF in the case a color component is 0.0 */ + if (accumulated_color.r == 0.0) { + accumulated_color.r = 1.0; + accumulated_light.r = 0.0; + } + if (accumulated_color.g == 0.0) { + accumulated_color.g = 1.0; + accumulated_light.g = 0.0; + } + if (accumulated_color.b == 0.0) { + accumulated_color.b = 1.0; + accumulated_light.b = 0.0; + } + fragColor = vec4(accumulated_light / accumulated_color, 1.0); + } else { + /* Output error color: Unknown how to post process this pass. */ fragColor = vec4(1.0, 0.0, 1.0, 1.0); } } diff --git a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl new file mode 100644 index 00000000000..fa02bee45b7 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl @@ -0,0 +1,58 @@ + +out vec4 fragColor; + +#ifndef UTIL_TEX +# define UTIL_TEX +uniform sampler2DArray utilTex; +# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) +#endif /* UTIL_TEX */ + +void main() +{ + if (laNumLight == 0) { + /* Early exit: No lights in scene */ + fragColor.r = 0.0; + return; + } + + ivec2 texel = ivec2(gl_FragCoord.xy); + float depth = texelFetch(depthBuffer, texel, 0).r; + if (depth == 1.0f) { + /* Early exit background does not receive shadows */ + fragColor.r = 1.0; + return; + } + + vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xy; + vec2 uvs = saturate(gl_FragCoord.xy * texel_size); + vec4 rand = texelfetch_noise_tex(texel); + + float accum_light = 0.0; + float tracing_depth = depth; + /* Constant bias (due to depth buffer precision) */ + /* Magic numbers for 24bits of precision. + * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ + tracing_depth -= mix(2.4e-7, 4.8e-7, depth); + /* Convert to view Z. */ + tracing_depth = get_view_z_from_depth(tracing_depth); + + vec3 viewPosition = get_view_space_from_depth(uvs, depth); + vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); + + vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition))); + + for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) { + LightData ld = lights_data[i]; + + vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ + l_vector.xyz = ld.l_position - worldPosition; + l_vector.w = length(l_vector.xyz); + + float l_vis = light_shadowing( + ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, true, 1.0); + + accum_light += l_vis; + } + + fragColor.r = accum_light / float(laNumLight); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_accum_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_accum_frag.glsl new file mode 100644 index 00000000000..1b6a7b33f42 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/volumetric_accum_frag.glsl @@ -0,0 +1,11 @@ + +/* This shader is used to add default values to the volume accum textures. + * so it looks similar (transmittance = 1, scattering = 0) */ +layout(location = 0, index = 0) out vec4 FragColor0; +layout(location = 0, index = 1) out vec4 FragColor1; + +void main() +{ + FragColor0 = vec4(0.0); + FragColor1 = vec4(1.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 4d705a4ee2b..31ac9a2b181 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -138,9 +138,12 @@ void main() facing = clamp(abs(facing), 0.0, 1.0); - vec3 final_front_col = mix(rim_col, wire_col, 0.4); - vec3 final_rim_col = mix(rim_col, wire_col, 0.1); - finalColor = mix(final_rim_col, final_front_col, facing); + /* Do interpolation in a non-linear space to have a better visual result. */ + rim_col = pow(rim_col, vec3(1.0 / 2.2)); + wire_col = pow(wire_col, vec3(1.0 / 2.2)); + vec3 final_front_col = mix(rim_col, wire_col, 0.35); + finalColor = mix(rim_col, final_front_col, facing); + finalColor = pow(finalColor, vec3(2.2)); #endif /* Cull flat edges below threshold. */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 1390567d5af..d003dac7fbf 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -230,8 +230,8 @@ bool ED_screen_change(struct bContext *C, struct bScreen *sc); void ED_screen_scene_change(struct bContext *C, struct wmWindow *win, struct Scene *scene); void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]); void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen); -void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable); -void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh); +void ED_screen_animation_timer(struct bContext *C, int redraws, int sync, int enable); +void ED_screen_animation_timer_update(struct bScreen *screen, int redraws); void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa); ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type); void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa); diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h index c515d501a8d..bbbcaab165a 100644 --- a/source/blender/editors/include/ED_screen_types.h +++ b/source/blender/editors/include/ED_screen_types.h @@ -30,7 +30,6 @@ typedef struct ScreenAnimData { ARegion *ar; /* do not read from this, only for comparing if region exists */ short redraws; - short refresh; short flag; /* flags for playback */ int sfra; /* frame that playback was started from */ int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index fabf6baed23..6739f7cb12c 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -793,7 +793,7 @@ DEF_ICON(BOOKMARKS) DEF_ICON(FONTPREVIEW) DEF_ICON(FILTER) DEF_ICON(NEWFOLDER) -DEF_ICON(FOLDER_REDIRECT) +DEF_ICON_FOLDER(FOLDER_REDIRECT) DEF_ICON(FILE_PARENT) DEF_ICON(FILE_REFRESH) DEF_ICON_FOLDER(FILE_FOLDER) diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 5710be04477..487d0098927 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -735,6 +735,8 @@ bool UI_context_copy_to_selected_list(bContext *C, { *r_use_path_from_id = false; *r_path = NULL; + /* special case for bone constraints */ + char *path_from_bone = NULL; /* PropertyGroup objects don't have a reference to the struct that actually owns * them, so it is normally necessary to do a brute force search to find it. This @@ -797,6 +799,11 @@ bool UI_context_copy_to_selected_list(bContext *C, else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) { *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves"); } + else if (RNA_struct_is_a(ptr->type, &RNA_Constraint) && + (path_from_bone = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone)) != NULL) { + *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); + *r_path = path_from_bone; + } else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { ListBase lb = {NULL, NULL}; char *path = NULL; diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 867ac652505..b72cc7296db 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -554,10 +554,8 @@ static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle) CTX_wm_region_set(C, ctx_ar); /* reset to region cursor (only if there's not another menu open) */ - if (BLI_listbase_is_empty(&sc->regionbase)) { - ED_region_cursor_set(win, ctx_sa, ctx_ar); - /* in case cursor needs to be changed again */ - WM_event_add_mousemove(C); + if ((ctx_sa != NULL) && (BLI_listbase_is_empty(&sc->regionbase))) { + ctx_sa->flag |= AREA_FLAG_CURSOR_UPDATE; } if (handle->scrolltimer) { diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 95bc90c8e5f..8ecaeefbd5f 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -217,13 +217,38 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) View3D *v3d = CTX_wm_view3d(C); bool changed_multi = false; + Object *obact = CTX_data_active_object(C); + const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL; + uint objects_len = 0; Object **objects = object_array_for_shading(C, &objects_len); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; - if (ob->actcol <= 0) { + short mat_nr_active = -1; + + if (ob->totcol == 0) { continue; } + if (obact && (mat_active == BKE_object_material_get(ob, obact->actcol))) { + /* Avoid searching since there may be multiple slots with the same material. + * For the active object or duplicates: match the material slot index first. */ + mat_nr_active = obact->actcol - 1; + } + else { + /* Find the first matching material. + * Note: there may be multiple but that's not a common use case. */ + for (short i = 0; i < ob->totcol; i++) { + const Material *mat = BKE_object_material_get(ob, i + 1); + if (mat_active == mat) { + mat_nr_active = i; + break; + } + } + if (mat_nr_active == -1) { + continue; + } + } + bool changed = false; if (ob->type == OB_MESH) { BMEditMesh *em = BKE_editmesh_from_object(ob); @@ -234,7 +259,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { changed = true; - efa->mat_nr = ob->actcol - 1; + efa->mat_nr = mat_nr_active; } } } @@ -247,7 +272,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) for (nu = nurbs->first; nu; nu = nu->next) { if (ED_curve_nurb_select_check(v3d, nu)) { changed = true; - nu->mat_nr = ob->actcol - 1; + nu->mat_nr = mat_nr_active; } } } @@ -259,7 +284,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) if (ef && BKE_vfont_select_get(ob, &selstart, &selend)) { for (i = selstart; i <= selend; i++) { changed = true; - ef->textbufinfo[i].mat_nr = ob->actcol; + ef->textbufinfo[i].mat_nr = mat_nr_active + 1; } } } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index c9e6cd24ac0..26240482e6d 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1869,15 +1869,21 @@ void ED_region_floating_initialize(ARegion *ar) void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar) { - if (ar && sa && ar->type && ar->type->cursor) { - ar->type->cursor(win, sa, ar); - } - else { - if (WM_cursor_set_from_tool(win, sa, ar)) { + if (ar != NULL) { + if ((ar->gizmo_map != NULL) && WM_gizmomap_cursor_set(ar->gizmo_map, win)) { + return; + } + if (sa && ar->type && ar->type->cursor) { + ar->type->cursor(win, sa, ar); return; } - WM_cursor_set(win, WM_CURSOR_DEFAULT); } + + if (WM_cursor_set_from_tool(win, sa, ar)) { + return; + } + + WM_cursor_set(win, WM_CURSOR_DEFAULT); } /* for use after changing visibility of regions */ diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 1520566cd9d..23a6704a617 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -398,6 +398,15 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) /* ****************** EXPORTED API TO OTHER MODULES *************************** */ /* screen sets cursor based on active region */ +static void region_cursor_set_ex(wmWindow *win, ScrArea *sa, ARegion *ar, bool swin_changed) +{ + BLI_assert(WM_window_get_active_screen(win)->active_region == ar); + if (sa->flag & AREA_FLAG_CURSOR_UPDATE || swin_changed || (ar->type && ar->type->event_cursor)) { + sa->flag &= ~AREA_FLAG_CURSOR_UPDATE; + ED_region_cursor_set(win, sa, ar); + } +} + static void region_cursor_set(wmWindow *win, bool swin_changed) { bScreen *screen = WM_window_get_active_screen(win); @@ -406,14 +415,7 @@ static void region_cursor_set(wmWindow *win, bool swin_changed) { for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { if (ar == screen->active_region) { - if (swin_changed || (ar->type && ar->type->event_cursor)) { - if (ar->gizmo_map != NULL) { - if (WM_gizmomap_cursor_set(ar->gizmo_map, win)) { - return; - } - } - ED_region_cursor_set(win, sa, ar); - } + region_cursor_set_ex(win, sa, ar, swin_changed); return; } } @@ -672,97 +674,98 @@ static void screen_cursor_set(wmWindow *win, const int xy[2]) } } -/* called in wm_event_system.c. sets state vars in screen, cursors */ -/* event type is mouse move */ +/** + * Called in wm_event_system.c. sets state vars in screen, cursors. + * event type is mouse move. + */ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2]) { bScreen *scr = WM_window_get_active_screen(win); + if (scr == NULL) { + return; + } - if (scr) { - ScrArea *sa = NULL; - ARegion *ar; - ARegion *old_ar = scr->active_region; + ScrArea *sa = NULL; + ARegion *ar; + ARegion *old_ar = scr->active_region; - ED_screen_areas_iter(win, scr, area_iter) - { - if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) { - if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) { - if (ED_area_azones_update(area_iter, xy) == NULL) { - sa = area_iter; - break; - } - } - } - } - if (sa) { - /* make overlap active when mouse over */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ED_region_contains_xy(ar, xy)) { - scr->active_region = ar; + ED_screen_areas_iter(win, scr, area_iter) + { + if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) { + if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) { + if (ED_area_azones_update(area_iter, xy) == NULL) { + sa = area_iter; break; } } } - else { - scr->active_region = NULL; + } + if (sa) { + /* Make overlap active when mouse over. */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ED_region_contains_xy(ar, xy)) { + scr->active_region = ar; + break; + } } + } + else { + scr->active_region = NULL; + } - /* check for redraw headers */ - if (old_ar != scr->active_region) { + /* Check for redraw headers. */ + if (old_ar != scr->active_region) { - ED_screen_areas_iter(win, scr, area_iter) - { - bool do_draw = false; + ED_screen_areas_iter(win, scr, area_iter) + { + bool do_draw = false; - for (ar = area_iter->regionbase.first; ar; ar = ar->next) { + for (ar = area_iter->regionbase.first; ar; ar = ar->next) { - /* call old area's deactivate if assigned */ - if (ar == old_ar && area_iter->type->deactivate) { - area_iter->type->deactivate(area_iter); - } + /* Call old area's deactivate if assigned. */ + if (ar == old_ar && area_iter->type->deactivate) { + area_iter->type->deactivate(area_iter); + } - if (ar == old_ar && ar != scr->active_region) { - wmGizmoMap *gzmap = old_ar->gizmo_map; - if (gzmap) { - if (WM_gizmo_highlight_set(gzmap, NULL)) { - ED_region_tag_redraw_no_rebuild(old_ar); - } + if (ar == old_ar && ar != scr->active_region) { + wmGizmoMap *gzmap = old_ar->gizmo_map; + if (gzmap) { + if (WM_gizmo_highlight_set(gzmap, NULL)) { + ED_region_tag_redraw_no_rebuild(old_ar); } } + } - if (ar == old_ar || ar == scr->active_region) { - do_draw = true; - } + if (ar == old_ar || ar == scr->active_region) { + do_draw = true; } + } - if (do_draw) { - for (ar = area_iter->regionbase.first; ar; ar = ar->next) { - if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { - ED_region_tag_redraw_no_rebuild(ar); - } + if (do_draw) { + for (ar = area_iter->regionbase.first; ar; ar = ar->next) { + if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { + ED_region_tag_redraw_no_rebuild(ar); } } } } + } - /* cursors, for time being set always on edges, otherwise aregion doesn't switch */ - if (scr->active_region == NULL) { - screen_cursor_set(win, xy); - } - else { - /* notifier invokes freeing the buttons... causing a bit too much redraws */ - if (old_ar != scr->active_region) { - region_cursor_set(win, true); + /* Cursors, for time being set always on edges, + * otherwise the active region doesn't switch. */ + if (scr->active_region == NULL) { + screen_cursor_set(win, xy); + } + else { + /* Notifier invokes freeing the buttons... causing a bit too much redraws. */ + region_cursor_set_ex(win, sa, scr->active_region, old_ar != scr->active_region); - /* this used to be a notifier, but needs to be done immediate - * because it can undo setting the right button as active due - * to delayed notifier handling */ - if (C) { - UI_screen_free_active_but(C, scr); - } - } - else { - region_cursor_set(win, false); + if (old_ar != scr->active_region) { + /* This used to be a notifier, but needs to be done immediate + * because it can undo setting the right button as active due + * to delayed notifier handling. */ + if (C) { + UI_screen_free_active_but(C, scr); } } } @@ -1441,7 +1444,7 @@ void ED_refresh_viewport_fps(bContext *C) /* redraws: uses defines from stime->redraws * enable: 1 - forward on, -1 - backwards on, 0 - off */ -void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync, int enable) +void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable) { bScreen *screen = CTX_wm_screen(C); wmWindowManager *wm = CTX_wm_manager(C); @@ -1481,7 +1484,6 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync, } } sad->redraws = redraws; - sad->refresh = refresh; sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0; sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0; @@ -1526,14 +1528,13 @@ static ARegion *time_top_left_3dwindow(bScreen *screen) return aret; } -void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh) +void ED_screen_animation_timer_update(bScreen *screen, int redraws) { if (screen && screen->animtimer) { wmTimer *wt = screen->animtimer; ScreenAnimData *sad = wt->customdata; sad->redraws = redraws; - sad->refresh = refresh; sad->ar = NULL; if (redraws & TIME_REGION) { sad->ar = time_top_left_3dwindow(screen); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index bd7475dc1a2..35d84d5d75e 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4616,20 +4616,18 @@ int ED_screen_animation_play(bContext *C, int sync, int mode) if (ED_screen_animation_playing(CTX_wm_manager(C))) { /* stop playback now */ - ED_screen_animation_timer(C, 0, 0, 0, 0); + ED_screen_animation_timer(C, 0, 0, 0); BKE_sound_stop_scene(scene_eval); WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); } else { /* these settings are currently only available from a menu in the TimeLine */ - int refresh = SPACE_ACTION; - if (mode == 1) { /* XXX only play audio forwards!? */ BKE_sound_play_scene(scene_eval); } - ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode); + ED_screen_animation_timer(C, screen->redraws_flag, sync, mode); if (screen->animtimer) { wmTimer *wt = screen->animtimer; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 0aec6d5e6a0..1739c15cbc6 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -133,8 +133,15 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh true, (float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color); } -static void file_draw_icon( - uiBlock *block, const char *path, int sx, int sy, int icon, int width, int height, bool drag) +static void file_draw_icon(uiBlock *block, + const char *path, + int sx, + int sy, + int icon, + int width, + int height, + bool drag, + bool dimmed) { uiBut *but; int x, y; @@ -142,8 +149,11 @@ static void file_draw_icon( x = sx; y = sy - height; + /* For uiDefIconBut(), if a1==1.0 then a2 is alpha 0.0 - 1.0 */ + const float a1 = dimmed ? 1.0f : 0.0f; + const float a2 = dimmed ? 0.3f : 0.0f; but = uiDefIconBut( - block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL); + block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, a1, a2, NULL); UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); if (drag) { @@ -210,7 +220,8 @@ static void file_draw_preview(uiBlock *block, FileLayout *layout, const bool is_icon, const int typeflags, - const bool drag) + const bool drag, + const bool dimmed) { uiBut *but; float fx, fy; @@ -273,6 +284,10 @@ static void file_draw_preview(uiBlock *block, UI_GetThemeColor4fv(TH_TEXT, col); } + if (dimmed) { + col[3] *= 0.3f; + } + if (!is_icon && typeflags & FILE_TYPE_BLENDERLIB) { /* Datablock preview images use premultiplied alpha. */ GPU_blend_set_func_separate( @@ -775,6 +790,7 @@ void file_draw_list(const bContext *C, ARegion *ar) /* don't drag parent or refresh items */ do_drag = !(FILENAME_IS_CURRPAR(file->relpath)); + const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN); if (FILE_IMGDISPLAY == params->display) { const int icon = filelist_geticon(files, i, false); @@ -795,7 +811,8 @@ void file_draw_list(const bContext *C, ARegion *ar) layout, is_icon, file->typeflag, - do_drag); + do_drag, + is_hidden); } else { file_draw_icon(block, @@ -805,7 +822,8 @@ void file_draw_list(const bContext *C, ARegion *ar) filelist_geticon(files, i, true), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, - do_drag); + do_drag, + is_hidden); icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index b328b32263c..28e6d95beb3 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -213,6 +213,9 @@ typedef struct FileListInternEntry { /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ char *name; + /** Defined in BLI_fileops.h */ + eFileAttributes attributes; + BLI_stat_t st; } FileListInternEntry; @@ -609,54 +612,76 @@ void filelist_setsorting(struct FileList *filelist, const short sort, bool inver /* ********** Filter helpers ********** */ -static bool is_hidden_file(const char *filename, FileListFilter *filter) +/* True if filename is meant to be hidden, eg. starting with period. */ +static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *file) { - char *sep = (char *)BLI_last_slash(filename); - bool is_hidden = false; - - if (filter->flags & FLF_HIDE_DOT) { - if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') { - is_hidden = true; /* ignore .file */ - } - else { - int len = strlen(filename); - if ((len > 0) && (filename[len - 1] == '~')) { - is_hidden = true; /* ignore file~ */ - } - } + if (filename[0] == '.' && !ELEM(filename[1], '.', '\0')) { + return true; /* ignore .file */ } - if (!is_hidden && (filter->flags & FLF_HIDE_PARENT)) { - if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { - is_hidden = true; /* ignore .. */ + else { + int len = strlen(filename); + if ((len > 0) && (filename[len - 1] == '~')) { + return true; /* ignore file~ */ } } - if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) { - is_hidden = true; /* ignore . */ - } + /* filename might actually be a piece of path, in which case we have to check all its parts. */ - if (!is_hidden && sep) { + + bool hidden = false; + char *sep = (char *)BLI_last_slash(filename); + + if (!hidden && sep) { char tmp_filename[FILE_MAX_LIBEXTRA]; BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename)); sep = tmp_filename + (sep - filename); while (sep) { BLI_assert(sep[1] != '\0'); - if (is_hidden_file(sep + 1, filter)) { - is_hidden = true; + if (is_hidden_dot_filename(sep + 1, file)) { + hidden = true; break; } *sep = '\0'; sep = (char *)BLI_last_slash(tmp_filename); } } - return is_hidden; + return hidden; +} + +/* True if should be hidden, based on current filtering. */ +static bool is_filtered_hidden(const char *filename, + FileListFilter *filter, + FileListInternEntry *file) +{ + if ((filename[0] == '.') && (filename[1] == '\0')) { + return true; /* Ignore . */ + } + + if (filter->flags & FLF_HIDE_PARENT) { + if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { + return true; /* Ignore .. */ + } + } + + if ((filter->flags & FLF_HIDE_DOT) && (file->attributes & FILE_ATTR_HIDDEN)) { + return true; /* Ignore files with Hidden attribute. */ + } + +#ifndef WIN32 + /* Check for unix-style names starting with period. */ + if ((filter->flags & FLF_HIDE_DOT) && is_hidden_dot_filename(filename, file)) { + return true; + } +#endif + + return false; } static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root), FileListFilter *filter) { - bool is_filtered = !is_hidden_file(file->relpath, filter); + bool is_filtered = !is_filtered_hidden(file->relpath, filter, file); if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { /* We only check for types if some type are enabled in filtering. */ @@ -699,7 +724,7 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis BLI_join_dirfile(path, sizeof(path), root, file->relpath); if (BLO_library_path_explode(path, dir, &group, &name)) { - is_filtered = !is_hidden_file(file->relpath, filter); + is_filtered = !is_filtered_hidden(file->relpath, filter, file); if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { /* We only check for types if some type are enabled in filtering. */ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { @@ -747,7 +772,7 @@ static bool is_filtered_main(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter) { - return !is_hidden_file(file->relpath, filter); + return !is_filtered_hidden(file->relpath, filter, file); } static void filelist_filter_clear(FileList *filelist) @@ -968,7 +993,7 @@ static int filelist_geticon_ex(FileDirEntry *file, else if (is_main) { /* Do not return icon for folders if icons are not 'main' draw type * (e.g. when used over previews). */ - return ICON_FILE_FOLDER; + return (file->attributes & FILE_ATTR_ANY_LINK) ? ICON_FOLDER_REDIRECT : ICON_FILE_FOLDER; } else { /* If this path is in System list then use that icon. */ @@ -984,6 +1009,19 @@ static int filelist_geticon_ex(FileDirEntry *file, } } } + + if (file->attributes & FILE_ATTR_ANY_LINK) { + return ICON_LOOP_FORWARDS; + } + else if (file->attributes & FILE_ATTR_OFFLINE) { + return ICON_ERROR; + } + else if (file->attributes & FILE_ATTR_TEMPORARY) { + return ICON_FILE_CACHE; + } + else if (file->attributes & FILE_ATTR_SYSTEM) { + return ICON_SYSTEM; + } } if (typeflag & FILE_TYPE_BLENDER) { @@ -1621,7 +1659,7 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid)); ret->blentype = entry->blentype; ret->typeflag = entry->typeflag; - + ret->attributes = entry->attributes; BLI_addtail(&cache->cached_entries, ret); return ret; } @@ -2401,6 +2439,7 @@ static int filelist_readjob_list_dir(const char *root, { struct direntry *files; int nbr_files, nbr_entries = 0; + char path[FILE_MAX]; nbr_files = BLI_filelist_dir_contents(root, &files); if (files) { @@ -2416,20 +2455,17 @@ static int filelist_readjob_list_dir(const char *root, entry->relpath = MEM_dupallocN(files[i].relname); entry->st = files[i].s; + BLI_join_dirfile(path, sizeof(path), root, entry->relpath); + /* Set file type. */ if (S_ISDIR(files[i].s.st_mode)) { entry->typeflag = FILE_TYPE_DIR; } else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { /* If we are considering .blend files as libs, promote them to directory status. */ - char name[FILE_MAX]; - entry->typeflag = FILE_TYPE_BLENDER; - - BLI_join_dirfile(name, sizeof(name), root, entry->relpath); - /* prevent current file being used as acceptable dir */ - if (BLI_path_cmp(main_name, name) != 0) { + if (BLI_path_cmp(main_name, path) != 0) { entry->typeflag |= FILE_TYPE_DIR; } } @@ -2441,6 +2477,16 @@ static int filelist_readjob_list_dir(const char *root, } } + /* Set file attributes. */ + entry->attributes = BLI_file_attributes(path); + +#ifndef WIN32 + /* Set linux-style dot files hidden too. */ + if (is_hidden_dot_filename(entry->relpath, entry)) { + entry->attributes |= FILE_ATTR_HIDDEN; + } +#endif + BLI_addtail(entries, entry); nbr_entries++; } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 858096f9a6d..bc81817647e 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -25,7 +25,6 @@ #include "MEM_guardedalloc.h" -#include "DNA_armature_types.h" #include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_mesh_types.h" @@ -917,7 +916,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initTranslation(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; @@ -935,21 +934,20 @@ int transformEvent(TransInfo *t, const wmEvent *event) resetTransRestrictions(t); /* first try edge slide */ - initEdgeSlide(t); + transform_mode_init(t, NULL, TFM_EDGE_SLIDE); /* if that fails, do vertex slide */ if (t->state == TRANS_CANCEL) { resetTransModal(t); t->state = TRANS_STARTING; - initVertSlide(t); + transform_mode_init(t, NULL, TFM_VERT_SLIDE); } /* vert slide can fail on unconnected vertices (rare but possible) */ if (t->state == TRANS_CANCEL) { resetTransModal(t); - t->mode = TFM_TRANSLATION; t->state = TRANS_STARTING; restoreTransObjects(t); resetTransRestrictions(t); - initTranslation(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); } initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; @@ -982,10 +980,10 @@ int transformEvent(TransInfo *t, const wmEvent *event) resetTransRestrictions(t); if (t->mode == TFM_ROTATION) { - initTrackball(t); + transform_mode_init(t, NULL, TFM_TRACKBALL); } else { - initRotation(t); + transform_mode_init(t, NULL, TFM_ROTATION); } initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; @@ -1010,7 +1008,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initResize(t); + transform_mode_init(t, NULL, TFM_RESIZE); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; @@ -1214,7 +1212,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) } else if (t->mode == TFM_ROTATION) { restoreTransObjects(t); - initTrackball(t); + transform_mode_init(t, NULL, TFM_TRACKBALL); } } else { @@ -1256,7 +1254,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initTranslation(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; @@ -1268,7 +1266,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initResize(t); + transform_mode_init(t, NULL, TFM_RESIZE); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; @@ -1283,10 +1281,10 @@ int transformEvent(TransInfo *t, const wmEvent *event) resetTransRestrictions(t); if (t->mode == TFM_ROTATION) { - initTrackball(t); + transform_mode_init(t, NULL, TFM_TRACKBALL); } else { - initRotation(t); + transform_mode_init(t, NULL, TFM_ROTATION); } initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; @@ -1368,7 +1366,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initNormalRotation(t); + transform_mode_init(t, NULL, TFM_NORMAL_ROTATION); t->redraw = TREDRAW_HARD; handled = true; } @@ -2113,145 +2111,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate); } - switch (mode) { - case TFM_TRANSLATION: - initTranslation(t); - break; - case TFM_ROTATION: - initRotation(t); - break; - case TFM_RESIZE: - initResize(t); - break; - case TFM_SKIN_RESIZE: - initSkinResize(t); - break; - case TFM_TOSPHERE: - initToSphere(t); - break; - case TFM_SHEAR: - initShear(t); - break; - case TFM_BEND: - initBend(t); - break; - case TFM_SHRINKFATTEN: - initShrinkFatten(t); - break; - case TFM_TILT: - initTilt(t); - break; - case TFM_CURVE_SHRINKFATTEN: - initCurveShrinkFatten(t); - break; - case TFM_MASK_SHRINKFATTEN: - initMaskShrinkFatten(t); - break; - case TFM_GPENCIL_SHRINKFATTEN: - initGPShrinkFatten(t); - break; - case TFM_TRACKBALL: - initTrackball(t); - break; - case TFM_PUSHPULL: - initPushPull(t); - break; - case TFM_CREASE: - initCrease(t); - break; - case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ - /* Note: we have to pick one, use the active object. */ - TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); - bArmature *arm = tc->poseobj->data; - if (arm->drawtype == ARM_ENVELOPE) { - initBoneEnvelope(t); - t->mode = TFM_BONE_ENVELOPE_DIST; - } - else { - initBoneSize(t); - } - break; - } - case TFM_BONE_ENVELOPE: - initBoneEnvelope(t); - break; - case TFM_BONE_ENVELOPE_DIST: - initBoneEnvelope(t); - t->mode = TFM_BONE_ENVELOPE_DIST; - break; - case TFM_EDGE_SLIDE: - case TFM_VERT_SLIDE: { - const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false); - const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false); - const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true); - if (mode == TFM_EDGE_SLIDE) { - const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true); - initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp); - } - else { - initVertSlide_ex(t, use_even, flipped, use_clamp); - } - break; - } - case TFM_BONE_ROLL: - initBoneRoll(t); - break; - case TFM_TIME_TRANSLATE: - initTimeTranslate(t); - break; - case TFM_TIME_SLIDE: - initTimeSlide(t); - break; - case TFM_TIME_SCALE: - initTimeScale(t); - break; - case TFM_TIME_DUPLICATE: - /* same as TFM_TIME_EXTEND, but we need the mode info for later - * so that duplicate-culling will work properly - */ - if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { - initTranslation(t); - } - else { - initTimeTranslate(t); - } - t->mode = mode; - break; - case TFM_TIME_EXTEND: - /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation - * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION - * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement) - * depending on which editor this was called from - */ - if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { - initTranslation(t); - } - else { - initTimeTranslate(t); - } - break; - case TFM_BAKE_TIME: - initBakeTime(t); - break; - case TFM_MIRROR: - initMirror(t); - break; - case TFM_BWEIGHT: - initBevelWeight(t); - break; - case TFM_ALIGN: - initAlign(t); - break; - case TFM_SEQ_SLIDE: - initSeqSlide(t); - break; - case TFM_NORMAL_ROTATION: - initNormalRotation(t); - break; - case TFM_GPENCIL_OPACITY: - initGPOpacity(t); - break; - } + transform_mode_init(t, op, mode); if (t->state == TRANS_CANCEL) { postTrans(C, t); diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 5d3d1d936a2..3d9a04c060b 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1030,7 +1030,15 @@ static void create_trans_vert_customdata_layer(BMVert *v, void trans_mesh_customdata_correction_init(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BLI_assert(tc->custom.type.data == NULL); + if (tc->custom.type.data) { + if (tc->custom.type.free_cb == trans_mesh_customdata_free_cb) { + /* Custom data correction has initiated before. */ + continue; + } + else { + BLI_assert(false); + } + } int i; BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 00f34a20cb6..c925f5c9a8e 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1374,13 +1374,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve bGPdata *gpd = CTX_data_gpencil_data(C); PropertyRNA *prop; - if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && - RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_get_array(op->ptr, prop, t->center_global); - mul_v3_v3(t->center_global, t->aspect); - t->flag |= T_OVERRIDE_CENTER; - } - if (op && (prop = RNA_struct_find_property(op->ptr, "mouse_coordinate_override")) && RNA_property_is_set(op->ptr, prop)) { RNA_property_int_get_array(op->ptr, prop, t->mval); @@ -1640,7 +1633,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) { RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix[0][0]); copy_m3_m3(t->spacemtx, t->orient_matrix); - negate_m3(t->spacemtx); /* Some transform modes use this to operate on an axis. */ t->orient_matrix_is_set = true; t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX; @@ -1780,6 +1772,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve setTransformViewAspect(t, t->aspect); + if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && + RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, t->center_global); + mul_v3_v3(t->center_global, t->aspect); + t->flag |= T_OVERRIDE_CENTER; + } + setTransformViewMatrices(t); initNumInput(&t->num); } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index e681b649451..cdd29ccf24f 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -24,8 +24,10 @@ #include <stdlib.h> #include "DNA_anim_types.h" +#include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_windowmanager_types.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -35,6 +37,8 @@ #include "BKE_context.h" #include "BKE_nla.h" +#include "RNA_access.h" + #include "ED_screen.h" #include "UI_interface.h" @@ -484,7 +488,7 @@ static void constraintSizeLim(TransInfo *t, TransData *td) } /* -------------------------------------------------------------------- */ -/* Transform (Rotaion Utils) */ +/* Transform (Rotation Utils) */ /** \name Transform Rotaion Utils * \{ */ @@ -1098,3 +1102,159 @@ void doAnimEdit_SnapFrame( } } /** \} */ + +/* -------------------------------------------------------------------- */ +/* Transform Mode API */ + +/** \name Transform Frame Utils + * \{ */ + +void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) +{ + t->mode = mode; + + switch (mode) { + case TFM_TRANSLATION: + initTranslation(t); + break; + case TFM_ROTATION: + initRotation(t); + break; + case TFM_RESIZE: + initResize(t); + break; + case TFM_SKIN_RESIZE: + initSkinResize(t); + break; + case TFM_TOSPHERE: + initToSphere(t); + break; + case TFM_SHEAR: + initShear(t); + break; + case TFM_BEND: + initBend(t); + break; + case TFM_SHRINKFATTEN: + initShrinkFatten(t); + break; + case TFM_TILT: + initTilt(t); + break; + case TFM_CURVE_SHRINKFATTEN: + initCurveShrinkFatten(t); + break; + case TFM_MASK_SHRINKFATTEN: + initMaskShrinkFatten(t); + break; + case TFM_GPENCIL_SHRINKFATTEN: + initGPShrinkFatten(t); + break; + case TFM_TRACKBALL: + initTrackball(t); + break; + case TFM_PUSHPULL: + initPushPull(t); + break; + case TFM_CREASE: + initCrease(t); + break; + case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ + /* Note: we have to pick one, use the active object. */ + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); + bArmature *arm = tc->poseobj->data; + if (arm->drawtype == ARM_ENVELOPE) { + initBoneEnvelope(t); + t->mode = TFM_BONE_ENVELOPE_DIST; + } + else { + initBoneSize(t); + } + break; + } + case TFM_BONE_ENVELOPE: + initBoneEnvelope(t); + break; + case TFM_BONE_ENVELOPE_DIST: + initBoneEnvelope(t); + t->mode = TFM_BONE_ENVELOPE_DIST; + break; + case TFM_EDGE_SLIDE: + case TFM_VERT_SLIDE: { + const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false); + const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false); + const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true); + if (mode == TFM_EDGE_SLIDE) { + const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true); + initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp); + } + else { + initVertSlide_ex(t, use_even, flipped, use_clamp); + } + break; + } + case TFM_BONE_ROLL: + initBoneRoll(t); + break; + case TFM_TIME_TRANSLATE: + initTimeTranslate(t); + break; + case TFM_TIME_SLIDE: + initTimeSlide(t); + break; + case TFM_TIME_SCALE: + initTimeScale(t); + break; + case TFM_TIME_DUPLICATE: + /* same as TFM_TIME_EXTEND, but we need the mode info for later + * so that duplicate-culling will work properly + */ + if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { + initTranslation(t); + } + else { + initTimeTranslate(t); + } + break; + case TFM_TIME_EXTEND: + /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation + * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION + * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement) + * depending on which editor this was called from + */ + if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { + initTranslation(t); + } + else { + initTimeTranslate(t); + } + break; + case TFM_BAKE_TIME: + initBakeTime(t); + break; + case TFM_MIRROR: + initMirror(t); + break; + case TFM_BWEIGHT: + initBevelWeight(t); + break; + case TFM_ALIGN: + initAlign(t); + break; + case TFM_SEQ_SLIDE: + initSeqSlide(t); + break; + case TFM_NORMAL_ROTATION: + initNormalRotation(t); + break; + case TFM_GPENCIL_OPACITY: + initGPOpacity(t); + break; + } + + /* TODO(germano): Some of these operations change the `t->mode`. + * This can be bad for Redo. + * BLI_assert(t->mode == mode); */ +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index bb036a69a88..a8a930cc156 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -30,6 +30,7 @@ struct LinkNode; struct TransInfo; struct TransDataContainer; struct TransData; +struct wmOperator; /* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */ typedef struct TransDataGenericSlideVert { @@ -56,6 +57,7 @@ void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float ma short getAnimEdit_SnapMode(TransInfo *t); void doAnimEdit_SnapFrame( TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap); +void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode); /* transform_mode_align.c */ void initAlign(TransInfo *t); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 1952a2c862e..ea4f1eedd81 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -512,11 +512,11 @@ void initTransformOrientation(bContext *C, TransInfo *t) t->orientation.unset = V3D_ORIENT_VIEW; copy_m3_m4(t->orient_matrix, t->viewinv); normalize_m3(t->orient_matrix); + negate_m3(t->orient_matrix); } else { copy_m3_m3(t->orient_matrix, t->spacemtx); } - negate_m3(t->orient_matrix); } } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl index e029905a908..714792489f6 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl @@ -4,8 +4,8 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result) N = normalize(N); result = CLOSURE_DEFAULT; eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance); + result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb); closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result); - result.radiance *= color.rgb; } #else /* Stub diffuse because it is not compatible with volumetrics. */ diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl index 34062cc8d02..747395857ee 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl @@ -32,7 +32,9 @@ void node_eevee_specular(vec4 diffuse, float alpha = 1.0 - transp; result = CLOSURE_DEFAULT; - result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb; + result.radiance = render_pass_diffuse_mask(diffuse.rgb, out_diff * diffuse.rgb); + result.radiance += render_pass_glossy_mask(vec3(1.0), out_spec); + result.radiance += render_pass_emission_mask(emissive.rgb); result.radiance *= alpha; result.transmittance = vec3(transp); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl index 092b9ed08bb..502bc7f92d6 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl @@ -2,7 +2,7 @@ void node_emission(vec4 color, float strength, vec3 vN, out Closure result) { result = CLOSURE_DEFAULT; #ifndef VOLUMETRICS - result.radiance = color.rgb * strength; + result.radiance = render_pass_emission_mask(color.rgb) * strength; result.ssr_normal = normal_encode(vN, viewCameraVec); #else result.emission = color.rgb * strength; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl index 5038cb3892f..ece770f0e73 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl @@ -17,12 +17,12 @@ void node_bsdf_glass( out_spec, out_refr, ssr_spec); - out_refr *= refr_color; - out_spec *= color.rgb; float fresnel = F_eta(ior, dot(N, cameraVec)); vec3 vN = mat3(ViewMatrix) * N; result = CLOSURE_DEFAULT; - result.radiance = mix(out_refr, out_spec, fresnel); + result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color) * (1.0 - fresnel); + result.radiance += render_pass_glossy_mask(color.rgb, out_spec * color.rgb) * fresnel; + closure_load_ssr_data( ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl index 75cc2e770c5..7513c3a4edb 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl @@ -7,7 +7,7 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec); vec3 vN = mat3(ViewMatrix) * N; result = CLOSURE_DEFAULT; - result.radiance = out_spec * color.rgb; + result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) * color.rgb; closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result); } #else diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index 7af409dd410..3c85dc6456c 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -18,15 +18,22 @@ void convert_metallic_to_specular_tinted(vec3 basecol, diffuse = basecol * (1.0 - metallic); } -vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint) +/* Output sheen is to be multiplied by sheen_color. */ +void principled_sheen(float NV, + vec3 basecol_tint, + float sheen, + float sheen_tint, + out float out_sheen, + out vec3 sheen_color) { float f = 1.0 - NV; /* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps, * therefore we need to clamp value. */ f = clamp(f, 0.0, 1.0); /* Empirical approximation (manual curve fitting). Can be refined. */ - float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026; - return sheen * mix(vec3(1.0), basecol_tint, sheen_tint); + out_sheen = f * f * f * 0.077 + f * 0.01 + 0.00026; + + sheen_color = sheen * mix(vec3(1.0), basecol_tint, sheen_tint); } void node_bsdf_principled(vec4 base_color, @@ -61,18 +68,23 @@ void node_bsdf_principled(vec4 base_color, ior = max(ior, 1e-5); metallic = saturate(metallic); transmission = saturate(transmission); + float m_transmission = 1.0 - transmission; + float dielectric = 1.0 - metallic; transmission *= dielectric; sheen *= dielectric; subsurface_color *= dielectric; - vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec; + vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec, sheen_color; + float out_sheen; vec3 ctint = tint_from_color(base_color.rgb); convert_metallic_to_specular_tinted( base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0); float NV = dot(N, cameraVec); - vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint); + principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color); + + vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic); /* Far from being accurate, but 2 glossy evaluation is too expensive. * Most noticeable difference is at grazing angles since the bsdf lut @@ -81,8 +93,12 @@ void node_bsdf_principled(vec4 base_color, float fresnel = F_eta(ior, NV); vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel; f0 = mix(f0, spec_col, transmission); + f90 = mix(f90, spec_col, transmission); - vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic); + /* Really poor approximation but needed to workaround issues with renderpasses. */ + spec_col = mix(vec3(1.0), spec_col, transmission); + /* Match cycles. */ + spec_col += float(clearcoat > 1e-5); vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface); @@ -108,19 +124,22 @@ void node_bsdf_principled(vec4 base_color, vec3 refr_color = base_color.rgb; refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission event */ - out_refr *= refr_color * (1.0 - fresnel) * transmission; + refr_color *= saturate(1.0 - fresnel) * transmission; + + sheen_color *= m_transmission; + mixed_ss_base_color *= m_transmission; result = CLOSURE_DEFAULT; - result.radiance = out_spec + out_refr; - result.radiance += out_diff * out_sheen; /* Coarse approx. */ - result.radiance += emission.rgb; + result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color); + result.radiance += render_pass_glossy_mask(spec_col, out_spec); + /* Coarse approx. */ + result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color); + result.radiance += render_pass_emission_mask(emission.rgb); result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); - mixed_ss_base_color *= alpha * (1.0 - transmission); + mixed_ss_base_color *= alpha; closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); - result.transmittance = vec3(1.0 - alpha); } @@ -156,22 +175,26 @@ void node_bsdf_principled_dielectric(vec4 base_color, metallic = saturate(metallic); float dielectric = 1.0 - metallic; - vec3 diffuse, f0, out_diff, out_spec, ssr_spec; + vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color; + float out_sheen; vec3 ctint = tint_from_color(base_color.rgb); convert_metallic_to_specular_tinted( base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0); + vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic); + float NV = dot(N, cameraVec); - vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint); + principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color); eevee_closure_default( - N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, true, out_diff, out_spec, ssr_spec); + N, diffuse, f0, f90, int(ssr_id), roughness, 1.0, true, out_diff, out_spec, ssr_spec); result = CLOSURE_DEFAULT; - result.radiance = out_spec + out_diff * (diffuse + out_sheen); - result.radiance += emission.rgb; + result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); + result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color); + result.radiance += render_pass_diffuse_mask(diffuse, out_diff * diffuse); + result.radiance += render_pass_emission_mask(emission.rgb); result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.transmittance = vec3(1.0 - alpha); @@ -214,10 +237,9 @@ void node_bsdf_principled_metallic(vec4 base_color, N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec); result = CLOSURE_DEFAULT; - result.radiance = out_spec; - result.radiance += emission.rgb; + result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); + result.radiance += render_pass_emission_mask(emission.rgb); result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.transmittance = vec3(1.0 - alpha); @@ -268,10 +290,12 @@ void node_bsdf_principled_clearcoat(vec4 base_color, true, out_spec, ssr_spec); + /* Match cycles. */ + float spec_col = 1.0 + float(clearcoat > 1e-5); result = CLOSURE_DEFAULT; - result.radiance = out_spec; - result.radiance += emission.rgb; + result.radiance = render_pass_glossy_mask(vec3(spec_col), out_spec); + result.radiance += render_pass_emission_mask(emission.rgb); result.radiance *= alpha; closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); @@ -310,7 +334,8 @@ void node_bsdf_principled_subsurface(vec4 base_color, metallic = saturate(metallic); N = normalize(N); - vec3 diffuse, f0, out_diff, out_spec, ssr_spec; + vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color; + float out_sheen; vec3 ctint = tint_from_color(base_color.rgb); convert_metallic_to_specular_tinted( base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0); @@ -320,7 +345,7 @@ void node_bsdf_principled_subsurface(vec4 base_color, float sss_scalef = avg(sss_scale) * subsurface; float NV = dot(N, cameraVec); - vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint); + principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color); vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic); @@ -338,14 +363,14 @@ void node_bsdf_principled_subsurface(vec4 base_color, ssr_spec); result = CLOSURE_DEFAULT; - result.radiance = out_spec; - result.radiance += out_diff * out_sheen; - result.radiance += emission.rgb; + result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); + result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color); + result.radiance += render_pass_emission_mask(emission.rgb); result.radiance *= alpha; closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); - mixed_ss_base_color *= alpha * (1.0 - transmission); + mixed_ss_base_color *= alpha; closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); result.transmittance = vec3(1.0 - alpha); @@ -400,16 +425,18 @@ void node_bsdf_principled_glass(vec4 base_color, vec3 refr_color = base_color.rgb; refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission events */ - out_refr *= refr_color; float fresnel = F_eta(ior, dot(N, cameraVec)); vec3 spec_col = F_color_blend(ior, fresnel, f0); - out_spec *= spec_col; - ssr_spec *= spec_col * fresnel; + spec_col *= fresnel; + refr_color *= (1.0 - fresnel); + + ssr_spec *= spec_col; result = CLOSURE_DEFAULT; - result.radiance = mix(out_refr, out_spec, fresnel); - result.radiance += emission.rgb; + result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color); + result.radiance += render_pass_glossy_mask(spec_col, out_spec * spec_col); + result.radiance += render_pass_emission_mask(emission.rgb); result.radiance *= alpha; closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.transmittance = vec3(1.0 - alpha); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl index 906964e1539..4088d6db06a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl @@ -8,7 +8,7 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl vec3 vN = mat3(ViewMatrix) * N; result = CLOSURE_DEFAULT; result.ssr_normal = normal_encode(vN, viewCameraVec); - result.radiance = out_refr * color.rgb; + result.radiance = render_pass_glossy_mask(color.rgb, out_refr * color.rgb); } #else /* Stub refraction because it is not compatible with volumetrics. */ diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl index 241228c0d4c..9bbbe71b206 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl @@ -19,6 +19,7 @@ void node_subsurface_scattering(vec4 color, /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */ vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur); out_diff *= mix(vec3(1.0), color.rgb, texture_blur); + result.radiance = render_pass_sss_mask(sss_albedo); closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result); } #else diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl index 749b3a4c11f..5c3ed81410a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl @@ -5,7 +5,7 @@ void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) result = CLOSURE_DEFAULT; eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance); closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result); - result.radiance *= color.rgb; + result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb); } #else /* Stub translucent because it is not compatible with volumetrics. */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 5480bed51e8..09d02e9a375 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -28,6 +28,26 @@ extern "C" { #include "DNA_freestyle_types.h" #include "DNA_listBase.h" +/* Renderpasses for EEVEE. + * ViewLayerEEVEE.render_passes */ +typedef enum eViewLayerEEVEEPassType { + EEVEE_RENDER_PASS_COMBINED = (1 << 0), + EEVEE_RENDER_PASS_Z = (1 << 1), + EEVEE_RENDER_PASS_MIST = (1 << 2), + EEVEE_RENDER_PASS_NORMAL = (1 << 3), + EEVEE_RENDER_PASS_DIFFUSE_LIGHT = (1 << 4), + EEVEE_RENDER_PASS_DIFFUSE_COLOR = (1 << 5), + EEVEE_RENDER_PASS_SPECULAR_LIGHT = (1 << 6), + EEVEE_RENDER_PASS_SPECULAR_COLOR = (1 << 7), + EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE = (1 << 8), + EEVEE_RENDER_PASS_VOLUME_SCATTER = (1 << 9), + EEVEE_RENDER_PASS_EMIT = (1 << 10), + EEVEE_RENDER_PASS_ENVIRONMENT = (1 << 11), + EEVEE_RENDER_PASS_SHADOW = (1 << 12), + EEVEE_RENDER_PASS_AO = (1 << 13), + EEVEE_RENDER_PASS_BLOOM = (1 << 14), +} eViewLayerEEVEEPassType; + typedef struct Base { struct Base *next, *prev; @@ -76,6 +96,12 @@ typedef struct LayerCollection { short _pad2[3]; } LayerCollection; +/* Type containing EEVEE settings per view-layer */ +typedef struct ViewLayerEEVEE { + int render_passes; + int _pad[1]; +} ViewLayerEEVEE; + typedef struct ViewLayer { struct ViewLayer *next, *prev; /** MAX_NAME. */ @@ -106,6 +132,7 @@ typedef struct ViewLayer { struct IDProperty *id_properties; struct FreestyleConfig freestyle_config; + struct ViewLayerEEVEE eevee; /* Runtime data */ /** ViewLayerEngineData. */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 7cd6b5f5013..0b5ab37b5ca 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -318,6 +318,9 @@ typedef enum eScenePassType { #define RE_PASSNAME_SUBSURFACE_COLOR "SubsurfaceCol" #define RE_PASSNAME_FREESTYLE "Freestyle" +#define RE_PASSNAME_BLOOM "BloomCol" +#define RE_PASSNAME_VOLUME_TRANSMITTANCE "VolumeTransmCol" +#define RE_PASSNAME_VOLUME_SCATTER "VolumeScatterCol" /* View - MultiView */ typedef struct SceneRenderView { diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 483e5c4a952..c0e62f01e66 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -474,8 +474,8 @@ enum { /** Update size of regions within the area. */ AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3), AREA_FLAG_ACTIVE_TOOL_UPDATE = (1 << 4), + AREA_FLAG_CURSOR_UPDATE = (1 << 5), - // AREA_FLAG_UNUSED_5 = (1 << 5), AREA_FLAG_UNUSED_6 = (1 << 6), /* cleared */ /** diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 159c0424ee8..bdfe5040794 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -965,6 +965,8 @@ typedef struct FileDirEntry { short status; short flags; + /* eFileAttributes defined in BLI_fileops.h */ + int attributes; ListBase variants; int nbr_variants; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 49a7f72be30..bd6f9148d1e 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -679,6 +679,7 @@ extern StructRNA RNA_View3DCursor; extern StructRNA RNA_View3DOverlay; extern StructRNA RNA_View3DShading; extern StructRNA RNA_ViewLayer; +extern StructRNA RNA_ViewLayerEEVEE; extern StructRNA RNA_VoronoiTexture; extern StructRNA RNA_WalkNavigation; extern StructRNA RNA_WarpModifier; diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index a87a091f15e..d4bc02bbf3e 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -1711,7 +1711,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Maximum Trapped Air Potential", "Upper clamping threshold for marking fluid cells where air is trapped " - "(highe value results in less marked cells)"); + "(higher value results in less marked cells)"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); prop = RNA_def_property(srna, "sndparticle_potential_min_energy", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index d2a17967de9..32c6239da5a 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3756,6 +3756,30 @@ static void rna_def_unit_settings(BlenderRNA *brna) RNA_def_property_update(prop, NC_WINDOW, NULL); } +static void rna_def_view_layer_eevee(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + srna = RNA_def_struct(brna, "ViewLayerEEVEE", NULL); + RNA_def_struct_ui_text(srna, "EEVEE Settings", "View layer settings for EEVEE"); + + prop = RNA_def_property(srna, "use_pass_volume_scatter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "render_passes", EEVEE_RENDER_PASS_VOLUME_SCATTER); + RNA_def_property_ui_text(prop, "Volume Scatter", "Deliver volume scattering pass"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + + prop = RNA_def_property(srna, "use_pass_volume_transmittance", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, NULL, "render_passes", EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE); + RNA_def_property_ui_text(prop, "Volume Transmittance", "Deliver volume transmittance pass"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + + prop = RNA_def_property(srna, "use_pass_bloom", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "render_passes", EEVEE_RENDER_PASS_BLOOM); + RNA_def_property_ui_text(prop, "Bloom", "Deliver bloom pass"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); +} + void rna_def_view_layer_common(StructRNA *srna, const bool scene) { PropertyRNA *prop; @@ -3801,6 +3825,11 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) "Z, Index, normal, UV and vector passes are only affected by surfaces with " "alpha transparency equal to or higher than this threshold"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + + prop = RNA_def_property(srna, "eevee", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "ViewLayerEEVEE"); + RNA_def_property_ui_text(prop, "EEVEE Settings", "View layer settings for EEVEE"); } /* layer options */ @@ -7546,6 +7575,7 @@ void RNA_def_scene(BlenderRNA *brna) rna_def_display_safe_areas(brna); rna_def_scene_display(brna); rna_def_scene_eevee(brna); + rna_def_view_layer_eevee(brna); RNA_define_animate_sdna(true); /* *** Animated *** */ rna_def_scene_render_data(brna); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index b0304b742df..89f65da335a 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -80,7 +80,7 @@ static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), /* the settings for this are currently only available from a menu in the TimeLine, * hence refresh=SPACE_ACTION, as timeline is now in there */ - ED_screen_animation_timer_update(screen, screen->redraws_flag, SPACE_ACTION); + ED_screen_animation_timer_update(screen, screen->redraws_flag); } static bool rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr)) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index fdea081d8f1..975a3bdaf2e 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -382,14 +382,32 @@ static const EnumPropertyItem rna_enum_studio_light_items[] = { }; static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] = { - {SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""}, - /* {SCE_PASS_Z, "Z", 0, "Z", ""},*/ - {SCE_PASS_AO, "AO", 0, "Ambient Occlusion", ""}, - {SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""}, - {SCE_PASS_MIST, "MIST", 0, "Mist", ""}, - {SCE_PASS_SUBSURFACE_DIRECT, "SUBSURFACE_DIRECT", 0, "Subsurface Direct", ""}, - /* {SCE_PASS_SUBSURFACE_INDIRECT, "SUBSURFACE_INDIRECT", 0, "Subsurface Indirect", ""}, */ - {SCE_PASS_SUBSURFACE_COLOR, "SUBSURFACE_COLOR", 0, "Subsurface Color", ""}, + {0, "", ICON_NONE, "General", ""}, + {EEVEE_RENDER_PASS_COMBINED, "COMBINED", 0, "Combined", ""}, + {EEVEE_RENDER_PASS_EMIT, "EMISSION", 0, "Emission", ""}, + {EEVEE_RENDER_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""}, + {EEVEE_RENDER_PASS_AO, "AO", 0, "Ambient Occlusion", ""}, + {EEVEE_RENDER_PASS_SHADOW, "SHADOW", 0, "Shadow", ""}, + + {0, "", ICON_NONE, "Light", ""}, + {EEVEE_RENDER_PASS_DIFFUSE_LIGHT, "DIFFUSE_LIGHT", 0, "Diffuse Light", ""}, + {EEVEE_RENDER_PASS_DIFFUSE_COLOR, "DIFFUSE_COLOR", 0, "Diffuse Color", ""}, + {EEVEE_RENDER_PASS_SPECULAR_LIGHT, "SPECULAR_LIGHT", 0, "Specular Light", ""}, + {EEVEE_RENDER_PASS_SPECULAR_COLOR, "SPECULAR_COLOR", 0, "Specular Color", ""}, + {EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE, + "VOLUME_TRANSMITTANCE", + 0, + "Volume Transmittance", + ""}, + {EEVEE_RENDER_PASS_VOLUME_SCATTER, "VOLUME_SCATTER", 0, "Volume Scattering", ""}, + + {0, "", ICON_NONE, "Effects", ""}, + {EEVEE_RENDER_PASS_BLOOM, "BLOOM", 0, "Bloom", ""}, + + {0, "", ICON_NONE, "Data", ""}, + {EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""}, + {EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""}, + {0, NULL, 0, NULL, NULL}, }; @@ -1242,6 +1260,30 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(bContext *UN return item; } +static const EnumPropertyItem *rna_3DViewShading_render_pass_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + Scene *scene = CTX_data_scene(C); + + const bool ao_enabled = scene->eevee.flag & SCE_EEVEE_GTAO_ENABLED; + const bool bloom_enabled = scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED; + + int totitem = 0; + EnumPropertyItem *result = NULL; + for (int i = 0; rna_enum_view3dshading_render_pass_type_items[i].identifier != NULL; i++) { + const EnumPropertyItem *item = &rna_enum_view3dshading_render_pass_type_items[i]; + if (!((!ao_enabled && item->value == EEVEE_RENDER_PASS_AO) || + (!bloom_enabled && + (item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))))) { + RNA_enum_item_add(&result, &totitem, item); + } + } + *r_free = true; + return result; +} + static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA *ptr) { Main *bmain = CTX_data_main(C); @@ -3328,6 +3370,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "render_pass"); RNA_def_property_enum_items(prop, rna_enum_view3dshading_render_pass_type_items); RNA_def_property_ui_text(prop, "Render Pass", "Render Pass to show in the viewport"); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_3DViewShading_render_pass_itemf"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); } diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index ffc7425adaa..71e421c8b28 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -67,7 +67,7 @@ set(SRC intern/MOD_laplaciandeform.c intern/MOD_laplaciansmooth.c intern/MOD_lattice.c - intern/MOD_mask.c + intern/MOD_mask.cc intern/MOD_meshcache.c intern/MOD_meshcache_mdd.c intern/MOD_meshcache_pc2.c diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c deleted file mode 100644 index 00b0068bd11..00000000000 --- a/source/blender/modifiers/intern/MOD_mask.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * 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. - * - * The Original Code is Copyright (C) 2005 by the Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup modifiers - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_utildefines.h" - -#include "BLI_listbase.h" -#include "BLI_ghash.h" - -#include "DNA_armature_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" - -#include "BKE_action.h" /* BKE_pose_channel_find_name */ -#include "BKE_customdata.h" -#include "BKE_lib_query.h" -#include "BKE_mesh.h" -#include "BKE_modifier.h" -#include "BKE_deform.h" - -#include "DEG_depsgraph_build.h" -#include "DEG_depsgraph_query.h" - -#include "MOD_modifiertypes.h" - -#include "BLI_strict_flags.h" - -static void requiredDataMask(Object *UNUSED(ob), - ModifierData *UNUSED(md), - CustomData_MeshMasks *r_cddata_masks) -{ - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; -} - -static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) -{ - MaskModifierData *mmd = (MaskModifierData *)md; - walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP); -} - -static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) -{ - MaskModifierData *mmd = (MaskModifierData *)md; - if (mmd->ob_arm) { - bArmature *arm = (bArmature *)mmd->ob_arm->data; - /* Tag relationship in depsgraph, but also on the armature. */ - /* TODO(sergey): Is it a proper relation here? */ - DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier"); - arm->flag |= ARM_HAS_VIZ_DEPS; - DEG_add_modifier_to_transform_relation(ctx->node, "Mask Modifier"); - } -} - -static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) -{ - MaskModifierData *mmd = (MaskModifierData *)md; - Object *ob = ctx->object; - const bool found_test = (mmd->flag & MOD_MASK_INV) == 0; - Mesh *result = NULL; - GHash *vertHash = NULL, *edgeHash, *polyHash; - GHashIterator gh_iter; - MDeformVert *dvert, *dv; - int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0; - int maxVerts, maxEdges, maxPolys; - int i; - - const MVert *mvert_src; - const MEdge *medge_src; - const MPoly *mpoly_src; - const MLoop *mloop_src; - - MPoly *mpoly_dst; - MLoop *mloop_dst; - MEdge *medge_dst; - MVert *mvert_dst; - - int *loop_mapping; - - dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); - if (dvert == NULL) { - return found_test ? BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0) : mesh; - } - - /* Overview of Method: - * 1. Get the vertices that are in the vertexgroup of interest. - * 2. Filter out unwanted geometry (i.e. not in vertexgroup), - * by populating mappings with new vs old indices. - * 3. Make a new mesh containing only the mapping data. - */ - - /* get original number of verts, edges, and faces */ - maxVerts = mesh->totvert; - maxEdges = mesh->totedge; - maxPolys = mesh->totpoly; - - /* check if we can just return the original mesh - * - must have verts and therefore verts assigned to vgroups to do anything useful - */ - if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (maxVerts == 0) || - BLI_listbase_is_empty(&ob->defbase)) { - return mesh; - } - - /* if mode is to use selected armature bones, aggregate the bone groups */ - if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */ - Object *oba = mmd->ob_arm; - bPoseChannel *pchan; - bDeformGroup *def; - bool *bone_select_array; - int bone_select_tot = 0; - const uint defbase_tot = (uint)BLI_listbase_count(&ob->defbase); - - /* check that there is armature object with bones to use, otherwise return original mesh */ - if (ELEM(NULL, oba, oba->pose, ob->defbase.first)) { - return mesh; - } - - /* Determine whether each vertex-group is associated with a selected bone or not: - * - Each cell is a boolean saying whether bone corresponding to the i'th group selected. - * - Groups that don't match a bone are treated as not existing - * (along with the corresponding un-grouped verts). - */ - bone_select_array = MEM_malloc_arrayN((size_t)defbase_tot, sizeof(char), "mask array"); - - for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { - pchan = BKE_pose_channel_find_name(oba->pose, def->name); - if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { - bone_select_array[i] = true; - bone_select_tot++; - } - else { - bone_select_array[i] = false; - } - } - - /* verthash gives mapping from original vertex indices to the new indices - * (including selected matches only): - * key = oldindex, value = newindex - */ - vertHash = BLI_ghash_int_new_ex("mask vert gh", (uint)maxVerts); - - /* add vertices which exist in vertexgroups into vertHash for filtering - * - dv = for each vertex, what vertexgroups does it belong to - * - dw = weight that vertex was assigned to a vertexgroup it belongs to - */ - for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { - MDeformWeight *dw = dv->dw; - bool found = false; - int j; - - /* check the groups that vertex is assigned to, and see if it was any use */ - for (j = 0; j < dv->totweight; j++, dw++) { - if (dw->def_nr < defbase_tot) { - if (bone_select_array[dw->def_nr]) { - if (dw->weight > mmd->threshold) { - found = true; - break; - } - } - } - } - - if (found_test != found) { - continue; - } - - /* add to ghash for verts (numVerts acts as counter for mapping) */ - BLI_ghash_insert(vertHash, POINTER_FROM_INT(i), POINTER_FROM_INT(numVerts)); - numVerts++; - } - - /* free temp hashes */ - MEM_freeN(bone_select_array); - } - else { /* --- Using Nominated VertexGroup only --- */ - int defgrp_index = defgroup_name_index(ob, mmd->vgroup); - - /* if no vgroup (i.e. dverts) found, return the initial mesh */ - if (defgrp_index == -1) { - return mesh; - } - - /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ - vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (uint)maxVerts); - - /* add vertices which exist in vertexgroup into ghash for filtering */ - for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { - const bool found = defvert_find_weight(dv, defgrp_index) > mmd->threshold; - if (found_test != found) { - continue; - } - - /* add to ghash for verts (numVerts acts as counter for mapping) */ - BLI_ghash_insert(vertHash, POINTER_FROM_INT(i), POINTER_FROM_INT(numVerts)); - numVerts++; - } - } - - /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ - edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (uint)maxEdges); - polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (uint)maxPolys); - - mvert_src = mesh->mvert; - medge_src = mesh->medge; - mpoly_src = mesh->mpoly; - mloop_src = mesh->mloop; - - /* overalloc, assume all polys are seen */ - loop_mapping = MEM_malloc_arrayN((size_t)maxPolys, sizeof(int), "mask loopmap"); - - /* loop over edges and faces, and do the same thing to - * ensure that they only reference existing verts - */ - for (i = 0; i < maxEdges; i++) { - const MEdge *me = &medge_src[i]; - - /* only add if both verts will be in new mesh */ - if (BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v1)) && - BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v2))) { - BLI_ghash_insert(edgeHash, POINTER_FROM_INT(i), POINTER_FROM_INT(numEdges)); - numEdges++; - } - } - for (i = 0; i < maxPolys; i++) { - const MPoly *mp_src = &mpoly_src[i]; - const MLoop *ml_src = &mloop_src[mp_src->loopstart]; - bool ok = true; - int j; - - for (j = 0; j < mp_src->totloop; j++, ml_src++) { - if (!BLI_ghash_haskey(vertHash, POINTER_FROM_INT(ml_src->v))) { - ok = false; - break; - } - } - - /* all verts must be available */ - if (ok) { - BLI_ghash_insert(polyHash, POINTER_FROM_INT(i), POINTER_FROM_INT(numPolys)); - loop_mapping[numPolys] = numLoops; - numPolys++; - numLoops += mp_src->totloop; - } - } - - /* now we know the number of verts, edges and faces, - * we can create the new (reduced) mesh - */ - result = BKE_mesh_new_nomain_from_template(mesh, numVerts, numEdges, 0, numLoops, numPolys); - - mpoly_dst = result->mpoly; - mloop_dst = result->mloop; - medge_dst = result->medge; - mvert_dst = result->mvert; - - /* using ghash-iterators, map data into new mesh */ - /* vertices */ - GHASH_ITER (gh_iter, vertHash) { - const MVert *v_src; - MVert *v_dst; - const int i_src = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); - const int i_dst = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); - - v_src = &mvert_src[i_src]; - v_dst = &mvert_dst[i_dst]; - - *v_dst = *v_src; - CustomData_copy_data(&mesh->vdata, &result->vdata, i_src, i_dst, 1); - } - - /* edges */ - GHASH_ITER (gh_iter, edgeHash) { - const MEdge *e_src; - MEdge *e_dst; - const int i_src = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); - const int i_dst = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); - - e_src = &medge_src[i_src]; - e_dst = &medge_dst[i_dst]; - - CustomData_copy_data(&mesh->edata, &result->edata, i_src, i_dst, 1); - *e_dst = *e_src; - e_dst->v1 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v1))); - e_dst->v2 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v2))); - } - - /* faces */ - GHASH_ITER (gh_iter, polyHash) { - const int i_src = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); - const int i_dst = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); - const MPoly *mp_src = &mpoly_src[i_src]; - MPoly *mp_dst = &mpoly_dst[i_dst]; - const int i_ml_src = mp_src->loopstart; - const int i_ml_dst = loop_mapping[i_dst]; - const MLoop *ml_src = &mloop_src[i_ml_src]; - MLoop *ml_dst = &mloop_dst[i_ml_dst]; - - CustomData_copy_data(&mesh->pdata, &result->pdata, i_src, i_dst, 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, i_ml_src, i_ml_dst, mp_src->totloop); - - *mp_dst = *mp_src; - mp_dst->loopstart = i_ml_dst; - for (i = 0; i < mp_src->totloop; i++) { - ml_dst[i].v = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(ml_src[i].v))); - ml_dst[i].e = POINTER_AS_UINT(BLI_ghash_lookup(edgeHash, POINTER_FROM_UINT(ml_src[i].e))); - } - } - - MEM_freeN(loop_mapping); - - /* why is this needed? - campbell */ - /* recalculate normals */ - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - - /* free hashes */ - BLI_ghash_free(vertHash, NULL, NULL); - BLI_ghash_free(edgeHash, NULL, NULL); - BLI_ghash_free(polyHash, NULL, NULL); - - /* return the new mesh */ - return result; -} - -static bool isDisabled(const struct Scene *UNUSED(scene), - ModifierData *md, - bool UNUSED(useRenderParams)) -{ - MaskModifierData *mmd = (MaskModifierData *)md; - - /* The object type check is only needed here in case we have a placeholder - * object assigned (because the library containing the armature is missing). - * - * In other cases it should be impossible to have a type mismatch. - */ - return mmd->ob_arm && mmd->ob_arm->type != OB_ARMATURE; -} - -ModifierTypeInfo modifierType_Mask = { - /* name */ "Mask", - /* structName */ "MaskModifierData", - /* structSize */ sizeof(MaskModifierData), - /* type */ eModifierTypeType_Nonconstructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ NULL, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, -}; diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc new file mode 100644 index 00000000000..fb179d2e485 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -0,0 +1,417 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2005 by the Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup modifiers + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BLI_listbase.h" +#include "BLI_ghash.h" + +#include "DNA_armature_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" /* BKE_pose_channel_find_name */ +#include "BKE_customdata.h" +#include "BKE_lib_query.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_deform.h" + +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "MOD_modifiertypes.h" + +#include "BLI_array_cxx.h" +#include "BLI_vector.h" +#include "BLI_listbase_wrapper.h" + +using BLI::Array; +using BLI::ArrayRef; +using BLI::IndexRange; +using BLI::IntrusiveListBaseWrapper; +using BLI::MutableArrayRef; +using BLI::Vector; + +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *r_cddata_masks) +{ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; +} + +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) +{ + MaskModifierData *mmd = (MaskModifierData *)md; + walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP); +} + +static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + MaskModifierData *mmd = (MaskModifierData *)md; + if (mmd->ob_arm) { + bArmature *arm = (bArmature *)mmd->ob_arm->data; + /* Tag relationship in depsgraph, but also on the armature. */ + /* TODO(sergey): Is it a proper relation here? */ + DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier"); + arm->flag |= ARM_HAS_VIZ_DEPS; + DEG_add_modifier_to_transform_relation(ctx->node, "Mask Modifier"); + } +} + +/* A vertex will be in the mask if a selected bone influences it more than a certain threshold. */ +static void compute_vertex_mask__armature_mode(MDeformVert *dvert, + Object *ob, + Object *armature_ob, + float threshold, + MutableArrayRef<bool> r_vertex_mask) +{ + /* Element i is true if there is a selected bone that uses vertex group i. */ + Vector<bool> selected_bone_uses_group; + + for (bDeformGroup *def : IntrusiveListBaseWrapper<bDeformGroup>(ob->defbase)) { + bPoseChannel *pchan = BKE_pose_channel_find_name(armature_ob->pose, def->name); + bool bone_for_group_exists = pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED); + selected_bone_uses_group.append(bone_for_group_exists); + } + + ArrayRef<bool> use_vertex_group = selected_bone_uses_group; + + for (int i : r_vertex_mask.index_range()) { + ArrayRef<MDeformWeight> weights(dvert[i].dw, dvert[i].totweight); + r_vertex_mask[i] = false; + + /* check the groups that vertex is assigned to, and see if it was any use */ + for (const MDeformWeight &dw : weights) { + if (use_vertex_group.get(dw.def_nr, false)) { + if (dw.weight > threshold) { + r_vertex_mask[i] = true; + break; + } + } + } + } +} + +/* A vertex will be in the mask if the vertex group influences it more than a certain threshold. */ +static void compute_vertex_mask__vertex_group_mode(MDeformVert *dvert, + int defgrp_index, + float threshold, + MutableArrayRef<bool> r_vertex_mask) +{ + for (int i : r_vertex_mask.index_range()) { + const bool found = defvert_find_weight(&dvert[i], defgrp_index) > threshold; + r_vertex_mask[i] = found; + } +} + +static void invert_boolean_array(MutableArrayRef<bool> array) +{ + for (bool &value : array) { + value = !value; + } +} + +static void compute_masked_vertices(ArrayRef<bool> vertex_mask, + MutableArrayRef<int> r_vertex_map, + uint *r_num_masked_vertices) +{ + BLI_assert(vertex_mask.size() == r_vertex_map.size()); + + uint num_masked_vertices = 0; + for (uint i_src : r_vertex_map.index_range()) { + if (vertex_mask[i_src]) { + r_vertex_map[i_src] = num_masked_vertices; + num_masked_vertices++; + } + else { + r_vertex_map[i_src] = -1; + } + } + + *r_num_masked_vertices = num_masked_vertices; +} + +static void computed_masked_edges(const Mesh *mesh, + ArrayRef<bool> vertex_mask, + MutableArrayRef<int> r_edge_map, + uint *r_num_masked_edges) +{ + BLI_assert(mesh->totedge == r_edge_map.size()); + + uint num_masked_edges = 0; + for (int i : IndexRange(mesh->totedge)) { + const MEdge &edge = mesh->medge[i]; + + /* only add if both verts will be in new mesh */ + if (vertex_mask[edge.v1] && vertex_mask[edge.v2]) { + r_edge_map[i] = num_masked_edges; + num_masked_edges++; + } + else { + r_edge_map[i] = -1; + } + } + + *r_num_masked_edges = num_masked_edges; +} + +static void computed_masked_polygons(const Mesh *mesh, + ArrayRef<bool> vertex_mask, + Vector<int> &r_masked_poly_indices, + Vector<int> &r_loop_starts, + uint *r_num_masked_polys, + uint *r_num_masked_loops) +{ + BLI_assert(mesh->totvert == vertex_mask.size()); + + r_masked_poly_indices.reserve(mesh->totpoly); + r_loop_starts.reserve(mesh->totloop); + + uint num_masked_loops = 0; + for (int i : IndexRange(mesh->totpoly)) { + const MPoly &poly_src = mesh->mpoly[i]; + + bool all_verts_in_mask = true; + ArrayRef<MLoop> loops_src(&mesh->mloop[poly_src.loopstart], poly_src.totloop); + for (const MLoop &loop : loops_src) { + if (!vertex_mask[loop.v]) { + all_verts_in_mask = false; + break; + } + } + + if (all_verts_in_mask) { + r_masked_poly_indices.append_unchecked(i); + r_loop_starts.append_unchecked(num_masked_loops); + num_masked_loops += poly_src.totloop; + } + } + + *r_num_masked_polys = r_masked_poly_indices.size(); + *r_num_masked_loops = num_masked_loops; +} + +static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + ArrayRef<int> vertex_map) +{ + BLI_assert(src_mesh.totvert == vertex_map.size()); + for (const int i_src : vertex_map.index_range()) { + const int i_dst = vertex_map[i_src]; + if (i_dst == -1) { + continue; + } + + const MVert &v_src = src_mesh.mvert[i_src]; + MVert &v_dst = dst_mesh.mvert[i_dst]; + + v_dst = v_src; + CustomData_copy_data(&src_mesh.vdata, &dst_mesh.vdata, i_src, i_dst, 1); + } +} + +static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + ArrayRef<int> vertex_map, + ArrayRef<int> edge_map) +{ + BLI_assert(src_mesh.totvert == vertex_map.size()); + BLI_assert(src_mesh.totedge == edge_map.size()); + for (const int i_src : IndexRange(src_mesh.totedge)) { + const int i_dst = edge_map[i_src]; + if (i_dst == -1) { + continue; + } + + const MEdge &e_src = src_mesh.medge[i_src]; + MEdge &e_dst = dst_mesh.medge[i_dst]; + + CustomData_copy_data(&src_mesh.edata, &dst_mesh.edata, i_src, i_dst, 1); + e_dst = e_src; + e_dst.v1 = vertex_map[e_src.v1]; + e_dst.v2 = vertex_map[e_src.v2]; + } +} + +static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + ArrayRef<int> vertex_map, + ArrayRef<int> edge_map, + ArrayRef<int> masked_poly_indices, + ArrayRef<int> new_loop_starts) +{ + for (const int i_dst : masked_poly_indices.index_range()) { + const int i_src = masked_poly_indices[i_dst]; + + const MPoly &mp_src = src_mesh.mpoly[i_src]; + MPoly &mp_dst = dst_mesh.mpoly[i_dst]; + const int i_ml_src = mp_src.loopstart; + const int i_ml_dst = new_loop_starts[i_dst]; + + CustomData_copy_data(&src_mesh.pdata, &dst_mesh.pdata, i_src, i_dst, 1); + CustomData_copy_data(&src_mesh.ldata, &dst_mesh.ldata, i_ml_src, i_ml_dst, mp_src.totloop); + + const MLoop *ml_src = src_mesh.mloop + i_ml_src; + MLoop *ml_dst = dst_mesh.mloop + i_ml_dst; + + mp_dst = mp_src; + mp_dst.loopstart = i_ml_dst; + for (int i : IndexRange(mp_src.totloop)) { + ml_dst[i].v = vertex_map[ml_src[i].v]; + ml_dst[i].e = edge_map[ml_src[i].e]; + } + } +} + +/* Components of the algorithm: + * 1. Figure out which vertices should be present in the output mesh. + * 2. Find edges and polygons only using those vertices. + * 3. Create a new mesh that only uses the found vertices, edges and polygons. + */ +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) +{ + MaskModifierData *mmd = (MaskModifierData *)md; + Object *ob = ctx->object; + const bool invert_mask = mmd->flag & MOD_MASK_INV; + + /* Return empty or input mesh when there are no vertex groups. */ + MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); + if (dvert == NULL) { + return invert_mask ? mesh : BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0); + } + + /* Quick test to see if we can return early. */ + if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (mesh->totvert == 0) || + BLI_listbase_is_empty(&ob->defbase)) { + return mesh; + } + + Array<bool> vertex_mask; + if (mmd->mode == MOD_MASK_MODE_ARM) { + Object *armature_ob = mmd->ob_arm; + + /* Return input mesh if there is no armature with bones. */ + if (ELEM(NULL, armature_ob, armature_ob->pose, ob->defbase.first)) { + return mesh; + } + + vertex_mask = Array<bool>(mesh->totvert); + compute_vertex_mask__armature_mode(dvert, ob, armature_ob, mmd->threshold, vertex_mask); + } + else { + int defgrp_index = defgroup_name_index(ob, mmd->vgroup); + + /* Return input mesh if the vertex group does not exist. */ + if (defgrp_index == -1) { + return mesh; + } + + vertex_mask = Array<bool>(mesh->totvert); + compute_vertex_mask__vertex_group_mode(dvert, defgrp_index, mmd->threshold, vertex_mask); + } + + if (invert_mask) { + invert_boolean_array(vertex_mask); + } + + Array<int> vertex_map(mesh->totvert); + uint num_masked_vertices; + compute_masked_vertices(vertex_mask, vertex_map, &num_masked_vertices); + + Array<int> edge_map(mesh->totedge); + uint num_masked_edges; + computed_masked_edges(mesh, vertex_mask, edge_map, &num_masked_edges); + + Vector<int> masked_poly_indices; + Vector<int> new_loop_starts; + uint num_masked_polys; + uint num_masked_loops; + computed_masked_polygons(mesh, + vertex_mask, + masked_poly_indices, + new_loop_starts, + &num_masked_polys, + &num_masked_loops); + + Mesh *result = BKE_mesh_new_nomain_from_template( + mesh, num_masked_vertices, num_masked_edges, 0, num_masked_loops, num_masked_polys); + + copy_masked_vertices_to_new_mesh(*mesh, *result, vertex_map); + copy_masked_edges_to_new_mesh(*mesh, *result, vertex_map, edge_map); + copy_masked_polys_to_new_mesh( + *mesh, *result, vertex_map, edge_map, masked_poly_indices, new_loop_starts); + + /* Tag to recalculate normals later. */ + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + + return result; +} + +static bool isDisabled(const struct Scene *UNUSED(scene), + ModifierData *md, + bool UNUSED(useRenderParams)) +{ + MaskModifierData *mmd = (MaskModifierData *)md; + + /* The object type check is only needed here in case we have a placeholder + * object assigned (because the library containing the armature is missing). + * + * In other cases it should be impossible to have a type mismatch. + */ + return mmd->ob_arm && mmd->ob_arm->type != OB_ARMATURE; +} + +ModifierTypeInfo modifierType_Mask = { + /* name */ "Mask", + /* structName */ "MaskModifierData", + /* structSize */ sizeof(MaskModifierData), + /* type */ eModifierTypeType_Nonconstructive, + /* flags */ + (ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode), + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ NULL, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, +}; diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index 89349d91f94..93f2ba44a3a 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -281,8 +281,11 @@ void ntreeCompositUpdateRLayers(bNodeTree *ntree) } } -void ntreeCompositRegisterPass( - bNodeTree *ntree, Scene *scene, ViewLayer *view_layer, const char *name, int type) +void ntreeCompositRegisterPass(bNodeTree *ntree, + Scene *scene, + ViewLayer *view_layer, + const char *name, + eNodeSocketDatatype type) { bNode *node; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index b74f325a3fa..f8a97868959 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -72,13 +72,14 @@ static bNodeSocketTemplate cmp_node_rlayers_out[] = { {SOCK_RGBA, 0, N_(RE_PASSNAME_SUBSURFACE_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, {-1, 0, ""}, }; +#define MAX_LEGACY_SOCKET_INDEX 30 static void cmp_node_image_add_pass_output(bNodeTree *ntree, bNode *node, const char *name, const char *passname, int rres_index, - int type, + eNodeSocketDatatype type, int is_rlayers, LinkNodePair *available_sockets, int *prev_index) @@ -94,8 +95,8 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree, * New sockets are placed behind the previously traversed one, * but always after the first 31. */ int after_index = *prev_index; - if (is_rlayers && after_index < 30) { - after_index = 30; + if (is_rlayers && after_index < MAX_LEGACY_SOCKET_INDEX) { + after_index = MAX_LEGACY_SOCKET_INDEX; } if (rres_index >= 0) { @@ -238,8 +239,12 @@ typedef struct RLayerUpdateData { int prev_index; } RLayerUpdateData; -void node_cmp_rlayers_register_pass( - bNodeTree *ntree, bNode *node, Scene *scene, ViewLayer *view_layer, const char *name, int type) +void node_cmp_rlayers_register_pass(bNodeTree *ntree, + bNode *node, + Scene *scene, + ViewLayer *view_layer, + const char *name, + eNodeSocketDatatype type) { RLayerUpdateData *data = node->storage; @@ -389,7 +394,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl break; } } - if (!link && (!rlayer || sock_index > 30)) { + if (!link && (!rlayer || sock_index > MAX_LEGACY_SOCKET_INDEX)) { MEM_freeN(sock->storage); nodeRemoveSocket(ntree, node, sock); } @@ -508,7 +513,7 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index) RE_PASSNAME_SUBSURFACE_INDIRECT, RE_PASSNAME_SUBSURFACE_COLOR, }; - if (sock_index > 30) { + if (sock_index > MAX_LEGACY_SOCKET_INDEX) { return NULL; } return sock_to_passname[sock_index]; diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index 5eb5223edfe..a0e2256b1ce 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -24,6 +24,8 @@ extern PyTypeObject matrix_Type; extern PyTypeObject matrix_access_Type; +typedef unsigned short ushort; + #define MatrixObject_Check(v) PyObject_TypeCheck((v), &matrix_Type) #define MatrixObject_CheckExact(v) (Py_TYPE(v) == &matrix_Type) diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 12e9123b5cb..88614de1641 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -26,6 +26,7 @@ #include "DNA_listBase.h" #include "DNA_scene_types.h" +#include "DNA_node_types.h" #include "RNA_types.h" #include "RE_bake.h" @@ -117,7 +118,7 @@ typedef void (*update_render_passes_cb_t)(void *userdata, const char *name, int channels, const char *chanid, - int type); + eNodeSocketDatatype type); typedef struct RenderEngine { RenderEngineType *type; @@ -212,7 +213,7 @@ void RE_engine_register_pass(struct RenderEngine *engine, const char *name, int channels, const char *chanid, - int type); + eNodeSocketDatatype type); /* Engine Types */ diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 90058da5f0c..598f300cf86 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -863,7 +863,7 @@ void RE_engine_register_pass(struct RenderEngine *engine, const char *name, int channels, const char *chanid, - int type) + eNodeSocketDatatype type) { if (!(scene && view_layer && engine && engine->update_render_passes_cb)) { return; diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 120787a8d13..b2225d70eaf 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -442,6 +442,15 @@ RenderResult *render_result_new(Render *re, if (view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) { RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB"); } + if (view_layer->eevee.render_passes & EEVEE_RENDER_PASS_BLOOM) { + RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_BLOOM, view, "RGB"); + } + if (view_layer->eevee.render_passes & EEVEE_RENDER_PASS_VOLUME_SCATTER) { + RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_VOLUME_SCATTER, view, "RGB"); + } + if (view_layer->eevee.render_passes & EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE) { + RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_VOLUME_TRANSMITTANCE, view, "RGB"); + } #undef RENDER_LAYER_ADD_PASS_SAFE } } diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index 616cb7613ba..9184a2b4566 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -374,6 +374,16 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C, toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref); + /* Set the cursor if possible, if not - it's fine as entering the region will refresh it. */ + { + wmWindow *win = CTX_wm_window(C); + ScrArea *sa = CTX_wm_area(C); + if (win && sa) { + win->addmousemove = true; + sa->flag |= AREA_FLAG_CURSOR_UPDATE; + } + } + { struct wmMsgBus *mbus = CTX_wm_message_bus(C); WM_msg_publish_rna_prop(mbus, &workspace->id, workspace, WorkSpace, tools); |