EEVEE: Arbitrary Output Variables
This patch adds support for AOVs in EEVEE. AOV Outputs can be defined in the render pass tab and used in shader materials. Both Object and World based shaders are supported. The AOV can be previewed in the viewport using the renderpass selector in the shading popover. AOV names that conflict with other AOVs are automatically corrected. AOV conflicts with render passes get a warning icon. The reason behind this is that changing render engines/passes can change the conflict, but you might not notice it. Changing this automatically would also make the materials incorrect, so best to leave this to the user. **Implementation** The patch adds a copies the AOV structures of Cycles into Blender. The goal is that the Cycles will use Blenders AOV defintions. In the Blender kernel (`layer.c`) the logic of these structures are implemented. The GLSL shader of any GPUMaterial can hold multiple outputs (the main output and the AOV outputs) based on the renderPassUBO the right output is selected. This selection uses an hash that encodes the AOV structure. The full AOV needed to be encoded when actually drawing the material pass as the AOV type changes the behavior of the AOV. This isn't known yet when the GLSL is compiled. **Future Developments** * The AOV definitions in the render layer panel isn't shared with Cycles. Cycles should be migrated to use the same viewlayer aovs. During a previous attempt this failed as the AOV validation in cycles and in Blender have implementation differences what made it crash when an aov name was invalid. This could be fixed by extending the external render engine API. * Add support to Cycles to render AOVs in the 3d viewport. * Use a drop down list for selecting AOVs in the AOV Output node. * Give user feedback when multiple AOV output nodes with the same AOV name exists in the same shader. * Fix viewing single channel images in the image editor [T83314] * Reduce viewport render time by only render needed draw passes. [T83316] Reviewed By: Brecht van Lommel, Clément Foucault Differential Revision: https://developer.blender.org/D7010
This commit is contained in:
committed by
Jeroen Bakker
parent
2bd0263fbf
commit
2bae11d5c0
+1
-1
Submodule release/datafiles/locale updated: ae7e6c215c...1c0e9c29fd
+1
-1
Submodule release/scripts/addons updated: ca74197440...672cfe9c85
@@ -17,7 +17,16 @@
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
from bpy.types import Panel
|
||||
from bpy.types import Panel, UIList
|
||||
|
||||
|
||||
class VIEWLAYER_UL_aov(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
row = layout.row()
|
||||
split = row.split(factor=0.65)
|
||||
icon = 'NONE' if item.is_valid else 'ERROR'
|
||||
split.row().prop(item, "name", text="", icon=icon, emboss=False)
|
||||
split.row().prop(item, "type", text="", emboss=False)
|
||||
|
||||
|
||||
class ViewLayerButtonsPanel:
|
||||
@@ -49,7 +58,7 @@ class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel):
|
||||
col.prop(rd, "use_single_layer", text="Render Single Layer")
|
||||
|
||||
|
||||
class VIEWLAYER_PT_eevee_layer_passes(ViewLayerButtonsPanel, Panel):
|
||||
class VIEWLAYER_PT_layer_passes(ViewLayerButtonsPanel, Panel):
|
||||
bl_label = "Passes"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
@@ -59,7 +68,7 @@ class VIEWLAYER_PT_eevee_layer_passes(ViewLayerButtonsPanel, Panel):
|
||||
|
||||
class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel):
|
||||
bl_label = "Data"
|
||||
bl_parent_id = "VIEWLAYER_PT_eevee_layer_passes"
|
||||
bl_parent_id = "VIEWLAYER_PT_layer_passes"
|
||||
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
@@ -81,7 +90,7 @@ class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel):
|
||||
|
||||
class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
|
||||
bl_label = "Light"
|
||||
bl_parent_id = "VIEWLAYER_PT_eevee_layer_passes"
|
||||
bl_parent_id = "VIEWLAYER_PT_layer_passes"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
def draw(self, context):
|
||||
@@ -116,7 +125,7 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
|
||||
|
||||
class VIEWLAYER_PT_eevee_layer_passes_effects(ViewLayerButtonsPanel, Panel):
|
||||
bl_label = "Effects"
|
||||
bl_parent_id = "VIEWLAYER_PT_eevee_layer_passes"
|
||||
bl_parent_id = "VIEWLAYER_PT_layer_passes"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
def draw(self, context):
|
||||
@@ -135,12 +144,41 @@ class VIEWLAYER_PT_eevee_layer_passes_effects(ViewLayerButtonsPanel, Panel):
|
||||
col.active = scene_eevee.use_bloom
|
||||
|
||||
|
||||
class VIEWLAYER_PT_layer_passes_aov(ViewLayerButtonsPanel, Panel):
|
||||
bl_label = "Shader AOV"
|
||||
bl_parent_id = "VIEWLAYER_PT_layer_passes"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
view_layer = context.view_layer
|
||||
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.template_list("VIEWLAYER_UL_aov", "aovs", view_layer, "aovs", view_layer, "active_aov_index", rows=2)
|
||||
|
||||
col = row.column()
|
||||
sub = col.column(align=True)
|
||||
sub.operator("scene.view_layer_add_aov", icon='ADD', text="")
|
||||
sub.operator("scene.view_layer_remove_aov", icon='REMOVE', text="")
|
||||
|
||||
aov = view_layer.active_aov
|
||||
if aov and not aov.is_valid:
|
||||
layout.label(text="Conflicts with another render pass with the same name", icon='ERROR')
|
||||
|
||||
|
||||
classes = (
|
||||
VIEWLAYER_PT_layer,
|
||||
VIEWLAYER_PT_eevee_layer_passes,
|
||||
VIEWLAYER_PT_layer_passes,
|
||||
VIEWLAYER_PT_eevee_layer_passes_data,
|
||||
VIEWLAYER_PT_eevee_layer_passes_light,
|
||||
VIEWLAYER_PT_eevee_layer_passes_effects,
|
||||
VIEWLAYER_PT_layer_passes_aov,
|
||||
VIEWLAYER_UL_aov,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
||||
@@ -165,11 +165,6 @@ def object_cycles_shader_nodes_poll(context):
|
||||
cycles_shader_nodes_poll(context))
|
||||
|
||||
|
||||
def cycles_aov_node_poll(context):
|
||||
return (object_cycles_shader_nodes_poll(context) or
|
||||
world_shader_nodes_poll(context))
|
||||
|
||||
|
||||
def object_eevee_shader_nodes_poll(context):
|
||||
return (object_shader_nodes_poll(context) and
|
||||
eevee_shader_nodes_poll(context))
|
||||
@@ -210,7 +205,7 @@ shader_node_categories = [
|
||||
ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[
|
||||
NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll),
|
||||
NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll),
|
||||
NodeItem("ShaderNodeOutputAOV", poll=cycles_aov_node_poll),
|
||||
NodeItem("ShaderNodeOutputAOV"),
|
||||
NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll),
|
||||
NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll),
|
||||
NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
|
||||
|
||||
@@ -26,6 +26,7 @@ extern "C" {
|
||||
struct ListBase;
|
||||
|
||||
void BKE_appdir_init(void);
|
||||
void BKE_appdir_exit(void);
|
||||
|
||||
/* note on naming: typical _get() suffix is omitted here,
|
||||
* since its the main purpose of the API. */
|
||||
|
||||
@@ -42,6 +42,7 @@ struct Depsgraph;
|
||||
struct LayerCollection;
|
||||
struct Main;
|
||||
struct Object;
|
||||
struct RenderEngine;
|
||||
struct Scene;
|
||||
struct View3D;
|
||||
struct ViewLayer;
|
||||
@@ -444,6 +445,15 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(struct Object *ob, void *user_dat
|
||||
BKE_view_layer_array_from_objects_in_mode( \
|
||||
view_layer, v3d, r_len, {.object_mode = mode, .no_dup_data = true})
|
||||
|
||||
struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer);
|
||||
void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
|
||||
void BKE_view_layer_set_active_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
|
||||
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer);
|
||||
bool BKE_view_layer_has_valid_aov(struct ViewLayer *view_layer);
|
||||
ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, struct ViewLayerAOV *view_layer_aov);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -726,6 +726,7 @@ if(WITH_GTESTS)
|
||||
intern/fcurve_test.cc
|
||||
intern/lattice_deform_test.cc
|
||||
intern/tracking_test.cc
|
||||
intern/layer_test.cc
|
||||
)
|
||||
set(TEST_INC
|
||||
../editors/include
|
||||
|
||||
@@ -114,6 +114,14 @@ void BKE_appdir_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void BKE_appdir_exit(void)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
BLI_assert(is_appdir_init == true);
|
||||
is_appdir_init = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
|
||||
#include "DRW_engine.h"
|
||||
|
||||
#include "RE_engine.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLO_read_write.h"
|
||||
@@ -279,6 +281,8 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
|
||||
}
|
||||
}
|
||||
BLI_freelistN(&view_layer->drawdata);
|
||||
BLI_freelistN(&view_layer->aovs);
|
||||
view_layer->active_aov = NULL;
|
||||
|
||||
MEM_SAFE_FREE(view_layer->stats);
|
||||
|
||||
@@ -412,6 +416,28 @@ void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Bas
|
||||
}
|
||||
|
||||
/**************************** Copy View Layer and Layer Collections ***********************/
|
||||
static void layer_aov_copy_data(ViewLayer *view_layer_dst,
|
||||
const ViewLayer *view_layer_src,
|
||||
ListBase *aovs_dst,
|
||||
const ListBase *aovs_src)
|
||||
{
|
||||
if (aovs_src != NULL) {
|
||||
BLI_duplicatelist(aovs_dst, aovs_src);
|
||||
}
|
||||
|
||||
ViewLayerAOV *aov_dst = aovs_dst->first;
|
||||
const ViewLayerAOV *aov_src = aovs_src->first;
|
||||
|
||||
while (aov_dst != NULL) {
|
||||
BLI_assert(aov_src);
|
||||
if (aov_src == view_layer_src->active_aov) {
|
||||
view_layer_dst->active_aov = aov_dst;
|
||||
}
|
||||
|
||||
aov_dst = aov_dst->next;
|
||||
aov_src = aov_src->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void layer_collections_copy_data(ViewLayer *view_layer_dst,
|
||||
const ViewLayer *view_layer_src,
|
||||
@@ -482,6 +508,10 @@ void BKE_view_layer_copy_data(Scene *scene_dst,
|
||||
LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
|
||||
lc_scene_dst->collection = scene_dst->master_collection;
|
||||
|
||||
BLI_listbase_clear(&view_layer_dst->aovs);
|
||||
layer_aov_copy_data(
|
||||
view_layer_dst, view_layer_src, &view_layer_dst->aovs, &view_layer_src->aovs);
|
||||
|
||||
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
||||
id_us_plus((ID *)view_layer_dst->mat_override);
|
||||
}
|
||||
@@ -1864,6 +1894,9 @@ void BKE_view_layer_blend_write(BlendWriter *writer, ViewLayer *view_layer)
|
||||
LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
|
||||
BLO_write_struct(writer, FreestyleLineSet, fls);
|
||||
}
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
BLO_write_struct(writer, ViewLayerAOV, aov);
|
||||
}
|
||||
write_layer_collections(writer, &view_layer->layer_collections);
|
||||
}
|
||||
|
||||
@@ -1899,6 +1932,9 @@ void BKE_view_layer_blend_read_data(BlendDataReader *reader, ViewLayer *view_lay
|
||||
BLO_read_list(reader, &(view_layer->freestyle_config.modules));
|
||||
BLO_read_list(reader, &(view_layer->freestyle_config.linesets));
|
||||
|
||||
BLO_read_list(reader, &view_layer->aovs);
|
||||
BLO_read_data_address(reader, &view_layer->active_aov);
|
||||
|
||||
BLI_listbase_clear(&view_layer->drawdata);
|
||||
view_layer->object_bases_array = NULL;
|
||||
view_layer->object_bases_hash = NULL;
|
||||
@@ -1952,3 +1988,129 @@ void BKE_view_layer_blend_read_lib(BlendLibReader *reader, Library *lib, ViewLay
|
||||
|
||||
IDP_BlendReadLib(reader, view_layer->id_properties);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Shader AOV
|
||||
* \{ */
|
||||
|
||||
static void viewlayer_aov_make_name_unique(ViewLayer *view_layer)
|
||||
{
|
||||
ViewLayerAOV *aov = view_layer->active_aov;
|
||||
if (aov == NULL) {
|
||||
return;
|
||||
}
|
||||
BLI_uniquename(
|
||||
&view_layer->aovs, aov, DATA_("AOV"), '.', offsetof(ViewLayerAOV, name), sizeof(aov->name));
|
||||
}
|
||||
|
||||
static void viewlayer_aov_active_set(ViewLayer *view_layer, ViewLayerAOV *aov)
|
||||
{
|
||||
if (aov != NULL) {
|
||||
BLI_assert(BLI_findindex(&view_layer->aovs, aov) != -1);
|
||||
view_layer->active_aov = aov;
|
||||
}
|
||||
else {
|
||||
view_layer->active_aov = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer)
|
||||
{
|
||||
ViewLayerAOV *aov;
|
||||
aov = MEM_callocN(sizeof(ViewLayerAOV), __func__);
|
||||
aov->type = AOV_TYPE_COLOR;
|
||||
BLI_strncpy(aov->name, DATA_("AOV"), sizeof(aov->name));
|
||||
BLI_addtail(&view_layer->aovs, aov);
|
||||
viewlayer_aov_active_set(view_layer, aov);
|
||||
viewlayer_aov_make_name_unique(view_layer);
|
||||
return aov;
|
||||
}
|
||||
|
||||
void BKE_view_layer_remove_aov(ViewLayer *view_layer, ViewLayerAOV *aov)
|
||||
{
|
||||
BLI_assert(BLI_findindex(&view_layer->aovs, aov) != -1);
|
||||
BLI_assert(aov != NULL);
|
||||
if (view_layer->active_aov == aov) {
|
||||
if (aov->next) {
|
||||
viewlayer_aov_active_set(view_layer, aov->next);
|
||||
}
|
||||
else {
|
||||
viewlayer_aov_active_set(view_layer, aov->prev);
|
||||
}
|
||||
}
|
||||
BLI_freelinkN(&view_layer->aovs, aov);
|
||||
}
|
||||
|
||||
void BKE_view_layer_set_active_aov(ViewLayer *view_layer, ViewLayerAOV *aov)
|
||||
{
|
||||
viewlayer_aov_active_set(view_layer, aov);
|
||||
}
|
||||
|
||||
static void bke_view_layer_verify_aov_cb(void *userdata,
|
||||
Scene *UNUSED(scene),
|
||||
ViewLayer *UNUSED(view_layer),
|
||||
const char *name,
|
||||
int UNUSED(channels),
|
||||
const char *UNUSED(chanid),
|
||||
int UNUSED(type))
|
||||
{
|
||||
GHash *name_count = userdata;
|
||||
void **value_p;
|
||||
void *key = BLI_strdup(name);
|
||||
|
||||
if (!BLI_ghash_ensure_p(name_count, key, &value_p)) {
|
||||
*value_p = POINTER_FROM_INT(1);
|
||||
}
|
||||
else {
|
||||
int value = POINTER_AS_INT(*value_p);
|
||||
value++;
|
||||
*value_p = POINTER_FROM_INT(value);
|
||||
MEM_freeN(key);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the naming and conflicts of the AOVs.
|
||||
*
|
||||
* Name must be unique between all AOVs.
|
||||
* Conflicts with render passes will show a conflict icon. Reason is that switching a render
|
||||
* engine or activating a render pass could lead to other conflicts that wouldn't be that clear
|
||||
* for the user. */
|
||||
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer)
|
||||
{
|
||||
viewlayer_aov_make_name_unique(view_layer);
|
||||
|
||||
GHash *name_count = BLI_ghash_str_new(__func__);
|
||||
RE_engine_update_render_passes(
|
||||
engine, scene, view_layer, bke_view_layer_verify_aov_cb, name_count);
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
void **value_p = BLI_ghash_lookup(name_count, aov->name);
|
||||
int count = POINTER_AS_INT(value_p);
|
||||
SET_FLAG_FROM_TEST(aov->flag, count > 1, AOV_CONFLICT);
|
||||
}
|
||||
BLI_ghash_free(name_count, MEM_freeN, NULL);
|
||||
}
|
||||
|
||||
/* Check if the given view layer has at least one valid AOV. */
|
||||
bool BKE_view_layer_has_valid_aov(ViewLayer *view_layer)
|
||||
{
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
if ((aov->flag & AOV_CONFLICT) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, struct ViewLayerAOV *aov)
|
||||
{
|
||||
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
|
||||
if (BLI_findindex(&view_layer->aovs, aov) != -1) {
|
||||
return view_layer;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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) 2020 by Blender Foundation.
|
||||
*/
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_layer.h"
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "RE_engine.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
namespace blender::bke::tests {
|
||||
|
||||
TEST(view_layer, aov_unique_names)
|
||||
{
|
||||
/* Set Up */
|
||||
CLG_init();
|
||||
BKE_appdir_init();
|
||||
IMB_init();
|
||||
RE_engines_init();
|
||||
|
||||
Scene scene = {{NULL}};
|
||||
IDType_ID_SCE.init_data(&scene.id);
|
||||
ViewLayer *view_layer = static_cast<ViewLayer *>(scene.view_layers.first);
|
||||
|
||||
RenderEngineType *engine_type = RE_engines_find(scene.r.engine);
|
||||
RenderEngine *engine = RE_engine_create(engine_type);
|
||||
|
||||
EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_EQ(view_layer->active_aov, nullptr);
|
||||
|
||||
/* Add an AOV */
|
||||
ViewLayerAOV *aov1 = BKE_view_layer_add_aov(view_layer);
|
||||
BKE_view_layer_verify_aov(engine, &scene, view_layer);
|
||||
EXPECT_EQ(view_layer->active_aov, aov1);
|
||||
EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
|
||||
|
||||
/* Add a second AOV */
|
||||
ViewLayerAOV *aov2 = BKE_view_layer_add_aov(view_layer);
|
||||
BKE_view_layer_verify_aov(engine, &scene, view_layer);
|
||||
EXPECT_EQ(view_layer->active_aov, aov2);
|
||||
EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
|
||||
EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0);
|
||||
EXPECT_TRUE(STREQ(aov1->name, "AOV"));
|
||||
EXPECT_TRUE(STREQ(aov2->name, "AOV.001"));
|
||||
|
||||
/* Revert previous resolution */
|
||||
BLI_strncpy(aov2->name, "AOV", MAX_NAME);
|
||||
BKE_view_layer_verify_aov(engine, &scene, view_layer);
|
||||
EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
|
||||
EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0);
|
||||
EXPECT_TRUE(STREQ(aov1->name, "AOV"));
|
||||
EXPECT_TRUE(STREQ(aov2->name, "AOV.001"));
|
||||
|
||||
/* Resolve by removing AOV resolution */
|
||||
BKE_view_layer_remove_aov(view_layer, aov2);
|
||||
aov2 = NULL;
|
||||
BKE_view_layer_verify_aov(engine, &scene, view_layer);
|
||||
EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
|
||||
|
||||
/* Tear down */
|
||||
RE_engine_free(engine);
|
||||
RE_engines_exit();
|
||||
IDType_ID_SCE.free_data(&scene.id);
|
||||
IMB_exit();
|
||||
BKE_appdir_exit();
|
||||
CLG_exit();
|
||||
}
|
||||
|
||||
static void test_render_pass_conflict(Scene *scene,
|
||||
RenderEngine *engine,
|
||||
ViewLayer *view_layer,
|
||||
ViewLayerAOV *aov,
|
||||
const char *render_pass_name,
|
||||
const char *rna_prop_name)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create(&scene->id, &RNA_ViewLayer, view_layer, &ptr);
|
||||
RNA_boolean_set(&ptr, rna_prop_name, false);
|
||||
|
||||
/* Rename to Conflicting name */
|
||||
BLI_strncpy(aov->name, render_pass_name, MAX_NAME);
|
||||
BKE_view_layer_verify_aov(engine, scene, view_layer);
|
||||
EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0);
|
||||
EXPECT_TRUE(STREQ(aov->name, render_pass_name));
|
||||
|
||||
/* Activate render pass */
|
||||
RNA_boolean_set(&ptr, rna_prop_name, true);
|
||||
BKE_view_layer_verify_aov(engine, scene, view_layer);
|
||||
EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_TRUE((aov->flag & AOV_CONFLICT) != 0);
|
||||
EXPECT_TRUE(STREQ(aov->name, render_pass_name));
|
||||
|
||||
/* Deactivate render pass */
|
||||
RNA_boolean_set(&ptr, rna_prop_name, false);
|
||||
BKE_view_layer_verify_aov(engine, scene, view_layer);
|
||||
EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0);
|
||||
EXPECT_TRUE(STREQ(aov->name, render_pass_name));
|
||||
}
|
||||
|
||||
TEST(view_layer, aov_conflict)
|
||||
{
|
||||
/* Set Up */
|
||||
CLG_init();
|
||||
BKE_appdir_init();
|
||||
IMB_init();
|
||||
RE_engines_init();
|
||||
|
||||
Scene scene = {{NULL}};
|
||||
IDType_ID_SCE.init_data(&scene.id);
|
||||
ViewLayer *view_layer = static_cast<ViewLayer *>(scene.view_layers.first);
|
||||
|
||||
RenderEngineType *engine_type = RE_engines_find(scene.r.engine);
|
||||
RenderEngine *engine = RE_engine_create(engine_type);
|
||||
|
||||
EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_EQ(view_layer->active_aov, nullptr);
|
||||
|
||||
/* Add an AOV */
|
||||
ViewLayerAOV *aov = BKE_view_layer_add_aov(view_layer);
|
||||
BKE_view_layer_verify_aov(engine, &scene, view_layer);
|
||||
EXPECT_EQ(view_layer->active_aov, aov);
|
||||
EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
|
||||
EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0);
|
||||
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "Depth", "use_pass_z");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "Normal", "use_pass_normal");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "Mist", "use_pass_mist");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "Shadow", "use_pass_shadow");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "AO", "use_pass_ambient_occlusion");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "Emit", "use_pass_emit");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "Env", "use_pass_environment");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "DiffDir", "use_pass_diffuse_direct");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "DiffCol", "use_pass_diffuse_color");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "GlossDir", "use_pass_glossy_direct");
|
||||
test_render_pass_conflict(&scene, engine, view_layer, aov, "GlossCol", "use_pass_glossy_color");
|
||||
|
||||
/* Tear down */
|
||||
RE_engine_free(engine);
|
||||
RE_engines_exit();
|
||||
IDType_ID_SCE.free_data(&scene.id);
|
||||
IMB_exit();
|
||||
BKE_appdir_exit();
|
||||
CLG_exit();
|
||||
}
|
||||
|
||||
} // namespace blender::bke::tests
|
||||
@@ -103,7 +103,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase()
|
||||
BKE_blender_atexit();
|
||||
|
||||
BKE_tempdir_session_purge();
|
||||
|
||||
BKE_appdir_exit();
|
||||
CLG_exit();
|
||||
|
||||
testing::Test::TearDownTestCase();
|
||||
|
||||
@@ -240,6 +240,9 @@ void EEVEE_view_layer_data_free(void *storage)
|
||||
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_light);
|
||||
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.emit);
|
||||
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.environment);
|
||||
for (int aov_index = 0; aov_index < MAX_AOVS; aov_index++) {
|
||||
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]);
|
||||
}
|
||||
|
||||
if (sldata->material_cache) {
|
||||
BLI_memblock_destroy(sldata->material_cache, NULL);
|
||||
|
||||
@@ -244,31 +244,31 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
|
||||
/* Create RenderPass UBO */
|
||||
if (sldata->renderpass_ubo.combined == NULL) {
|
||||
EEVEE_RenderPassData data;
|
||||
data = (EEVEE_RenderPassData){true, true, true, true, true, false, false};
|
||||
data = (EEVEE_RenderPassData){true, true, true, true, true, false, false, false, 0};
|
||||
sldata->renderpass_ubo.combined = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.combined");
|
||||
|
||||
data = (EEVEE_RenderPassData){true, false, false, false, false, true, false};
|
||||
data = (EEVEE_RenderPassData){true, false, false, false, false, true, false, false, 0};
|
||||
sldata->renderpass_ubo.diff_color = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.diff_color");
|
||||
|
||||
data = (EEVEE_RenderPassData){true, true, false, false, false, false, false};
|
||||
data = (EEVEE_RenderPassData){true, true, false, false, false, false, false, false, 0};
|
||||
sldata->renderpass_ubo.diff_light = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.diff_light");
|
||||
|
||||
data = (EEVEE_RenderPassData){false, false, true, false, false, false, false};
|
||||
data = (EEVEE_RenderPassData){false, false, true, false, false, false, false, false, 0};
|
||||
sldata->renderpass_ubo.spec_color = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.spec_color");
|
||||
|
||||
data = (EEVEE_RenderPassData){false, false, true, true, false, false, false};
|
||||
data = (EEVEE_RenderPassData){false, false, true, true, false, false, false, false, 0};
|
||||
sldata->renderpass_ubo.spec_light = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.spec_light");
|
||||
|
||||
data = (EEVEE_RenderPassData){false, false, false, false, true, false, false};
|
||||
data = (EEVEE_RenderPassData){false, false, false, false, true, false, false, false, 0};
|
||||
sldata->renderpass_ubo.emit = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.emit");
|
||||
|
||||
data = (EEVEE_RenderPassData){true, true, true, true, true, false, true};
|
||||
data = (EEVEE_RenderPassData){true, true, true, true, true, false, true, false, 0};
|
||||
sldata->renderpass_ubo.environment = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.environment");
|
||||
}
|
||||
@@ -276,6 +276,51 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
|
||||
/* Used combined pass by default. */
|
||||
g_data->renderpass_ubo = sldata->renderpass_ubo.combined;
|
||||
|
||||
{
|
||||
g_data->num_aovs_used = 0;
|
||||
if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) {
|
||||
EEVEE_RenderPassData data = {true, true, true, true, true, false, false, true, 0};
|
||||
if (stl->g_data->aov_hash == EEVEE_AOV_HASH_ALL) {
|
||||
ViewLayer *view_layer = draw_ctx->view_layer;
|
||||
int aov_index = 0;
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
if ((aov->flag & AOV_CONFLICT) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (aov_index == MAX_AOVS) {
|
||||
break;
|
||||
}
|
||||
data.renderPassAOVActive = EEVEE_renderpasses_aov_hash(aov);
|
||||
if (sldata->renderpass_ubo.aovs[aov_index]) {
|
||||
GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[aov_index], &data);
|
||||
}
|
||||
else {
|
||||
sldata->renderpass_ubo.aovs[aov_index] = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.aovs");
|
||||
}
|
||||
aov_index++;
|
||||
}
|
||||
g_data->num_aovs_used = aov_index;
|
||||
}
|
||||
else {
|
||||
/* Rendering a single AOV in the 3d viewport */
|
||||
data.renderPassAOVActive = stl->g_data->aov_hash;
|
||||
if (sldata->renderpass_ubo.aovs[0]) {
|
||||
GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[0], &data);
|
||||
}
|
||||
else {
|
||||
sldata->renderpass_ubo.aovs[0] = GPU_uniformbuf_create_ex(
|
||||
sizeof(data), &data, "renderpass_ubo.aovs");
|
||||
}
|
||||
g_data->num_aovs_used = 1;
|
||||
}
|
||||
}
|
||||
/* Free AOV UBO's that are not in use. */
|
||||
for (int aov_index = g_data->num_aovs_used; aov_index < MAX_AOVS; aov_index++) {
|
||||
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]);
|
||||
}
|
||||
}
|
||||
|
||||
/* HACK: EEVEE_material_get can create a new context. This can only be
|
||||
* done when there is no active framebuffer. We do this here otherwise
|
||||
* `EEVEE_renderpasses_output_init` will fail. It cannot be done in
|
||||
@@ -949,6 +994,11 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
|
||||
material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear);
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
|
||||
for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
|
||||
material_renderpass_init(fbl, &txl->aov_surface_accum[aov_index], texture_format, do_clear);
|
||||
}
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
|
||||
material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear);
|
||||
|
||||
@@ -960,6 +1010,7 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
|
||||
|
||||
static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
|
||||
DRWPass *renderpass,
|
||||
DRWPass *renderpass2,
|
||||
EEVEE_PrivateData *pd,
|
||||
GPUTexture *output_tx,
|
||||
struct GPUUniformBuf *renderpass_option_ubo)
|
||||
@@ -969,6 +1020,9 @@ static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
|
||||
|
||||
pd->renderpass_ubo = renderpass_option_ubo;
|
||||
DRW_draw_pass(renderpass);
|
||||
if (renderpass2) {
|
||||
DRW_draw_pass(renderpass2);
|
||||
}
|
||||
|
||||
GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx);
|
||||
}
|
||||
@@ -983,38 +1037,69 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
|
||||
|
||||
if (fbl->material_accum_fb != NULL) {
|
||||
DRWPass *material_accum_ps = psl->material_accum_ps;
|
||||
DRWPass *background_accum_ps = psl->background_accum_ps;
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
|
||||
material_renderpass_accumulate(
|
||||
fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.environment);
|
||||
fbl, background_accum_ps, NULL, pd, txl->env_accum, sldata->renderpass_ubo.environment);
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) {
|
||||
material_renderpass_accumulate(
|
||||
fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
|
||||
fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) {
|
||||
material_renderpass_accumulate(
|
||||
fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color);
|
||||
material_renderpass_accumulate(fbl,
|
||||
material_accum_ps,
|
||||
NULL,
|
||||
pd,
|
||||
txl->diff_color_accum,
|
||||
sldata->renderpass_ubo.diff_color);
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
|
||||
material_renderpass_accumulate(
|
||||
fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light);
|
||||
material_renderpass_accumulate(fbl,
|
||||
material_accum_ps,
|
||||
NULL,
|
||||
pd,
|
||||
txl->diff_light_accum,
|
||||
sldata->renderpass_ubo.diff_light);
|
||||
|
||||
if (effects->enabled_effects & EFFECT_SSS) {
|
||||
EEVEE_subsurface_output_accumulate(sldata, vedata);
|
||||
}
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
|
||||
material_renderpass_accumulate(
|
||||
fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color);
|
||||
material_renderpass_accumulate(fbl,
|
||||
material_accum_ps,
|
||||
NULL,
|
||||
pd,
|
||||
txl->spec_color_accum,
|
||||
sldata->renderpass_ubo.spec_color);
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
|
||||
material_renderpass_accumulate(
|
||||
fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light);
|
||||
material_renderpass_accumulate(fbl,
|
||||
material_accum_ps,
|
||||
NULL,
|
||||
pd,
|
||||
txl->spec_light_accum,
|
||||
sldata->renderpass_ubo.spec_light);
|
||||
|
||||
if (effects->enabled_effects & EFFECT_SSR) {
|
||||
EEVEE_reflection_output_accumulate(sldata, vedata);
|
||||
}
|
||||
}
|
||||
if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
|
||||
for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
|
||||
material_renderpass_accumulate(fbl,
|
||||
material_accum_ps,
|
||||
background_accum_ps,
|
||||
pd,
|
||||
txl->aov_surface_accum[aov_index],
|
||||
sldata->renderpass_ubo.aovs[aov_index]);
|
||||
}
|
||||
}
|
||||
/* Free unused aov textures. */
|
||||
for (int aov_index = pd->num_aovs_used; aov_index < MAX_AOVS; aov_index++) {
|
||||
DRW_TEXTURE_FREE_SAFE(txl->aov_surface_accum[aov_index]);
|
||||
}
|
||||
|
||||
/* Restore default. */
|
||||
pd->renderpass_ubo = sldata->renderpass_ubo.combined;
|
||||
|
||||
@@ -53,6 +53,7 @@ extern struct DrawEngineType draw_engine_eevee_type;
|
||||
#define MAX_SHADOW_CASCADE 8
|
||||
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
|
||||
#define MAX_BLOOM_STEP 16
|
||||
#define MAX_AOVS 64
|
||||
|
||||
// #define DEBUG_SHADOW_DISTRIBUTION
|
||||
|
||||
@@ -163,8 +164,9 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d)
|
||||
#define EEVEE_RENDERPASSES_MATERIAL \
|
||||
(EEVEE_RENDER_PASS_EMIT | EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_DIFFUSE_LIGHT | \
|
||||
EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_SPECULAR_LIGHT | \
|
||||
EEVEE_RENDER_PASS_ENVIRONMENT)
|
||||
|
||||
EEVEE_RENDER_PASS_ENVIRONMENT | EEVEE_RENDER_PASS_AOV)
|
||||
#define EEVEE_AOV_HASH_ALL -1
|
||||
#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1
|
||||
/* Material shader variations */
|
||||
enum {
|
||||
VAR_MAT_MESH = (1 << 0),
|
||||
@@ -376,6 +378,7 @@ typedef struct EEVEE_TextureList {
|
||||
struct GPUTexture *diff_light_accum;
|
||||
struct GPUTexture *spec_color_accum;
|
||||
struct GPUTexture *spec_light_accum;
|
||||
struct GPUTexture *aov_surface_accum[MAX_AOVS];
|
||||
struct GPUTexture *emit_accum;
|
||||
struct GPUTexture *bloom_accum;
|
||||
struct GPUTexture *ssr_accum;
|
||||
@@ -430,7 +433,9 @@ typedef struct EEVEE_RenderPassData {
|
||||
int renderPassEmit;
|
||||
int renderPassSSSColor;
|
||||
int renderPassEnvironment;
|
||||
int _pad[1];
|
||||
int renderPassAOV;
|
||||
int renderPassAOVActive;
|
||||
int _pad[3];
|
||||
} EEVEE_RenderPassData;
|
||||
|
||||
/* ************ LIGHT UBO ************* */
|
||||
@@ -860,6 +865,7 @@ typedef struct EEVEE_ViewLayerData {
|
||||
struct GPUUniformBuf *spec_color;
|
||||
struct GPUUniformBuf *spec_light;
|
||||
struct GPUUniformBuf *emit;
|
||||
struct GPUUniformBuf *aovs[MAX_AOVS];
|
||||
} renderpass_ubo;
|
||||
|
||||
/* Common Uniform Buffer */
|
||||
@@ -959,6 +965,9 @@ typedef struct EEVEE_PrivateData {
|
||||
/* Renderpasses */
|
||||
/* Bitmask containing the active render_passes */
|
||||
eViewLayerEEVEEPassType render_passes;
|
||||
int aov_hash;
|
||||
int num_aovs_used;
|
||||
|
||||
/* Uniform references that are referenced inside the `renderpass_pass`. They are updated
|
||||
* to reuse the drawing pass and the shading group. */
|
||||
int renderpass_type;
|
||||
@@ -1284,10 +1293,12 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
|
||||
bool post_effect);
|
||||
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
|
||||
EEVEE_Data *vedata,
|
||||
eViewLayerEEVEEPassType renderpass_type);
|
||||
eViewLayerEEVEEPassType renderpass_type,
|
||||
int aov_index);
|
||||
void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
|
||||
void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata);
|
||||
bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata);
|
||||
int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
|
||||
|
||||
/* eevee_temporal_sampling.c */
|
||||
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
|
||||
|
||||
@@ -301,7 +301,7 @@ static void eevee_render_result_normal(RenderLayer *rl,
|
||||
}
|
||||
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_NORMAL) != 0) {
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL);
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL, 0);
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata);
|
||||
}
|
||||
@@ -321,7 +321,7 @@ static void eevee_render_result_z(RenderLayer *rl,
|
||||
}
|
||||
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_Z) != 0) {
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z);
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z, 0);
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata);
|
||||
}
|
||||
@@ -334,7 +334,7 @@ static void eevee_render_result_mist(RenderLayer *rl,
|
||||
EEVEE_ViewLayerData *sldata)
|
||||
{
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_MIST) != 0) {
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST);
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST, 0);
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata);
|
||||
}
|
||||
@@ -347,7 +347,7 @@ static void eevee_render_result_shadow(RenderLayer *rl,
|
||||
EEVEE_ViewLayerData *sldata)
|
||||
{
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_SHADOW) != 0) {
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW);
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW, 0);
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, RE_PASSNAME_SHADOW, 3, vedata->fbl->renderpass_fb, vedata);
|
||||
}
|
||||
@@ -360,7 +360,7 @@ static void eevee_render_result_occlusion(RenderLayer *rl,
|
||||
EEVEE_ViewLayerData *sldata)
|
||||
{
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AO) != 0) {
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO);
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO, 0);
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata);
|
||||
}
|
||||
@@ -378,7 +378,7 @@ static void eevee_render_result_bloom(RenderLayer *rl,
|
||||
}
|
||||
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_BLOOM) != 0) {
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM);
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM, 0);
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, RE_PASSNAME_BLOOM, 3, vedata->fbl->renderpass_fb, vedata);
|
||||
}
|
||||
@@ -386,7 +386,7 @@ static void eevee_render_result_bloom(RenderLayer *rl,
|
||||
|
||||
#define EEVEE_RENDER_RESULT_MATERIAL_PASS(pass_name, eevee_pass_type) \
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_##eevee_pass_type) != 0) { \
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type); \
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type, 0); \
|
||||
eevee_render_color_result( \
|
||||
rl, viewname, rect, RE_PASSNAME_##pass_name, 3, vedata->fbl->renderpass_fb, vedata); \
|
||||
}
|
||||
@@ -462,6 +462,35 @@ static void eevee_render_result_volume_transmittance(RenderLayer *rl,
|
||||
EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_TRANSMITTANCE, VOLUME_TRANSMITTANCE)
|
||||
}
|
||||
|
||||
static void eevee_render_result_aovs(RenderLayer *rl,
|
||||
const char *viewname,
|
||||
const rcti *rect,
|
||||
EEVEE_Data *vedata,
|
||||
EEVEE_ViewLayerData *sldata)
|
||||
{
|
||||
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) {
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
ViewLayer *view_layer = draw_ctx->view_layer;
|
||||
int aov_index = 0;
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
if ((aov->flag & AOV_CONFLICT) != 0) {
|
||||
continue;
|
||||
}
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AOV, aov_index);
|
||||
switch (aov->type) {
|
||||
case AOV_TYPE_COLOR:
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, aov->name, 4, vedata->fbl->renderpass_fb, vedata);
|
||||
break;
|
||||
case AOV_TYPE_VALUE:
|
||||
eevee_render_color_result(
|
||||
rl, viewname, rect, aov->name, 1, vedata->fbl->renderpass_fb, vedata);
|
||||
}
|
||||
aov_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef EEVEE_RENDER_RESULT_MATERIAL_PASS
|
||||
|
||||
static void eevee_render_draw_background(EEVEE_Data *vedata)
|
||||
@@ -641,6 +670,7 @@ void EEVEE_render_read_result(EEVEE_Data *vedata,
|
||||
eevee_render_result_bloom(rl, viewname, rect, vedata, sldata);
|
||||
eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata);
|
||||
eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata);
|
||||
eevee_render_result_aovs(rl, viewname, rect, vedata, sldata);
|
||||
}
|
||||
|
||||
void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
|
||||
@@ -675,6 +705,22 @@ void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *v
|
||||
CHECK_PASS_EEVEE(VOLUME_TRANSMITTANCE, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_EEVEE(BLOOM, SOCK_RGBA, 3, "RGB");
|
||||
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
if ((aov->flag & AOV_CONFLICT) != 0) {
|
||||
continue;
|
||||
}
|
||||
switch (aov->type) {
|
||||
case AOV_TYPE_COLOR:
|
||||
RE_engine_register_pass(engine, scene, view_layer, aov->name, 4, "RGBA", SOCK_RGBA);
|
||||
break;
|
||||
case AOV_TYPE_VALUE:
|
||||
RE_engine_register_pass(engine, scene, view_layer, aov->name, 1, "X", SOCK_FLOAT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef CHECK_PASS_LEGACY
|
||||
#undef CHECK_PASS_EEVEE
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "BKE_global.h" /* for G.debug_value */
|
||||
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_string_utils.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
@@ -36,12 +37,13 @@
|
||||
typedef enum eRenderPassPostProcessType {
|
||||
PASS_POST_UNDEFINED = 0,
|
||||
PASS_POST_ACCUMULATED_COLOR = 1,
|
||||
PASS_POST_ACCUMULATED_LIGHT = 2,
|
||||
PASS_POST_ACCUMULATED_VALUE = 3,
|
||||
PASS_POST_DEPTH = 4,
|
||||
PASS_POST_AO = 5,
|
||||
PASS_POST_NORMAL = 6,
|
||||
PASS_POST_TWO_LIGHT_BUFFERS = 7,
|
||||
PASS_POST_ACCUMULATED_COLOR_ALPHA = 2,
|
||||
PASS_POST_ACCUMULATED_LIGHT = 3,
|
||||
PASS_POST_ACCUMULATED_VALUE = 4,
|
||||
PASS_POST_DEPTH = 5,
|
||||
PASS_POST_AO = 6,
|
||||
PASS_POST_NORMAL = 7,
|
||||
PASS_POST_TWO_LIGHT_BUFFERS = 8,
|
||||
} eRenderPassPostProcessType;
|
||||
|
||||
/* bitmask containing all renderpasses that need post-processing */
|
||||
@@ -70,6 +72,15 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
|
||||
return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
|
||||
}
|
||||
|
||||
/* Calculate the hash for an AOV. The least significant bit is used to store the AOV
|
||||
* type the rest of the bits are used for the name hash. */
|
||||
int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov)
|
||||
{
|
||||
int hash = BLI_hash_string(aov->name);
|
||||
SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void EEVEE_renderpasses_init(EEVEE_Data *vedata)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
@@ -81,10 +92,24 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata)
|
||||
if (v3d) {
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
eViewLayerEEVEEPassType render_pass = v3d->shading.render_pass;
|
||||
g_data->aov_hash = 0;
|
||||
|
||||
if (render_pass == EEVEE_RENDER_PASS_BLOOM &&
|
||||
((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
|
||||
render_pass = EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
if (render_pass == EEVEE_RENDER_PASS_AOV) {
|
||||
ViewLayerAOV *aov = BLI_findstring(
|
||||
&view_layer->aovs, v3d->shading.aov_name, offsetof(ViewLayerAOV, name));
|
||||
if (aov != NULL) {
|
||||
g_data->aov_hash = EEVEE_renderpasses_aov_hash(aov);
|
||||
}
|
||||
else {
|
||||
/* AOV not found in view layer. */
|
||||
render_pass = EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
}
|
||||
|
||||
g_data->render_passes = render_pass;
|
||||
}
|
||||
else {
|
||||
@@ -110,10 +135,14 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata)
|
||||
ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT)
|
||||
|
||||
#undef ENABLE_FROM_LEGACY
|
||||
if (DRW_state_is_image_render() && !BLI_listbase_is_empty(&view_layer->aovs)) {
|
||||
enabled_render_passes |= EEVEE_RENDER_PASS_AOV;
|
||||
g_data->aov_hash = EEVEE_AOV_HASH_ALL;
|
||||
}
|
||||
|
||||
g_data->render_passes = (enabled_render_passes & EEVEE_RENDERPASSES_ALL) |
|
||||
EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
|
||||
EEVEE_material_renderpasses_init(vedata);
|
||||
}
|
||||
|
||||
@@ -216,7 +245,8 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
|
||||
* After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */
|
||||
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
|
||||
EEVEE_Data *vedata,
|
||||
eViewLayerEEVEEPassType renderpass_type)
|
||||
eViewLayerEEVEEPassType renderpass_type,
|
||||
int aov_index)
|
||||
{
|
||||
EEVEE_PassList *psl = vedata->psl;
|
||||
EEVEE_TextureList *txl = vedata->txl;
|
||||
@@ -311,6 +341,11 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EEVEE_RENDER_PASS_AOV: {
|
||||
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR_ALPHA;
|
||||
g_data->renderpass_input = txl->aov_surface_accum[aov_index];
|
||||
break;
|
||||
}
|
||||
case EEVEE_RENDER_PASS_BLOOM: {
|
||||
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
|
||||
g_data->renderpass_input = txl->bloom_accum;
|
||||
@@ -392,7 +427,7 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
||||
}
|
||||
|
||||
if (is_valid) {
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, render_pass);
|
||||
EEVEE_renderpasses_postprocess(sldata, vedata, render_pass, 0);
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
DRW_transform_none(txl->renderpass);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Resources
|
||||
@@ -12,6 +13,8 @@ layout(std140) uniform renderpass_block
|
||||
bool renderPassEmit;
|
||||
bool renderPassSSSColor;
|
||||
bool renderPassEnvironment;
|
||||
bool renderPassAOV;
|
||||
int renderPassAOVActive;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
@@ -40,4 +43,14 @@ vec3 render_pass_emission_mask(vec3 emission_light)
|
||||
return renderPassEmit ? emission_light : vec3(0.0);
|
||||
}
|
||||
|
||||
bool render_pass_aov_is_color()
|
||||
{
|
||||
return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0;
|
||||
}
|
||||
|
||||
int render_pass_aov_hash()
|
||||
{
|
||||
return renderPassAOVActive & ~EEVEE_AOV_HASH_COLOR_TYPE_MASK;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
|
||||
#define PASS_POST_UNDEFINED 0
|
||||
#define PASS_POST_ACCUMULATED_COLOR 1
|
||||
#define PASS_POST_ACCUMULATED_LIGHT 2
|
||||
#define PASS_POST_ACCUMULATED_VALUE 3
|
||||
#define PASS_POST_DEPTH 4
|
||||
#define PASS_POST_AO 5
|
||||
#define PASS_POST_NORMAL 6
|
||||
#define PASS_POST_TWO_LIGHT_BUFFERS 7
|
||||
#define PASS_POST_ACCUMULATED_COLOR_ALPHA 2
|
||||
#define PASS_POST_ACCUMULATED_LIGHT 3
|
||||
#define PASS_POST_ACCUMULATED_VALUE 4
|
||||
#define PASS_POST_DEPTH 5
|
||||
#define PASS_POST_AO 6
|
||||
#define PASS_POST_NORMAL 7
|
||||
#define PASS_POST_TWO_LIGHT_BUFFERS 8
|
||||
|
||||
uniform int postProcessType;
|
||||
uniform int currentSample;
|
||||
@@ -55,7 +56,7 @@ vec3 safe_divide_even_color(vec3 a, vec3 b)
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 color;
|
||||
vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
|
||||
if (postProcessType == PASS_POST_DEPTH) {
|
||||
@@ -66,11 +67,11 @@ void main()
|
||||
else {
|
||||
depth = -get_view_z_from_depth(depth);
|
||||
}
|
||||
color = vec3(depth);
|
||||
color.rgb = vec3(depth);
|
||||
}
|
||||
else if (postProcessType == PASS_POST_AO) {
|
||||
float ao_accum = texelFetch(inputBuffer, texel, 0).r;
|
||||
color = vec3(min(1.0, ao_accum / currentSample));
|
||||
color.rgb = vec3(min(1.0, ao_accum / currentSample));
|
||||
}
|
||||
else if (postProcessType == PASS_POST_NORMAL) {
|
||||
float depth = texelFetch(depthBuffer, texel, 0).r;
|
||||
@@ -80,35 +81,39 @@ void main()
|
||||
if (depth != 1.0 && any(notEqual(encoded_normal, vec2(0.0)))) {
|
||||
vec3 decoded_normal = normal_decode(texelFetch(inputBuffer, texel, 0).rg, vec3(0.0));
|
||||
vec3 world_normal = mat3(ViewMatrixInverse) * decoded_normal;
|
||||
color = world_normal;
|
||||
color.rgb = world_normal;
|
||||
}
|
||||
else {
|
||||
color = vec3(0.0);
|
||||
color.rgb = vec3(0.0);
|
||||
}
|
||||
}
|
||||
else if (postProcessType == PASS_POST_ACCUMULATED_VALUE) {
|
||||
float accumulated_value = texelFetch(inputBuffer, texel, 0).r;
|
||||
color = vec3(accumulated_value / currentSample);
|
||||
color.rgb = vec3(accumulated_value / currentSample);
|
||||
}
|
||||
else if (postProcessType == PASS_POST_ACCUMULATED_COLOR) {
|
||||
vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb;
|
||||
color.rgb = (accumulated_color / currentSample);
|
||||
}
|
||||
else if (postProcessType == PASS_POST_ACCUMULATED_COLOR_ALPHA) {
|
||||
vec4 accumulated_color = texelFetch(inputBuffer, texel, 0);
|
||||
color = (accumulated_color / currentSample);
|
||||
}
|
||||
else if (postProcessType == PASS_POST_ACCUMULATED_LIGHT) {
|
||||
vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb;
|
||||
vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb;
|
||||
color = safe_divide_even_color(accumulated_light, accumulated_color);
|
||||
color.rgb = safe_divide_even_color(accumulated_light, accumulated_color);
|
||||
}
|
||||
else if (postProcessType == PASS_POST_TWO_LIGHT_BUFFERS) {
|
||||
vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb +
|
||||
texelFetch(inputSecondLightBuffer, texel, 0).rgb;
|
||||
vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb;
|
||||
color = safe_divide_even_color(accumulated_light, accumulated_color);
|
||||
color.rgb = safe_divide_even_color(accumulated_light, accumulated_color);
|
||||
}
|
||||
else {
|
||||
/* Output error color: Unknown how to post process this pass. */
|
||||
color = vec3(1.0, 0.0, 1.0);
|
||||
color.rgb = vec3(1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
fragColor = color;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
|
||||
|
||||
void SCENE_OT_view_layer_add(struct wmOperatorType *ot);
|
||||
void SCENE_OT_view_layer_remove(struct wmOperatorType *ot);
|
||||
void SCENE_OT_view_layer_add_aov(struct wmOperatorType *ot);
|
||||
void SCENE_OT_view_layer_remove_aov(struct wmOperatorType *ot);
|
||||
|
||||
void SCENE_OT_light_cache_bake(struct wmOperatorType *ot);
|
||||
void SCENE_OT_light_cache_free(struct wmOperatorType *ot);
|
||||
|
||||
@@ -53,6 +53,8 @@ void ED_operatortypes_render(void)
|
||||
|
||||
WM_operatortype_append(SCENE_OT_view_layer_add);
|
||||
WM_operatortype_append(SCENE_OT_view_layer_remove);
|
||||
WM_operatortype_append(SCENE_OT_view_layer_add_aov);
|
||||
WM_operatortype_append(SCENE_OT_view_layer_remove_aov);
|
||||
|
||||
WM_operatortype_append(SCENE_OT_render_view_add);
|
||||
WM_operatortype_append(SCENE_OT_render_view_remove);
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "RE_engine.h"
|
||||
#include "RE_pipeline.h"
|
||||
|
||||
#include "engines/eevee/eevee_lightcache.h"
|
||||
@@ -1013,6 +1014,93 @@ void SCENE_OT_view_layer_remove(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name View Layer Add AOV Operator
|
||||
* \{ */
|
||||
|
||||
static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
BKE_view_layer_add_aov(view_layer);
|
||||
|
||||
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
|
||||
if (engine_type->update_render_passes) {
|
||||
RenderEngine *engine = RE_engine_create(engine_type);
|
||||
if (engine) {
|
||||
BKE_view_layer_verify_aov(engine, scene, view_layer);
|
||||
}
|
||||
RE_engine_free(engine);
|
||||
engine = NULL;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&scene->id, 0);
|
||||
DEG_relations_tag_update(CTX_data_main(C));
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void SCENE_OT_view_layer_add_aov(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add AOV";
|
||||
ot->idname = "SCENE_OT_view_layer_add_aov";
|
||||
ot->description = "Add a Shader AOV";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = view_layer_add_aov_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name View Layer Remove AOV Operator
|
||||
* \{ */
|
||||
|
||||
static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
BKE_view_layer_remove_aov(view_layer, view_layer->active_aov);
|
||||
|
||||
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
|
||||
if (engine_type->update_render_passes) {
|
||||
RenderEngine *engine = RE_engine_create(engine_type);
|
||||
if (engine) {
|
||||
BKE_view_layer_verify_aov(engine, scene, view_layer);
|
||||
}
|
||||
RE_engine_free(engine);
|
||||
engine = NULL;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&scene->id, 0);
|
||||
DEG_relations_tag_update(CTX_data_main(C));
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void SCENE_OT_view_layer_remove_aov(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove AOV";
|
||||
ot->idname = "SCENE_OT_view_layer_remove_aov";
|
||||
ot->description = "Remove Active AOV";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = view_layer_remove_aov_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Light Cache Bake Operator
|
||||
* \{ */
|
||||
|
||||
@@ -313,6 +313,7 @@ data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC)
|
||||
data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC)
|
||||
data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC)
|
||||
data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC)
|
||||
data_to_c_simple(shaders/material/gpu_shader_material_output_aov.glsl SRC)
|
||||
data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC)
|
||||
data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC)
|
||||
data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC)
|
||||
|
||||
@@ -173,6 +173,7 @@ GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat,
|
||||
const int index);
|
||||
|
||||
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
|
||||
void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash);
|
||||
|
||||
void GPU_material_sss_profile_create(GPUMaterial *material,
|
||||
float radii[3],
|
||||
|
||||
@@ -411,7 +411,7 @@ static void codegen_declare_tmps(DynStr *ds, GPUNodeGraph *graph)
|
||||
BLI_dynstr_append(ds, "\n");
|
||||
}
|
||||
|
||||
static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *finaloutput)
|
||||
static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph)
|
||||
{
|
||||
LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
|
||||
BLI_dynstr_appendf(ds, " %s(", node->name);
|
||||
@@ -509,8 +509,11 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f
|
||||
|
||||
BLI_dynstr_append(ds, ");\n");
|
||||
}
|
||||
}
|
||||
|
||||
BLI_dynstr_appendf(ds, "\n return tmp%d;\n", finaloutput->id);
|
||||
static void codegen_final_output(DynStr *ds, GPUOutput *finaloutput)
|
||||
{
|
||||
BLI_dynstr_appendf(ds, "return tmp%d;\n", finaloutput->id);
|
||||
}
|
||||
|
||||
static char *code_generate_fragment(GPUMaterial *material,
|
||||
@@ -593,7 +596,35 @@ static char *code_generate_fragment(GPUMaterial *material,
|
||||
}
|
||||
|
||||
codegen_declare_tmps(ds, graph);
|
||||
codegen_call_functions(ds, graph, graph->outlink->output);
|
||||
codegen_call_functions(ds, graph);
|
||||
|
||||
BLI_dynstr_append(ds, " #ifndef VOLUMETRICS\n");
|
||||
BLI_dynstr_append(ds, " if (renderPassAOV) {\n");
|
||||
BLI_dynstr_append(ds, " switch (render_pass_aov_hash()) {\n");
|
||||
GSet *aovhashes_added = BLI_gset_int_new(__func__);
|
||||
LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
|
||||
void *aov_key = POINTER_FROM_INT(aovlink->hash);
|
||||
if (BLI_gset_haskey(aovhashes_added, aov_key)) {
|
||||
continue;
|
||||
}
|
||||
BLI_dynstr_appendf(ds, " case %d: {\n ", aovlink->hash);
|
||||
codegen_final_output(ds, aovlink->outlink->output);
|
||||
BLI_dynstr_append(ds, " }\n");
|
||||
BLI_gset_add(aovhashes_added, aov_key);
|
||||
}
|
||||
BLI_gset_free(aovhashes_added, NULL);
|
||||
BLI_dynstr_append(ds, " default: {\n");
|
||||
BLI_dynstr_append(ds, " Closure no_aov = CLOSURE_DEFAULT;\n");
|
||||
BLI_dynstr_append(ds, " no_aov.holdout = 1.0;\n");
|
||||
BLI_dynstr_append(ds, " return no_aov;\n");
|
||||
BLI_dynstr_append(ds, " }\n");
|
||||
BLI_dynstr_append(ds, " }\n");
|
||||
BLI_dynstr_append(ds, " } else {\n");
|
||||
BLI_dynstr_append(ds, " #else /* VOLUMETRICS */\n");
|
||||
BLI_dynstr_append(ds, " {\n");
|
||||
BLI_dynstr_append(ds, " #endif /* VOLUMETRICS */\n ");
|
||||
codegen_final_output(ds, graph->outlink->output);
|
||||
BLI_dynstr_append(ds, " }\n");
|
||||
|
||||
BLI_dynstr_append(ds, "}\n");
|
||||
|
||||
|
||||
@@ -597,6 +597,14 @@ void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash)
|
||||
{
|
||||
GPUNodeGraphOutputLink *aov_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__);
|
||||
aov_link->outlink = link;
|
||||
aov_link->hash = hash;
|
||||
BLI_addtail(&material->graph.outlink_aovs, aov_link);
|
||||
}
|
||||
|
||||
GPUNodeGraph *gpu_material_node_graph(GPUMaterial *material)
|
||||
{
|
||||
return &material->graph;
|
||||
|
||||
@@ -84,6 +84,7 @@ extern char datatoc_gpu_shader_material_noise_glsl[];
|
||||
extern char datatoc_gpu_shader_material_normal_glsl[];
|
||||
extern char datatoc_gpu_shader_material_normal_map_glsl[];
|
||||
extern char datatoc_gpu_shader_material_object_info_glsl[];
|
||||
extern char datatoc_gpu_shader_material_output_aov_glsl[];
|
||||
extern char datatoc_gpu_shader_material_output_material_glsl[];
|
||||
extern char datatoc_gpu_shader_material_output_world_glsl[];
|
||||
extern char datatoc_gpu_shader_material_particle_info_glsl[];
|
||||
@@ -354,6 +355,11 @@ static GPUMaterialLibrary gpu_shader_material_object_info_library = {
|
||||
.dependencies = {NULL},
|
||||
};
|
||||
|
||||
static GPUMaterialLibrary gpu_shader_material_output_aov_library = {
|
||||
.code = datatoc_gpu_shader_material_output_aov_glsl,
|
||||
.dependencies = {NULL},
|
||||
};
|
||||
|
||||
static GPUMaterialLibrary gpu_shader_material_output_material_library = {
|
||||
.code = datatoc_gpu_shader_material_output_material_glsl,
|
||||
.dependencies = {NULL},
|
||||
@@ -619,6 +625,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
|
||||
&gpu_shader_material_normal_library,
|
||||
&gpu_shader_material_normal_map_library,
|
||||
&gpu_shader_material_object_info_library,
|
||||
&gpu_shader_material_output_aov_library,
|
||||
&gpu_shader_material_output_material_library,
|
||||
&gpu_shader_material_output_world_library,
|
||||
&gpu_shader_material_particle_info_library,
|
||||
|
||||
@@ -805,6 +805,7 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
|
||||
/* Free both node graph and requested attributes and textures. */
|
||||
void gpu_node_graph_free(GPUNodeGraph *graph)
|
||||
{
|
||||
BLI_freelistN(&graph->outlink_aovs);
|
||||
gpu_node_graph_free_nodes(graph);
|
||||
|
||||
LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
|
||||
@@ -847,6 +848,9 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
|
||||
}
|
||||
|
||||
gpu_nodes_tag(graph->outlink);
|
||||
LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
|
||||
gpu_nodes_tag(aovlink->outlink);
|
||||
}
|
||||
|
||||
for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) {
|
||||
next = node->next;
|
||||
|
||||
@@ -141,12 +141,20 @@ typedef struct GPUInput {
|
||||
};
|
||||
} GPUInput;
|
||||
|
||||
typedef struct GPUNodeGraphOutputLink {
|
||||
struct GPUNodeGraphOutputLink *next, *prev;
|
||||
int hash;
|
||||
GPUNodeLink *outlink;
|
||||
} GPUNodeGraphOutputLink;
|
||||
|
||||
typedef struct GPUNodeGraph {
|
||||
/* Nodes */
|
||||
ListBase nodes;
|
||||
|
||||
/* Output. */
|
||||
/* Main Output. */
|
||||
GPUNodeLink *outlink;
|
||||
/* List of GPUNodeGraphOutputLink */
|
||||
ListBase outlink_aovs;
|
||||
|
||||
/* Requested attributes and textures. */
|
||||
ListBase attributes;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
void node_output_aov(vec4 color, float value, out Closure result)
|
||||
{
|
||||
result = CLOSURE_DEFAULT;
|
||||
#ifndef VOLUMETRICS
|
||||
if (render_pass_aov_is_color()) {
|
||||
result.radiance = color.rgb;
|
||||
}
|
||||
else {
|
||||
result.radiance = vec3(value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -47,8 +47,20 @@ typedef enum eViewLayerEEVEEPassType {
|
||||
EEVEE_RENDER_PASS_SHADOW = (1 << 12),
|
||||
EEVEE_RENDER_PASS_AO = (1 << 13),
|
||||
EEVEE_RENDER_PASS_BLOOM = (1 << 14),
|
||||
EEVEE_RENDER_PASS_AOV = (1 << 15),
|
||||
} eViewLayerEEVEEPassType;
|
||||
#define EEVEE_RENDER_PASS_MAX_BIT 15
|
||||
#define EEVEE_RENDER_PASS_MAX_BIT 16
|
||||
|
||||
/* ViewLayerAOV.type */
|
||||
typedef enum eViewLayerAOVType {
|
||||
AOV_TYPE_VALUE = 0,
|
||||
AOV_TYPE_COLOR = 1,
|
||||
} eViewLayerAOVType;
|
||||
|
||||
/* ViewLayerAOV.type */
|
||||
typedef enum eViewLayerAOVFlag {
|
||||
AOV_CONFLICT = (1 << 0),
|
||||
} eViewLayerAOVFlag;
|
||||
|
||||
typedef struct Base {
|
||||
struct Base *next, *prev;
|
||||
@@ -104,6 +116,17 @@ typedef struct ViewLayerEEVEE {
|
||||
int _pad[1];
|
||||
} ViewLayerEEVEE;
|
||||
|
||||
/* AOV Renderpass definition. */
|
||||
typedef struct ViewLayerAOV {
|
||||
struct ViewLayerAOV *next, *prev;
|
||||
|
||||
/* Name of the AOV */
|
||||
char name[64];
|
||||
int flag;
|
||||
/* Type of AOV (color/value)
|
||||
* matches `eViewLayerAOVType` */
|
||||
int type;
|
||||
} ViewLayerAOV;
|
||||
typedef struct ViewLayer {
|
||||
struct ViewLayer *next, *prev;
|
||||
/** MAX_NAME. */
|
||||
@@ -136,6 +159,10 @@ typedef struct ViewLayer {
|
||||
struct FreestyleConfig freestyle_config;
|
||||
struct ViewLayerEEVEE eevee;
|
||||
|
||||
/* List containing the `ViewLayerAOV`s */
|
||||
ListBase aovs;
|
||||
ViewLayerAOV *active_aov;
|
||||
|
||||
/* Runtime data */
|
||||
/** ViewLayerEngineData. */
|
||||
ListBase drawdata;
|
||||
|
||||
@@ -192,6 +192,7 @@ typedef struct View3DShading {
|
||||
|
||||
/* Render pass displayed in the viewport. Is an `eScenePassType` where one bit is set */
|
||||
int render_pass;
|
||||
char aov_name[64];
|
||||
|
||||
struct IDProperty *prop;
|
||||
void *_pad2;
|
||||
|
||||
@@ -60,6 +60,7 @@ extern StructRNA RNA_AnimData;
|
||||
extern StructRNA RNA_AnimViz;
|
||||
extern StructRNA RNA_AnimVizMotionPaths;
|
||||
extern StructRNA RNA_AnyType;
|
||||
extern StructRNA RNA_AOV;
|
||||
extern StructRNA RNA_Area;
|
||||
extern StructRNA RNA_AreaLight;
|
||||
extern StructRNA RNA_Armature;
|
||||
|
||||
@@ -345,6 +345,10 @@ void rna_ViewLayer_material_override_update(struct Main *bmain,
|
||||
void rna_ViewLayer_pass_update(struct Main *bmain,
|
||||
struct Scene *activescene,
|
||||
struct PointerRNA *ptr);
|
||||
void rna_ViewLayer_active_aov_index_range(
|
||||
PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax);
|
||||
int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr);
|
||||
void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value);
|
||||
|
||||
/* named internal so as not to conflict with obj.update() rna func */
|
||||
void rna_Object_internal_update_data(struct Main *bmain,
|
||||
|
||||
@@ -152,7 +152,18 @@ static void rna_ViewLayer_update_render_passes(ID *id)
|
||||
if (scene->nodetree) {
|
||||
ntreeCompositUpdateRLayers(scene->nodetree);
|
||||
}
|
||||
}
|
||||
|
||||
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
|
||||
if (engine_type->update_render_passes) {
|
||||
RenderEngine *engine = RE_engine_create(engine_type);
|
||||
if (engine) {
|
||||
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
|
||||
BKE_view_layer_verify_aov(engine, scene, view_layer);
|
||||
}
|
||||
}
|
||||
RE_engine_free(engine);
|
||||
engine = NULL;
|
||||
}}
|
||||
|
||||
static PointerRNA rna_ViewLayer_objects_get(CollectionPropertyIterator *iter)
|
||||
{
|
||||
|
||||
@@ -529,6 +529,12 @@ const EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_view_layer_aov_type_items[] = {
|
||||
{AOV_TYPE_COLOR, "COLOR", 0, "Color", ""},
|
||||
{AOV_TYPE_VALUE, "VALUE", 0, "Value", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
#ifndef RNA_RUNTIME
|
||||
static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
|
||||
/* interpolation */
|
||||
@@ -1779,6 +1785,27 @@ void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr)
|
||||
ntreeCompositUpdateRLayers(scene->nodetree);
|
||||
}
|
||||
|
||||
ViewLayer *view_layer = NULL;
|
||||
if (ptr->type == &RNA_ViewLayer) {
|
||||
view_layer = (ViewLayer *)ptr->data;
|
||||
}
|
||||
else if (ptr->type == &RNA_AOV) {
|
||||
ViewLayerAOV *aov = (ViewLayerAOV *)ptr->data;
|
||||
view_layer = BKE_view_layer_find_with_aov(scene, aov);
|
||||
}
|
||||
|
||||
if (view_layer) {
|
||||
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
|
||||
if (engine_type->update_render_passes) {
|
||||
RenderEngine *engine = RE_engine_create(engine_type);
|
||||
if (engine) {
|
||||
BKE_view_layer_verify_aov(engine, scene, view_layer);
|
||||
}
|
||||
RE_engine_free(engine);
|
||||
engine = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rna_Scene_glsl_update(bmain, activescene, ptr);
|
||||
}
|
||||
|
||||
@@ -2397,6 +2424,28 @@ static void rna_ViewLayer_remove(
|
||||
}
|
||||
}
|
||||
|
||||
void rna_ViewLayer_active_aov_index_range(
|
||||
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
|
||||
{
|
||||
ViewLayer *view_layer = (ViewLayer *)ptr->data;
|
||||
|
||||
*min = 0;
|
||||
*max = max_ii(0, BLI_listbase_count(&view_layer->aovs) - 1);
|
||||
}
|
||||
|
||||
int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr)
|
||||
{
|
||||
ViewLayer *view_layer = (ViewLayer *)ptr->data;
|
||||
return BLI_findindex(&view_layer->aovs, view_layer->active_aov);
|
||||
}
|
||||
|
||||
void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
ViewLayer *view_layer = (ViewLayer *)ptr->data;
|
||||
ViewLayerAOV *aov = BLI_findlink(&view_layer->aovs, value);
|
||||
view_layer->active_aov = aov;
|
||||
}
|
||||
|
||||
/* Fake value, used internally (not saved to DNA). */
|
||||
# define V3D_ORIENT_DEFAULT -1
|
||||
|
||||
@@ -3963,6 +4012,33 @@ static void rna_def_view_layer_eevee(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
|
||||
}
|
||||
|
||||
static void rna_def_view_layer_aov(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
srna = RNA_def_struct(brna, "AOV", NULL);
|
||||
RNA_def_struct_sdna(srna, "ViewLayerAOV");
|
||||
RNA_def_struct_ui_text(srna, "Shader AOV", "");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "name");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Name of the AOV");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", AOV_CONFLICT);
|
||||
RNA_def_property_ui_text(prop, "Valid", "Is the name of the AOV conflicting");
|
||||
|
||||
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, rna_enum_view_layer_aov_type_items);
|
||||
RNA_def_property_enum_default(prop, AOV_TYPE_COLOR);
|
||||
RNA_def_property_ui_text(prop, "Type", "Data type of the AOV");
|
||||
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;
|
||||
@@ -4013,6 +4089,24 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene)
|
||||
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");
|
||||
|
||||
prop = RNA_def_property(srna, "aovs", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "aovs", NULL);
|
||||
RNA_def_property_struct_type(prop, "AOV");
|
||||
RNA_def_property_ui_text(prop, "Shader AOV", "");
|
||||
|
||||
prop = RNA_def_property(srna, "active_aov", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "AOV");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Shader AOV", "Active AOV");
|
||||
|
||||
prop = RNA_def_property(srna, "active_aov_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_ViewLayer_active_aov_index_get",
|
||||
"rna_ViewLayer_active_aov_index_set",
|
||||
"rna_ViewLayer_active_aov_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active AOV Index", "Index of active aov");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
|
||||
}
|
||||
|
||||
/* layer options */
|
||||
@@ -7848,6 +7942,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_aov(brna);
|
||||
rna_def_view_layer_eevee(brna);
|
||||
rna_def_scene_gpencil(brna);
|
||||
RNA_define_animate_sdna(true);
|
||||
|
||||
@@ -426,6 +426,9 @@ static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] =
|
||||
{EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
|
||||
{EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""},
|
||||
|
||||
{0, "", ICON_NONE, "Shader AOV", ""},
|
||||
{EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""},
|
||||
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -1065,6 +1068,19 @@ static Scene *rna_3DViewShading_scene(PointerRNA *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
static ViewLayer *rna_3DViewShading_view_layer(PointerRNA *ptr)
|
||||
{
|
||||
/* Get scene, depends if using 3D view or OpenGL render settings. */
|
||||
ID *id = ptr->owner_id;
|
||||
if (GS(id->name) == ID_SCE) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
bScreen *screen = (bScreen *)ptr->owner_id;
|
||||
return WM_windows_view_layer_get_from_screen(G_MAIN->wm.first, screen);
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_3DViewShading_type_get(PointerRNA *ptr)
|
||||
{
|
||||
/* Available shading types depend on render engine. */
|
||||
@@ -1292,15 +1308,33 @@ static const EnumPropertyItem *rna_3DViewShading_render_pass_itemf(bContext *C,
|
||||
bool *r_free)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
const bool bloom_enabled = scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED;
|
||||
const bool aov_available = BKE_view_layer_has_valid_aov(view_layer);
|
||||
|
||||
int totitem = 0;
|
||||
EnumPropertyItem *result = NULL;
|
||||
EnumPropertyItem aov_template;
|
||||
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 (!((!bloom_enabled &&
|
||||
(item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))))) {
|
||||
if (item->value == EEVEE_RENDER_PASS_AOV) {
|
||||
aov_template.value = item->value;
|
||||
aov_template.icon = 0;
|
||||
aov_template.description = item->description;
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
if ((aov->flag & AOV_CONFLICT) != 0) {
|
||||
continue;
|
||||
}
|
||||
aov_template.name = aov->name;
|
||||
aov_template.identifier = aov->name;
|
||||
RNA_enum_item_add(&result, &totitem, &aov_template);
|
||||
aov_template.value++;
|
||||
}
|
||||
}
|
||||
else if (!((!bloom_enabled &&
|
||||
(item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))) ||
|
||||
(!aov_available && STREQ(item->name, "Shader AOV")))) {
|
||||
RNA_enum_item_add(&result, &totitem, item);
|
||||
}
|
||||
}
|
||||
@@ -1314,14 +1348,58 @@ static int rna_3DViewShading_render_pass_get(PointerRNA *ptr)
|
||||
View3DShading *shading = (View3DShading *)ptr->data;
|
||||
eViewLayerEEVEEPassType result = shading->render_pass;
|
||||
Scene *scene = rna_3DViewShading_scene(ptr);
|
||||
ViewLayer *view_layer = rna_3DViewShading_view_layer(ptr);
|
||||
|
||||
if (result == EEVEE_RENDER_PASS_BLOOM && ((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
|
||||
result = EEVEE_RENDER_PASS_COMBINED;
|
||||
return EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
else if (result == EEVEE_RENDER_PASS_AOV) {
|
||||
if (!view_layer) {
|
||||
return EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
const int aov_index = BLI_findstringindex(
|
||||
&view_layer->aovs, shading->aov_name, offsetof(ViewLayerAOV, name));
|
||||
if (aov_index == -1) {
|
||||
return EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
return result + aov_index;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void rna_3DViewShading_render_pass_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
View3DShading *shading = (View3DShading *)ptr->data;
|
||||
Scene *scene = rna_3DViewShading_scene(ptr);
|
||||
ViewLayer *view_layer = rna_3DViewShading_view_layer(ptr);
|
||||
shading->aov_name[0] = 0;
|
||||
|
||||
if ((value & EEVEE_RENDER_PASS_AOV) != 0) {
|
||||
if (!view_layer) {
|
||||
shading->render_pass = EEVEE_RENDER_PASS_COMBINED;
|
||||
return;
|
||||
}
|
||||
const int aov_index = value & ~EEVEE_RENDER_PASS_AOV;
|
||||
ViewLayerAOV *aov = BLI_findlink(&view_layer->aovs, aov_index);
|
||||
if (!aov) {
|
||||
/* AOV not found, cannot select AOV. */
|
||||
shading->render_pass = EEVEE_RENDER_PASS_COMBINED;
|
||||
return;
|
||||
}
|
||||
|
||||
shading->render_pass = EEVEE_RENDER_PASS_AOV;
|
||||
BLI_strncpy(shading->aov_name, aov->name, sizeof(aov->name));
|
||||
}
|
||||
else if (value == EEVEE_RENDER_PASS_BLOOM &&
|
||||
((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
|
||||
shading->render_pass = EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
else {
|
||||
shading->render_pass = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
@@ -3488,9 +3566,17 @@ 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, "rna_3DViewShading_render_pass_get", NULL, "rna_3DViewShading_render_pass_itemf");
|
||||
RNA_def_property_enum_funcs(prop,
|
||||
"rna_3DViewShading_render_pass_get",
|
||||
"rna_3DViewShading_render_pass_set",
|
||||
"rna_3DViewShading_render_pass_itemf");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "aov_name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "aov_name");
|
||||
RNA_def_property_ui_text(prop, "Shader AOV Name", "Name of the active Shader AOV");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_space_view3d_overlay(BlenderRNA *brna)
|
||||
|
||||
@@ -903,6 +903,16 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
|
||||
/* Duplicate bump height branches for manual derivatives.
|
||||
*/
|
||||
nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0);
|
||||
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
|
||||
if (node->type == SH_NODE_OUTPUT_AOV) {
|
||||
nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0);
|
||||
nTreeTags tags = {
|
||||
.ssr_id = 1.0,
|
||||
.sss_id = 1.0,
|
||||
};
|
||||
ntree_shader_tag_nodes(localtree, node, &tags);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
|
||||
nTreeTags tags = {
|
||||
@@ -913,6 +923,11 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
|
||||
|
||||
exec = ntreeShaderBeginExecTree(localtree);
|
||||
ntreeExecGPUNodes(exec, mat, output);
|
||||
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
|
||||
if (node->type == SH_NODE_OUTPUT_AOV) {
|
||||
ntreeExecGPUNodes(exec, mat, node);
|
||||
}
|
||||
}
|
||||
ntreeShaderEndExecTree(exec);
|
||||
|
||||
/* EEVEE: Find which material domain was used (volume, surface ...). */
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "../node_shader_util.h"
|
||||
|
||||
#include "BLI_hash.h"
|
||||
|
||||
/* **************** OUTPUT ******************** */
|
||||
|
||||
static bNodeSocketTemplate sh_node_output_aov_in[] = {
|
||||
@@ -33,6 +35,22 @@ static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
node->storage = aov;
|
||||
}
|
||||
|
||||
static int node_shader_gpu_output_aov(GPUMaterial *mat,
|
||||
bNode *node,
|
||||
bNodeExecData *UNUSED(execdata),
|
||||
GPUNodeStack *in,
|
||||
GPUNodeStack *out)
|
||||
{
|
||||
GPUNodeLink *outlink;
|
||||
NodeShaderOutputAOV *aov = (NodeShaderOutputAOV *)node->storage;
|
||||
/* Keep in sync with `renderpass_lib.glsl#render_pass_aov_hash`. */
|
||||
unsigned int hash = BLI_hash_string(aov->name) & ~1;
|
||||
GPU_stack_link(mat, node, "node_output_aov", in, out, &outlink);
|
||||
GPU_material_add_output_link_aov(mat, outlink, hash);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* node type definition */
|
||||
void register_node_type_sh_output_aov(void)
|
||||
{
|
||||
@@ -43,6 +61,7 @@ void register_node_type_sh_output_aov(void)
|
||||
node_type_init(&ntype, node_shader_init_output_aov);
|
||||
node_type_storage(
|
||||
&ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage);
|
||||
node_type_gpu(&ntype, node_shader_gpu_output_aov);
|
||||
|
||||
/* Do not allow muting output node. */
|
||||
node_type_internal_links(&ntype, NULL);
|
||||
|
||||
@@ -130,6 +130,9 @@ void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATT
|
||||
struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm,
|
||||
const struct bScreen *screen)
|
||||
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
|
||||
struct ViewLayer *WM_windows_view_layer_get_from_screen(const struct wmWindowManager *wm,
|
||||
const struct bScreen *screen)
|
||||
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
|
||||
struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm,
|
||||
const struct bScreen *screen)
|
||||
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
@@ -656,6 +656,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
|
||||
* pieces of Blender using sound may exit cleanly, see also T50676. */
|
||||
BKE_sound_exit();
|
||||
|
||||
BKE_appdir_exit();
|
||||
CLG_exit();
|
||||
|
||||
BKE_blender_atexit();
|
||||
|
||||
@@ -2261,6 +2261,17 @@ Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ViewLayer *WM_windows_view_layer_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
|
||||
{
|
||||
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
|
||||
if (WM_window_get_active_screen(win) == screen) {
|
||||
return WM_window_get_active_view_layer(win);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
|
||||
{
|
||||
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
|
||||
|
||||
+1
-1
Submodule source/tools updated: 7011d02c29...d7d7e9d41f
Reference in New Issue
Block a user