EEVEE-Next: Cryptomatte render passes.
This change adds cryptomatte render passes to EEVEE-Next. Due to the upcoming viewport compositor we also improved cryptomatte so it will be real-time. This also allows viewing the cryptomatte passes in the viewport directly. {F13482749} A surface shader would store any active cryptomatte layer to a texture. Object hash is stored as R, Asset hash as G and Material hash as B. Hashes are only calculated when the cryptomatte layer is active to reduce any unneeded work. During film accumulation the hashes are separated and stored in a texture array that matches the cryptomatte standard. For the real-time use case sorting is skipped. For final rendering the samples are sorted and normalized. NOTE: Eventually we should also do sample normalization in the viewport in order to extract the correct mask when using the viewport compositor. Reviewed By: fclem Maniphest Tasks: T99390 Differential Revision: https://developer.blender.org/D15753
This commit is contained in:
parent
bb3a021427
commit
8068b89a68
Notes:
blender-bot
2023-02-14 10:43:47 +01:00
Referenced by issue #99390, Eevee-next: Cryptomatte render pass
|
@ -209,7 +209,7 @@ class ViewLayerCryptomattePanel(ViewLayerButtonsPanel, Panel):
|
|||
|
||||
class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerCryptomattePanel, Panel):
|
||||
bl_parent_id = "VIEWLAYER_PT_layer_passes"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}
|
||||
|
||||
|
||||
class VIEWLAYER_MT_lightgroup_sync(Menu):
|
||||
|
|
|
@ -25,6 +25,8 @@ struct CryptomatteSession *BKE_cryptomatte_init(void);
|
|||
struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
|
||||
const struct RenderResult *render_result);
|
||||
struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene);
|
||||
struct CryptomatteSession *BKE_cryptomatte_init_from_view_layer(
|
||||
const struct ViewLayer *view_layer);
|
||||
void BKE_cryptomatte_free(struct CryptomatteSession *session);
|
||||
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "BKE_cryptomatte.h"
|
||||
|
||||
#include "BLI_hash_mm3.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
|
@ -54,10 +55,14 @@ struct CryptomatteHash {
|
|||
uint32_t hash;
|
||||
|
||||
CryptomatteHash(uint32_t hash);
|
||||
CryptomatteHash(const char *name, int name_len);
|
||||
static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
|
||||
CryptomatteHash(const char *name, int name_len)
|
||||
{
|
||||
hash = BLI_hash_mm3((const unsigned char *)name, name_len, 0);
|
||||
}
|
||||
|
||||
static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
|
||||
std::string hex_encoded() const;
|
||||
|
||||
/**
|
||||
* Convert a cryptomatte hash to a float.
|
||||
*
|
||||
|
@ -70,7 +75,20 @@ struct CryptomatteHash {
|
|||
*
|
||||
* Note that this conversion assumes to be running on a L-endian system.
|
||||
*/
|
||||
float float_encoded() const;
|
||||
float float_encoded() const
|
||||
{
|
||||
uint32_t mantissa = hash & ((1 << 23) - 1);
|
||||
uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
|
||||
exponent = MAX2(exponent, (uint32_t)1);
|
||||
exponent = MIN2(exponent, (uint32_t)254);
|
||||
exponent = exponent << 23;
|
||||
uint32_t sign = (hash >> 31);
|
||||
sign = sign << 31;
|
||||
uint32_t float_bits = sign | exponent | mantissa;
|
||||
float f;
|
||||
memcpy(&f, &float_bits, sizeof(uint32_t));
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
struct CryptomatteLayer {
|
||||
|
@ -107,6 +125,8 @@ struct CryptomatteStampDataCallbackData {
|
|||
|
||||
const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
|
||||
const CryptomatteSession &session);
|
||||
CryptomatteLayer *BKE_cryptomatte_layer_get(CryptomatteSession &session,
|
||||
const StringRef layer_name);
|
||||
|
||||
struct CryptomatteSessionDeleter {
|
||||
void operator()(CryptomatteSession *session)
|
||||
|
|
|
@ -41,7 +41,9 @@ struct CryptomatteSession {
|
|||
CryptomatteSession() = default;
|
||||
CryptomatteSession(const Main *bmain);
|
||||
CryptomatteSession(StampData *stamp_data);
|
||||
CryptomatteSession(const ViewLayer *view_layer);
|
||||
CryptomatteSession(const Scene *scene);
|
||||
void init(const ViewLayer *view_layer);
|
||||
|
||||
blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name);
|
||||
std::optional<std::string> operator[](float encoded_hash) const;
|
||||
|
@ -54,13 +56,15 @@ struct CryptomatteSession {
|
|||
CryptomatteSession::CryptomatteSession(const Main *bmain)
|
||||
{
|
||||
if (!BLI_listbase_is_empty(&bmain->objects)) {
|
||||
blender::bke::cryptomatte::CryptomatteLayer &objects = add_layer("CryptoObject");
|
||||
blender::bke::cryptomatte::CryptomatteLayer &objects = add_layer(
|
||||
RE_PASSNAME_CRYPTOMATTE_OBJECT);
|
||||
LISTBASE_FOREACH (ID *, id, &bmain->objects) {
|
||||
objects.add_ID(*id);
|
||||
}
|
||||
}
|
||||
if (!BLI_listbase_is_empty(&bmain->materials)) {
|
||||
blender::bke::cryptomatte::CryptomatteLayer &materials = add_layer("CryptoMaterial");
|
||||
blender::bke::cryptomatte::CryptomatteLayer &materials = add_layer(
|
||||
RE_PASSNAME_CRYPTOMATTE_MATERIAL);
|
||||
LISTBASE_FOREACH (ID *, id, &bmain->materials) {
|
||||
materials.add_ID(*id);
|
||||
}
|
||||
|
@ -83,24 +87,34 @@ CryptomatteSession::CryptomatteSession(StampData *stamp_data)
|
|||
false);
|
||||
}
|
||||
|
||||
CryptomatteSession::CryptomatteSession(const ViewLayer *view_layer)
|
||||
{
|
||||
init(view_layer);
|
||||
}
|
||||
|
||||
CryptomatteSession::CryptomatteSession(const Scene *scene)
|
||||
{
|
||||
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
|
||||
eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
|
||||
view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
|
||||
if (cryptoflags == 0) {
|
||||
cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
|
||||
}
|
||||
LISTBASE_FOREACH (const ViewLayer *, view_layer, &scene->view_layers) {
|
||||
init(view_layer);
|
||||
}
|
||||
}
|
||||
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + ".CryptoObject");
|
||||
}
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + ".CryptoAsset");
|
||||
}
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + ".CryptoMaterial");
|
||||
}
|
||||
void CryptomatteSession::init(const ViewLayer *view_layer)
|
||||
{
|
||||
eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
|
||||
view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
|
||||
if (cryptoflags == 0) {
|
||||
cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
|
||||
}
|
||||
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_OBJECT);
|
||||
}
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_ASSET);
|
||||
}
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_MATERIAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,6 +156,12 @@ struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *s
|
|||
return session;
|
||||
}
|
||||
|
||||
struct CryptomatteSession *BKE_cryptomatte_init_from_view_layer(const struct ViewLayer *view_layer)
|
||||
{
|
||||
CryptomatteSession *session = new CryptomatteSession(view_layer);
|
||||
return session;
|
||||
}
|
||||
|
||||
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name)
|
||||
{
|
||||
session->add_layer(layer_name);
|
||||
|
@ -485,11 +505,6 @@ CryptomatteHash::CryptomatteHash(uint32_t hash) : hash(hash)
|
|||
{
|
||||
}
|
||||
|
||||
CryptomatteHash::CryptomatteHash(const char *name, const int name_len)
|
||||
{
|
||||
hash = BLI_hash_mm3((const unsigned char *)name, name_len, 0);
|
||||
}
|
||||
|
||||
CryptomatteHash CryptomatteHash::from_hex_encoded(blender::StringRef hex_encoded)
|
||||
{
|
||||
CryptomatteHash result(0);
|
||||
|
@ -504,21 +519,6 @@ std::string CryptomatteHash::hex_encoded() const
|
|||
return encoded.str();
|
||||
}
|
||||
|
||||
float CryptomatteHash::float_encoded() const
|
||||
{
|
||||
uint32_t mantissa = hash & ((1 << 23) - 1);
|
||||
uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
|
||||
exponent = MAX2(exponent, (uint32_t)1);
|
||||
exponent = MIN2(exponent, (uint32_t)254);
|
||||
exponent = exponent << 23;
|
||||
uint32_t sign = (hash >> 31);
|
||||
sign = sign << 31;
|
||||
uint32_t float_bits = sign | exponent | mantissa;
|
||||
float f;
|
||||
memcpy(&f, &float_bits, sizeof(uint32_t));
|
||||
return f;
|
||||
}
|
||||
|
||||
std::unique_ptr<CryptomatteLayer> CryptomatteLayer::read_from_manifest(
|
||||
blender::StringRefNull manifest)
|
||||
{
|
||||
|
@ -625,4 +625,9 @@ const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
|
|||
return session.layer_names;
|
||||
}
|
||||
|
||||
CryptomatteLayer *BKE_cryptomatte_layer_get(CryptomatteSession &session, StringRef layer_name)
|
||||
{
|
||||
return session.layers.lookup_ptr(layer_name);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::cryptomatte
|
||||
|
|
|
@ -135,6 +135,7 @@ set(SRC
|
|||
engines/eevee/eevee_temporal_sampling.c
|
||||
engines/eevee/eevee_volumes.c
|
||||
engines/eevee_next/eevee_camera.cc
|
||||
engines/eevee_next/eevee_cryptomatte.cc
|
||||
engines/eevee_next/eevee_depth_of_field.cc
|
||||
engines/eevee_next/eevee_engine.cc
|
||||
engines/eevee_next/eevee_film.cc
|
||||
|
@ -395,6 +396,7 @@ set(GLSL_SRC
|
|||
engines/eevee_next/shaders/eevee_attributes_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_camera_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_colorspace_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_cryptomatte_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl
|
||||
|
@ -411,6 +413,7 @@ set(GLSL_SRC
|
|||
engines/eevee_next/shaders/eevee_depth_of_field_tiles_dilate_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_film_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_film_cryptomatte_post_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_film_frag.glsl
|
||||
engines/eevee_next/shaders/eevee_film_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
#include "BKE_cryptomatte.hh"
|
||||
|
||||
#include "GPU_material.h"
|
||||
|
||||
#include "eevee_cryptomatte.hh"
|
||||
#include "eevee_instance.hh"
|
||||
#include "eevee_renderbuffers.hh"
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
void Cryptomatte::begin_sync()
|
||||
{
|
||||
const eViewLayerEEVEEPassType enabled_passes = static_cast<eViewLayerEEVEEPassType>(
|
||||
inst_.film.enabled_passes_get() &
|
||||
(EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT | EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET |
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET));
|
||||
|
||||
session_.reset();
|
||||
object_layer_ = nullptr;
|
||||
asset_layer_ = nullptr;
|
||||
material_layer_ = nullptr;
|
||||
|
||||
if (enabled_passes && !inst_.is_viewport()) {
|
||||
session_.reset(BKE_cryptomatte_init_from_view_layer(inst_.view_layer));
|
||||
|
||||
for (const std::string &layer_name :
|
||||
bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session_)) {
|
||||
StringRef layer_name_ref = layer_name;
|
||||
bke::cryptomatte::CryptomatteLayer *layer = bke::cryptomatte::BKE_cryptomatte_layer_get(
|
||||
*session_, layer_name);
|
||||
if (layer_name_ref.endswith(RE_PASSNAME_CRYPTOMATTE_OBJECT)) {
|
||||
object_layer_ = layer;
|
||||
}
|
||||
else if (layer_name_ref.endswith(RE_PASSNAME_CRYPTOMATTE_ASSET)) {
|
||||
asset_layer_ = layer;
|
||||
}
|
||||
else if (layer_name_ref.endswith(RE_PASSNAME_CRYPTOMATTE_MATERIAL)) {
|
||||
material_layer_ = layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(enabled_passes &
|
||||
(EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT | EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET))) {
|
||||
cryptomatte_object_buf.resize(16);
|
||||
}
|
||||
}
|
||||
|
||||
void Cryptomatte::sync_object(Object *ob, ResourceHandle res_handle)
|
||||
{
|
||||
const eViewLayerEEVEEPassType enabled_passes = inst_.film.enabled_passes_get();
|
||||
if (!(enabled_passes &
|
||||
(EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT | EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET))) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t resource_id = res_handle.resource_index();
|
||||
float2 object_hashes(0.0f, 0.0f);
|
||||
|
||||
if (enabled_passes & EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT) {
|
||||
object_hashes[0] = register_id(EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT, ob->id);
|
||||
}
|
||||
|
||||
if (enabled_passes & EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET) {
|
||||
Object *asset = ob;
|
||||
while (asset->parent) {
|
||||
asset = asset->parent;
|
||||
}
|
||||
object_hashes[1] = register_id(EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET, asset->id);
|
||||
}
|
||||
cryptomatte_object_buf.get_or_resize(resource_id) = object_hashes;
|
||||
}
|
||||
|
||||
void Cryptomatte::sync_material(const ::Material *material)
|
||||
{
|
||||
/* Material crypto hashes are generated during shader codegen stage. We only need to register
|
||||
* them to store inside the metadata. */
|
||||
if (material_layer_ && material) {
|
||||
material_layer_->add_ID(material->id);
|
||||
}
|
||||
}
|
||||
|
||||
void Cryptomatte::end_sync()
|
||||
{
|
||||
cryptomatte_object_buf.push_update();
|
||||
|
||||
object_layer_ = nullptr;
|
||||
asset_layer_ = nullptr;
|
||||
material_layer_ = nullptr;
|
||||
}
|
||||
|
||||
float Cryptomatte::register_id(const eViewLayerEEVEEPassType layer, const ID &id) const
|
||||
{
|
||||
BLI_assert(ELEM(layer,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL));
|
||||
|
||||
uint32_t cryptomatte_hash = 0;
|
||||
if (session_) {
|
||||
if (layer == EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT) {
|
||||
BLI_assert(object_layer_);
|
||||
cryptomatte_hash = object_layer_->add_ID(id);
|
||||
}
|
||||
else if (layer == EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET) {
|
||||
BLI_assert(asset_layer_);
|
||||
cryptomatte_hash = asset_layer_->add_ID(id);
|
||||
}
|
||||
else if (layer == EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL) {
|
||||
BLI_assert(material_layer_);
|
||||
cryptomatte_hash = material_layer_->add_ID(id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *name = &id.name[2];
|
||||
const int name_len = BLI_strnlen(name, MAX_NAME - 2);
|
||||
cryptomatte_hash = BKE_cryptomatte_hash(name, name_len);
|
||||
}
|
||||
|
||||
return BKE_cryptomatte_hash_to_float(cryptomatte_hash);
|
||||
}
|
||||
|
||||
void Cryptomatte::store_metadata(RenderResult *render_result)
|
||||
{
|
||||
if (session_) {
|
||||
BKE_cryptomatte_store_metadata(&*session_, render_result, inst_.view_layer);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::eevee
|
|
@ -0,0 +1,69 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2021 Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup eevee
|
||||
*
|
||||
* Cryptomatte.
|
||||
*
|
||||
* During rasterization, cryptomatte hashes are stored into a single array texture.
|
||||
* The film pass then resamples this texture using pixel filter weighting.
|
||||
* Each cryptomatte layer can hold N samples. These are stored in sequential layers
|
||||
* of the array texture. The samples are sorted and merged only for final rendering.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "eevee_shader_shared.hh"
|
||||
|
||||
#include "BKE_cryptomatte.hh"
|
||||
|
||||
extern "C" {
|
||||
struct Material;
|
||||
struct CryptomatteSession;
|
||||
}
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
class Instance;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Cryptomatte
|
||||
* \{ */
|
||||
|
||||
class Cryptomatte {
|
||||
private:
|
||||
class Instance &inst_;
|
||||
|
||||
bke::cryptomatte::CryptomatteSessionPtr session_;
|
||||
|
||||
/* Cached pointer to the cryptomatte layer instances. */
|
||||
bke::cryptomatte::CryptomatteLayer *object_layer_ = nullptr;
|
||||
bke::cryptomatte::CryptomatteLayer *asset_layer_ = nullptr;
|
||||
bke::cryptomatte::CryptomatteLayer *material_layer_ = nullptr;
|
||||
|
||||
/** Contains per object hashes (object and asset hash). Indexed by resource ID. */
|
||||
CryptomatteObjectBuf cryptomatte_object_buf;
|
||||
|
||||
public:
|
||||
Cryptomatte(Instance &inst) : inst_(inst){};
|
||||
|
||||
void begin_sync();
|
||||
void sync_object(Object *ob, ResourceHandle res_handle);
|
||||
void sync_material(const ::Material *material);
|
||||
void end_sync();
|
||||
|
||||
template<typename T> void bind_resources(draw::detail::PassBase<T> *pass)
|
||||
{
|
||||
pass->bind_ssbo(CRYPTOMATTE_BUF_SLOT, &cryptomatte_object_buf);
|
||||
}
|
||||
|
||||
/* Register ID to use inside cryptomatte layer and returns associated hash as float. */
|
||||
float register_id(const eViewLayerEEVEEPassType layer, const ID &id) const;
|
||||
void store_metadata(RenderResult *render_result);
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::eevee
|
|
@ -82,6 +82,7 @@
|
|||
#define RBUFS_EMISSION_SLOT 4
|
||||
#define RBUFS_AOV_COLOR_SLOT 5
|
||||
#define RBUFS_AOV_VALUE_SLOT 6
|
||||
#define RBUFS_CRYPTOMATTE_SLOT 7
|
||||
|
||||
/* Uniform Buffers. */
|
||||
/* Only during prepass. */
|
||||
|
@ -96,6 +97,8 @@
|
|||
#define LIGHT_TILE_BUF_SLOT 3
|
||||
#define RBUFS_AOV_BUF_SLOT 5
|
||||
#define SAMPLING_BUF_SLOT 6
|
||||
#define CRYPTOMATTE_BUF_SLOT 7
|
||||
|
||||
/* Only during pre-pass. */
|
||||
#define VELOCITY_OBJ_PREV_BUF_SLOT 0
|
||||
#define VELOCITY_OBJ_NEXT_BUF_SLOT 1
|
||||
|
|
|
@ -140,7 +140,7 @@ static void eevee_instance_free(void *instance)
|
|||
delete reinterpret_cast<eevee::Instance *>(instance);
|
||||
}
|
||||
|
||||
static void eevee_render_to_image(void *UNUSED(vedata),
|
||||
static void eevee_render_to_image(void *vedata,
|
||||
struct RenderEngine *engine,
|
||||
struct RenderLayer *layer,
|
||||
const struct rcti *UNUSED(rect))
|
||||
|
@ -164,7 +164,23 @@ static void eevee_render_to_image(void *UNUSED(vedata),
|
|||
instance->init(size, &rect, engine, depsgraph, nullptr, camera_original_ob, layer);
|
||||
instance->render_frame(layer, viewname);
|
||||
|
||||
EEVEE_Data *ved = static_cast<EEVEE_Data *>(vedata);
|
||||
if (ved->instance) {
|
||||
delete ved->instance;
|
||||
}
|
||||
ved->instance = instance;
|
||||
}
|
||||
|
||||
static void eevee_store_metadata(void *vedata, struct RenderResult *render_result)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
EEVEE_Data *ved = static_cast<EEVEE_Data *>(vedata);
|
||||
eevee::Instance *instance = ved->instance;
|
||||
instance->store_metadata(render_result);
|
||||
delete instance;
|
||||
ved->instance = nullptr;
|
||||
}
|
||||
|
||||
static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
|
||||
|
@ -172,51 +188,7 @@ static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewL
|
|||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
|
||||
|
||||
#define CHECK_PASS_LEGACY(name, type, channels, chanid) \
|
||||
if (view_layer->passflag & (SCE_PASS_##name)) { \
|
||||
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_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(DIFFUSE_DIRECT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(DIFFUSE_COLOR, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(GLOSSY_DIRECT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(GLOSSY_COLOR, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_EEVEE(VOLUME_LIGHT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(EMIT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(ENVIRONMENT, SOCK_RGBA, 3, "RGB");
|
||||
/* TODO: CHECK_PASS_LEGACY(SHADOW, SOCK_RGBA, 3, "RGB");
|
||||
* CHECK_PASS_LEGACY(AO, SOCK_RGBA, 3, "RGB");
|
||||
* When available they should be converted from Value textures to RGB. */
|
||||
|
||||
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
|
||||
if ((aov->flag & AOV_CONFLICT) != 0) {
|
||||
continue;
|
||||
}
|
||||
switch (aov->type) {
|
||||
case AOV_TYPE_COLOR:
|
||||
RE_engine_register_pass(engine, scene, view_layer, aov->name, 4, "RGBA", SOCK_RGBA);
|
||||
break;
|
||||
case AOV_TYPE_VALUE:
|
||||
RE_engine_register_pass(engine, scene, view_layer, aov->name, 1, "X", SOCK_FLOAT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
eevee::Instance::update_passes(engine, scene, view_layer);
|
||||
}
|
||||
|
||||
static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);
|
||||
|
@ -238,7 +210,7 @@ DrawEngineType draw_engine_eevee_next_type = {
|
|||
nullptr,
|
||||
nullptr,
|
||||
&eevee_render_to_image,
|
||||
nullptr,
|
||||
&eevee_store_metadata,
|
||||
};
|
||||
|
||||
RenderEngineType DRW_engine_viewport_eevee_next_type = {
|
||||
|
|
|
@ -162,6 +162,45 @@ inline bool operator!=(const FilmData &a, const FilmData &b)
|
|||
/** \name Film
|
||||
* \{ */
|
||||
|
||||
static eViewLayerEEVEEPassType enabled_passes(const ViewLayer *view_layer)
|
||||
{
|
||||
eViewLayerEEVEEPassType result = eViewLayerEEVEEPassType(view_layer->eevee.render_passes);
|
||||
|
||||
#define ENABLE_FROM_LEGACY(name_legacy, name_eevee) \
|
||||
SET_FLAG_FROM_TEST(result, \
|
||||
(view_layer->passflag & SCE_PASS_##name_legacy) != 0, \
|
||||
EEVEE_RENDER_PASS_##name_eevee);
|
||||
|
||||
ENABLE_FROM_LEGACY(COMBINED, COMBINED)
|
||||
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)
|
||||
ENABLE_FROM_LEGACY(VECTOR, VECTOR)
|
||||
|
||||
#undef ENABLE_FROM_LEGACY
|
||||
|
||||
SET_FLAG_FROM_TEST(result,
|
||||
view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_OBJECT,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT);
|
||||
SET_FLAG_FROM_TEST(result,
|
||||
view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ASSET,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET);
|
||||
SET_FLAG_FROM_TEST(result,
|
||||
view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_MATERIAL,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Film::init(const int2 &extent, const rcti *output_rect)
|
||||
{
|
||||
Sampling &sampling = inst_.sampling;
|
||||
|
@ -186,29 +225,7 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
}
|
||||
else {
|
||||
/* Render Case. */
|
||||
render_passes = eViewLayerEEVEEPassType(inst_.view_layer->eevee.render_passes);
|
||||
|
||||
#define ENABLE_FROM_LEGACY(name_legacy, name_eevee) \
|
||||
SET_FLAG_FROM_TEST(render_passes, \
|
||||
(inst_.view_layer->passflag & SCE_PASS_##name_legacy) != 0, \
|
||||
EEVEE_RENDER_PASS_##name_eevee);
|
||||
|
||||
ENABLE_FROM_LEGACY(COMBINED, COMBINED)
|
||||
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)
|
||||
ENABLE_FROM_LEGACY(VECTOR, VECTOR)
|
||||
|
||||
#undef ENABLE_FROM_LEGACY
|
||||
render_passes = enabled_passes(inst_.view_layer);
|
||||
}
|
||||
|
||||
/* Filter obsolete passes. */
|
||||
|
@ -241,6 +258,7 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
/* TODO(fclem): parameter hidden in experimental.
|
||||
* We need to figure out LOD bias first in order to preserve texture crispiness. */
|
||||
data.scaling_factor = 1;
|
||||
data.cryptomatte_samples_len = inst_.view_layer->cryptomatte_levels;
|
||||
|
||||
data.background_opacity = (scene.r.alphamode == R_ALPHAPREMUL) ? 0.0f : 1.0f;
|
||||
if (inst_.is_viewport() && false /* TODO(fclem): StudioLight */) {
|
||||
|
@ -273,7 +291,8 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
/* Set pass offsets. */
|
||||
|
||||
data_.display_id = aovs_info.display_id;
|
||||
data_.display_is_value = aovs_info.display_is_value;
|
||||
data_.display_storage_type = aovs_info.display_is_value ? PASS_STORAGE_VALUE :
|
||||
PASS_STORAGE_COLOR;
|
||||
|
||||
/* Combined is in a separate buffer. */
|
||||
data_.combined_id = (enabled_passes_ & EEVEE_RENDER_PASS_COMBINED) ? 0 : -1;
|
||||
|
@ -284,13 +303,13 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
data_.value_len = 0;
|
||||
|
||||
auto pass_index_get = [&](eViewLayerEEVEEPassType pass_type) {
|
||||
bool is_value = pass_is_value(pass_type);
|
||||
ePassStorageType storage_type = pass_storage_type(pass_type);
|
||||
int index = (enabled_passes_ & pass_type) ?
|
||||
(is_value ? data_.value_len : data_.color_len)++ :
|
||||
(storage_type == PASS_STORAGE_VALUE ? data_.value_len : data_.color_len)++ :
|
||||
-1;
|
||||
if (inst_.is_viewport() && inst_.v3d->shading.render_pass == pass_type) {
|
||||
data_.display_id = index;
|
||||
data_.display_is_value = is_value;
|
||||
data_.display_storage_type = storage_type;
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
@ -316,6 +335,24 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
|
||||
data_.color_len += data_.aov_color_len;
|
||||
data_.value_len += data_.aov_value_len;
|
||||
|
||||
int cryptomatte_id = 0;
|
||||
auto cryptomatte_index_get = [&](eViewLayerEEVEEPassType pass_type) {
|
||||
int index = -1;
|
||||
if (enabled_passes_ & pass_type) {
|
||||
index = cryptomatte_id;
|
||||
cryptomatte_id += data_.cryptomatte_samples_len / 2;
|
||||
|
||||
if (inst_.is_viewport() && inst_.v3d->shading.render_pass == pass_type) {
|
||||
data_.display_id = index;
|
||||
data_.display_storage_type = PASS_STORAGE_CRYPTOMATTE;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
};
|
||||
data_.cryptomatte_object_id = cryptomatte_index_get(EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT);
|
||||
data_.cryptomatte_asset_id = cryptomatte_index_get(EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET);
|
||||
data_.cryptomatte_material_id = cryptomatte_index_get(EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL);
|
||||
}
|
||||
{
|
||||
/* TODO(@fclem): Over-scans. */
|
||||
|
@ -327,6 +364,7 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
eGPUTextureFormat float_format = GPU_R16F;
|
||||
eGPUTextureFormat weight_format = GPU_R32F;
|
||||
eGPUTextureFormat depth_format = GPU_R32F;
|
||||
eGPUTextureFormat cryptomatte_format = GPU_RGBA32F;
|
||||
|
||||
int reset = 0;
|
||||
reset += depth_tx_.ensure_2d(depth_format, data_.extent);
|
||||
|
@ -341,6 +379,12 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
reset += value_accum_tx_.ensure_2d_array(float_format,
|
||||
(data_.value_len > 0) ? data_.extent : int2(1),
|
||||
(data_.value_len > 0) ? data_.value_len : 1);
|
||||
/* Divided by two as two cryptomatte samples fit in pixel (RG, BA). */
|
||||
int cryptomatte_array_len = cryptomatte_layer_len_get() * data_.cryptomatte_samples_len / 2;
|
||||
reset += cryptomatte_tx_.ensure_2d_array(cryptomatte_format,
|
||||
(cryptomatte_array_len > 0) ? data_.extent : int2(1),
|
||||
(cryptomatte_array_len > 0) ? cryptomatte_array_len :
|
||||
1);
|
||||
|
||||
if (reset > 0) {
|
||||
sampling.reset();
|
||||
|
@ -353,6 +397,7 @@ void Film::init(const int2 &extent, const rcti *output_rect)
|
|||
combined_tx_.current().clear(float4(0.0f));
|
||||
weight_tx_.current().clear(float4(0.0f));
|
||||
depth_tx_.clear(float4(0.0f));
|
||||
cryptomatte_tx_.clear(float4(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,6 +443,7 @@ void Film::sync()
|
|||
accumulate_ps_.bind_texture("ambient_occlusion_tx", &rbuffers.ambient_occlusion_tx);
|
||||
accumulate_ps_.bind_texture("aov_color_tx", &rbuffers.aov_color_tx);
|
||||
accumulate_ps_.bind_texture("aov_value_tx", &rbuffers.aov_value_tx);
|
||||
accumulate_ps_.bind_texture("cryptomatte_tx", &rbuffers.cryptomatte_tx);
|
||||
/* NOTE(@fclem): 16 is the max number of sampled texture in many implementations.
|
||||
* If we need more, we need to pack more of the similar passes in the same textures as arrays or
|
||||
* use image binding instead. */
|
||||
|
@ -408,6 +454,7 @@ void Film::sync()
|
|||
accumulate_ps_.bind_image("depth_img", &depth_tx_);
|
||||
accumulate_ps_.bind_image("color_accum_img", &color_accum_tx_);
|
||||
accumulate_ps_.bind_image("value_accum_img", &value_accum_tx_);
|
||||
accumulate_ps_.bind_image("cryptomatte_img", &cryptomatte_tx_);
|
||||
/* Sync with rendering passes. */
|
||||
accumulate_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
if (use_compute) {
|
||||
|
@ -416,6 +463,22 @@ void Film::sync()
|
|||
else {
|
||||
accumulate_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
|
||||
const int cryptomatte_layer_count = cryptomatte_layer_len_get();
|
||||
const bool is_cryptomatte_pass_enabled = cryptomatte_layer_count > 0;
|
||||
const bool do_cryptomatte_sorting = inst_.is_viewport() == false;
|
||||
cryptomatte_post_ps_.init();
|
||||
if (is_cryptomatte_pass_enabled && do_cryptomatte_sorting) {
|
||||
cryptomatte_post_ps_.state_set(DRW_STATE_NO_DRAW);
|
||||
cryptomatte_post_ps_.shader_set(inst_.shaders.static_shader_get(FILM_CRYPTOMATTE_POST));
|
||||
cryptomatte_post_ps_.bind_image("cryptomatte_img", &cryptomatte_tx_);
|
||||
cryptomatte_post_ps_.bind_image("weight_img", &weight_tx_.current());
|
||||
cryptomatte_post_ps_.push_constant("cryptomatte_layer_len", cryptomatte_layer_count);
|
||||
cryptomatte_post_ps_.push_constant("cryptomatte_samples_per_layer",
|
||||
inst_.view_layer->cryptomatte_levels);
|
||||
int2 dispatch_size = math::divide_ceil(int2(cryptomatte_tx_.size()), int2(FILM_GROUP_SIZE));
|
||||
cryptomatte_post_ps_.dispatch(int3(UNPACK2(dispatch_size), 1));
|
||||
}
|
||||
}
|
||||
|
||||
void Film::end_sync()
|
||||
|
@ -463,6 +526,29 @@ eViewLayerEEVEEPassType Film::enabled_passes_get() const
|
|||
return enabled_passes_;
|
||||
}
|
||||
|
||||
int Film::cryptomatte_layer_len_get() const
|
||||
{
|
||||
int result = 0;
|
||||
result += data_.cryptomatte_object_id == -1 ? 0 : 1;
|
||||
result += data_.cryptomatte_asset_id == -1 ? 0 : 1;
|
||||
result += data_.cryptomatte_material_id == -1 ? 0 : 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
int Film::cryptomatte_layer_max_get() const
|
||||
{
|
||||
if (data_.cryptomatte_material_id != -1) {
|
||||
return 3;
|
||||
}
|
||||
if (data_.cryptomatte_asset_id != -1) {
|
||||
return 2;
|
||||
}
|
||||
if (data_.cryptomatte_object_id != -1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Film::update_sample_table()
|
||||
{
|
||||
data_.subpixel_offset = pixel_jitter_get();
|
||||
|
@ -599,20 +685,28 @@ void Film::display()
|
|||
/* IMPORTANT: Do not swap! No accumulation has happened. */
|
||||
}
|
||||
|
||||
float *Film::read_pass(eViewLayerEEVEEPassType pass_type)
|
||||
void Film::cryptomatte_sort()
|
||||
{
|
||||
DRW_manager_get()->submit(cryptomatte_post_ps_);
|
||||
}
|
||||
|
||||
float *Film::read_pass(eViewLayerEEVEEPassType pass_type, int layer_offset)
|
||||
{
|
||||
ePassStorageType storage_type = pass_storage_type(pass_type);
|
||||
const bool is_value = storage_type == PASS_STORAGE_VALUE;
|
||||
const bool is_cryptomatte = storage_type == PASS_STORAGE_CRYPTOMATTE;
|
||||
|
||||
bool is_value = pass_is_value(pass_type);
|
||||
Texture &accum_tx = (pass_type == EEVEE_RENDER_PASS_COMBINED) ?
|
||||
combined_tx_.current() :
|
||||
(pass_type == EEVEE_RENDER_PASS_Z) ?
|
||||
depth_tx_ :
|
||||
(is_value ? value_accum_tx_ : color_accum_tx_);
|
||||
(is_cryptomatte ? cryptomatte_tx_ :
|
||||
(is_value ? value_accum_tx_ : color_accum_tx_));
|
||||
|
||||
accum_tx.ensure_layer_views();
|
||||
|
||||
int index = pass_id_get(pass_type);
|
||||
GPUTexture *pass_tx = accum_tx.layer_view(index);
|
||||
GPUTexture *pass_tx = accum_tx.layer_view(index + layer_offset);
|
||||
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
|
||||
|
|
|
@ -43,11 +43,16 @@ class Film {
|
|||
/** Incoming combined buffer with post FX applied (motion blur + depth of field). */
|
||||
GPUTexture *combined_final_tx_ = nullptr;
|
||||
|
||||
/** Main accumulation textures containing every render-pass except depth and combined. */
|
||||
/**
|
||||
* Main accumulation textures containing every render-pass except depth, cryptomatte and
|
||||
* combined.
|
||||
*/
|
||||
Texture color_accum_tx_;
|
||||
Texture value_accum_tx_;
|
||||
/** Depth accumulation texture. Separated because using a different format. */
|
||||
Texture depth_tx_;
|
||||
/** Cryptomatte texture. Separated because it requires full floats. */
|
||||
Texture cryptomatte_tx_;
|
||||
/** Combined "Color" buffer. Double buffered to allow re-projection. */
|
||||
SwapChain<Texture, 2> combined_tx_;
|
||||
/** Weight buffers. Double buffered to allow updating it during accumulation. */
|
||||
|
@ -56,6 +61,7 @@ class Film {
|
|||
bool force_disable_reprojection_ = false;
|
||||
|
||||
PassSimple accumulate_ps_ = {"Film.Accumulate"};
|
||||
PassSimple cryptomatte_post_ps_ = {"Film.Cryptomatte.Post"};
|
||||
|
||||
FilmDataBuf data_;
|
||||
|
||||
|
@ -73,10 +79,13 @@ class Film {
|
|||
/** Accumulate the newly rendered sample contained in #RenderBuffers and blit to display. */
|
||||
void accumulate(const DRWView *view, GPUTexture *combined_final_tx);
|
||||
|
||||
/** Sort and normalize cryptomatte samples. */
|
||||
void cryptomatte_sort();
|
||||
|
||||
/** Blit to display. No rendered sample needed. */
|
||||
void display();
|
||||
|
||||
float *read_pass(eViewLayerEEVEEPassType pass_type);
|
||||
float *read_pass(eViewLayerEEVEEPassType pass_type, int layer_offset);
|
||||
float *read_aov(ViewLayerAOV *aov);
|
||||
|
||||
/** Returns shading views internal resolution. */
|
||||
|
@ -93,17 +102,23 @@ class Film {
|
|||
}
|
||||
|
||||
eViewLayerEEVEEPassType enabled_passes_get() const;
|
||||
int cryptomatte_layer_max_get() const;
|
||||
int cryptomatte_layer_len_get() const;
|
||||
|
||||
static bool pass_is_value(eViewLayerEEVEEPassType pass_type)
|
||||
static ePassStorageType pass_storage_type(eViewLayerEEVEEPassType pass_type)
|
||||
{
|
||||
switch (pass_type) {
|
||||
case EEVEE_RENDER_PASS_Z:
|
||||
case EEVEE_RENDER_PASS_MIST:
|
||||
case EEVEE_RENDER_PASS_SHADOW:
|
||||
case EEVEE_RENDER_PASS_AO:
|
||||
return true;
|
||||
return PASS_STORAGE_VALUE;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT:
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET:
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL:
|
||||
return PASS_STORAGE_CRYPTOMATTE;
|
||||
default:
|
||||
return false;
|
||||
return PASS_STORAGE_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,8 +169,12 @@ class Film {
|
|||
return data_.shadow_id;
|
||||
case EEVEE_RENDER_PASS_AO:
|
||||
return data_.ambient_occlusion_id;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE:
|
||||
return -1; /* TODO */
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT:
|
||||
return data_.cryptomatte_object_id;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET:
|
||||
return data_.cryptomatte_asset_id;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL:
|
||||
return data_.cryptomatte_material_id;
|
||||
case EEVEE_RENDER_PASS_VECTOR:
|
||||
return data_.vector_id;
|
||||
default:
|
||||
|
@ -163,44 +182,80 @@ class Film {
|
|||
}
|
||||
}
|
||||
|
||||
static const char *pass_to_render_pass_name(eViewLayerEEVEEPassType pass_type)
|
||||
static const Vector<std::string> pass_to_render_pass_names(eViewLayerEEVEEPassType pass_type,
|
||||
const ViewLayer *view_layer)
|
||||
{
|
||||
Vector<std::string> result;
|
||||
|
||||
auto build_cryptomatte_passes = [&](const char *pass_name) {
|
||||
const int num_cryptomatte_passes = (view_layer->cryptomatte_levels + 1) / 2;
|
||||
for (int pass = 0; pass < num_cryptomatte_passes; pass++) {
|
||||
std::stringstream ss;
|
||||
ss.fill('0');
|
||||
ss << pass_name;
|
||||
ss.width(2);
|
||||
ss << pass;
|
||||
result.append(ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
switch (pass_type) {
|
||||
case EEVEE_RENDER_PASS_COMBINED:
|
||||
return RE_PASSNAME_COMBINED;
|
||||
result.append(RE_PASSNAME_COMBINED);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_Z:
|
||||
return RE_PASSNAME_Z;
|
||||
result.append(RE_PASSNAME_Z);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_MIST:
|
||||
return RE_PASSNAME_MIST;
|
||||
result.append(RE_PASSNAME_MIST);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_NORMAL:
|
||||
return RE_PASSNAME_NORMAL;
|
||||
result.append(RE_PASSNAME_NORMAL);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_DIFFUSE_LIGHT:
|
||||
return RE_PASSNAME_DIFFUSE_DIRECT;
|
||||
result.append(RE_PASSNAME_DIFFUSE_DIRECT);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_DIFFUSE_COLOR:
|
||||
return RE_PASSNAME_DIFFUSE_COLOR;
|
||||
result.append(RE_PASSNAME_DIFFUSE_COLOR);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_SPECULAR_LIGHT:
|
||||
return RE_PASSNAME_GLOSSY_DIRECT;
|
||||
result.append(RE_PASSNAME_GLOSSY_DIRECT);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_SPECULAR_COLOR:
|
||||
return RE_PASSNAME_GLOSSY_COLOR;
|
||||
result.append(RE_PASSNAME_GLOSSY_COLOR);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_VOLUME_LIGHT:
|
||||
return RE_PASSNAME_VOLUME_LIGHT;
|
||||
result.append(RE_PASSNAME_VOLUME_LIGHT);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_EMIT:
|
||||
return RE_PASSNAME_EMIT;
|
||||
result.append(RE_PASSNAME_EMIT);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_ENVIRONMENT:
|
||||
return RE_PASSNAME_ENVIRONMENT;
|
||||
result.append(RE_PASSNAME_ENVIRONMENT);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_SHADOW:
|
||||
return RE_PASSNAME_SHADOW;
|
||||
result.append(RE_PASSNAME_SHADOW);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_AO:
|
||||
return RE_PASSNAME_AO;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE:
|
||||
BLI_assert_msg(0, "Cryptomatte is not implemented yet.");
|
||||
return ""; /* TODO */
|
||||
result.append(RE_PASSNAME_AO);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT:
|
||||
build_cryptomatte_passes(RE_PASSNAME_CRYPTOMATTE_OBJECT);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET:
|
||||
build_cryptomatte_passes(RE_PASSNAME_CRYPTOMATTE_ASSET);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL:
|
||||
build_cryptomatte_passes(RE_PASSNAME_CRYPTOMATTE_MATERIAL);
|
||||
break;
|
||||
case EEVEE_RENDER_PASS_VECTOR:
|
||||
return RE_PASSNAME_VECTOR;
|
||||
result.append(RE_PASSNAME_VECTOR);
|
||||
break;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
return "";
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -102,6 +102,7 @@ void Instance::begin_sync()
|
|||
materials.begin_sync();
|
||||
velocity.begin_sync(); /* NOTE: Also syncs camera. */
|
||||
lights.begin_sync();
|
||||
cryptomatte.begin_sync();
|
||||
|
||||
gpencil_engine_enabled = false;
|
||||
|
||||
|
@ -182,6 +183,7 @@ void Instance::end_sync()
|
|||
lights.end_sync();
|
||||
sampling.end_sync();
|
||||
film.end_sync();
|
||||
cryptomatte.end_sync();
|
||||
}
|
||||
|
||||
void Instance::render_sync()
|
||||
|
@ -236,10 +238,15 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na
|
|||
continue;
|
||||
}
|
||||
|
||||
const char *pass_name = Film::pass_to_render_pass_name(pass_type);
|
||||
RenderPass *rp = RE_pass_find_by_name(render_layer, pass_name, view_name);
|
||||
if (rp) {
|
||||
float *result = film.read_pass(pass_type);
|
||||
Vector<std::string> pass_names = Film::pass_to_render_pass_names(pass_type, view_layer);
|
||||
for (int64_t pass_offset : IndexRange(pass_names.size())) {
|
||||
RenderPass *rp = RE_pass_find_by_name(
|
||||
render_layer, pass_names[pass_offset].c_str(), view_name);
|
||||
if (!rp) {
|
||||
continue;
|
||||
}
|
||||
float *result = film.read_pass(pass_type, pass_offset);
|
||||
|
||||
if (result) {
|
||||
BLI_mutex_lock(&render->update_render_passes_mutex);
|
||||
/* WORKAROUND: We use texture read to avoid using a framebuffer to get the render result.
|
||||
|
@ -255,10 +262,13 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na
|
|||
|
||||
/* The vector pass is initialized to weird values. Set it to neutral value if not rendered. */
|
||||
if ((pass_bits & EEVEE_RENDER_PASS_VECTOR) == 0) {
|
||||
const char *vector_pass_name = Film::pass_to_render_pass_name(EEVEE_RENDER_PASS_VECTOR);
|
||||
RenderPass *vector_rp = RE_pass_find_by_name(render_layer, vector_pass_name, view_name);
|
||||
if (vector_rp) {
|
||||
memset(vector_rp->rect, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty);
|
||||
for (std::string vector_pass_name :
|
||||
Film::pass_to_render_pass_names(EEVEE_RENDER_PASS_VECTOR, view_layer)) {
|
||||
RenderPass *vector_rp = RE_pass_find_by_name(
|
||||
render_layer, vector_pass_name.c_str(), view_name);
|
||||
if (vector_rp) {
|
||||
memset(vector_rp->rect, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,6 +300,8 @@ void Instance::render_frame(RenderLayer *render_layer, const char *view_name)
|
|||
#endif
|
||||
}
|
||||
|
||||
this->film.cryptomatte_sort();
|
||||
|
||||
this->render_read_result(render_layer, view_name);
|
||||
}
|
||||
|
||||
|
@ -313,6 +325,76 @@ void Instance::draw_viewport(DefaultFramebufferList *dfbl)
|
|||
}
|
||||
}
|
||||
|
||||
void Instance::store_metadata(RenderResult *render_result)
|
||||
{
|
||||
cryptomatte.store_metadata(render_result);
|
||||
}
|
||||
|
||||
void Instance::update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
|
||||
|
||||
#define CHECK_PASS_LEGACY(name, type, channels, chanid) \
|
||||
if (view_layer->passflag & (SCE_PASS_##name)) { \
|
||||
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_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(DIFFUSE_DIRECT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(DIFFUSE_COLOR, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(GLOSSY_DIRECT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(GLOSSY_COLOR, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_EEVEE(VOLUME_LIGHT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(EMIT, SOCK_RGBA, 3, "RGB");
|
||||
CHECK_PASS_LEGACY(ENVIRONMENT, SOCK_RGBA, 3, "RGB");
|
||||
/* TODO: CHECK_PASS_LEGACY(SHADOW, SOCK_RGBA, 3, "RGB");
|
||||
* CHECK_PASS_LEGACY(AO, SOCK_RGBA, 3, "RGB");
|
||||
* When available they should be converted from Value textures to 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: Name channels lowercase rgba so that compression rules check in OpenEXR DWA code uses
|
||||
* loseless compression. Reportedly this naming is the only one which works good from the
|
||||
* interoperability point of view. Using xyzw naming is not portable. */
|
||||
auto register_cryptomatte_passes = [&](eViewLayerCryptomatteFlags cryptomatte_layer,
|
||||
eViewLayerEEVEEPassType eevee_pass) {
|
||||
if (view_layer->cryptomatte_flag & cryptomatte_layer) {
|
||||
for (std::string pass_name : Film::pass_to_render_pass_names(eevee_pass, view_layer)) {
|
||||
RE_engine_register_pass(
|
||||
engine, scene, view_layer, pass_name.c_str(), 4, "rgba", SOCK_RGBA);
|
||||
}
|
||||
}
|
||||
};
|
||||
register_cryptomatte_passes(VIEW_LAYER_CRYPTOMATTE_OBJECT, EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT);
|
||||
register_cryptomatte_passes(VIEW_LAYER_CRYPTOMATTE_ASSET, EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET);
|
||||
register_cryptomatte_passes(VIEW_LAYER_CRYPTOMATTE_MATERIAL,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::eevee
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "DRW_render.h"
|
||||
|
||||
#include "eevee_camera.hh"
|
||||
#include "eevee_cryptomatte.hh"
|
||||
#include "eevee_depth_of_field.hh"
|
||||
#include "eevee_film.hh"
|
||||
#include "eevee_hizbuffer.hh"
|
||||
|
@ -49,6 +50,7 @@ class Instance {
|
|||
VelocityModule velocity;
|
||||
MotionBlurModule motion_blur;
|
||||
DepthOfField depth_of_field;
|
||||
Cryptomatte cryptomatte;
|
||||
HiZBuffer hiz_buffer;
|
||||
Sampling sampling;
|
||||
Camera camera;
|
||||
|
@ -91,6 +93,7 @@ class Instance {
|
|||
velocity(*this),
|
||||
motion_blur(*this),
|
||||
depth_of_field(*this),
|
||||
cryptomatte(*this),
|
||||
hiz_buffer(*this),
|
||||
sampling(*this),
|
||||
camera(*this),
|
||||
|
@ -117,9 +120,12 @@ class Instance {
|
|||
|
||||
void render_sync();
|
||||
void render_frame(RenderLayer *render_layer, const char *view_name);
|
||||
void store_metadata(RenderResult *render_result);
|
||||
|
||||
void draw_viewport(DefaultFramebufferList *dfbl);
|
||||
|
||||
static void update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer);
|
||||
|
||||
bool is_viewport() const
|
||||
{
|
||||
return render == nullptr;
|
||||
|
|
|
@ -44,6 +44,7 @@ void WorldPipeline::sync(GPUMaterial *gpumat)
|
|||
world_ps_.bind_image("rp_diffuse_color_img", &rbufs.diffuse_color_tx);
|
||||
world_ps_.bind_image("rp_specular_color_img", &rbufs.specular_color_tx);
|
||||
world_ps_.bind_image("rp_emission_img", &rbufs.emission_tx);
|
||||
world_ps_.bind_image("rp_cryptomatte_img", &rbufs.cryptomatte_tx);
|
||||
|
||||
world_ps_.draw(DRW_cache_fullscreen_quad_get(), handle);
|
||||
/* To allow opaque pass rendering over it. */
|
||||
|
@ -110,6 +111,8 @@ void ForwardPipeline::sync()
|
|||
/* AOVs. */
|
||||
opaque_ps_.bind_image(RBUFS_AOV_COLOR_SLOT, &inst_.render_buffers.aov_color_tx);
|
||||
opaque_ps_.bind_image(RBUFS_AOV_VALUE_SLOT, &inst_.render_buffers.aov_value_tx);
|
||||
/* Cryptomatte. */
|
||||
opaque_ps_.bind_image(RBUFS_CRYPTOMATTE_SLOT, &inst_.render_buffers.cryptomatte_tx);
|
||||
/* Storage Buf. */
|
||||
opaque_ps_.bind_ssbo(RBUFS_AOV_BUF_SLOT, &inst_.film.aovs_info);
|
||||
/* Textures. */
|
||||
|
@ -117,6 +120,7 @@ void ForwardPipeline::sync()
|
|||
|
||||
inst_.lights.bind_resources(&opaque_ps_);
|
||||
inst_.sampling.bind_resources(&opaque_ps_);
|
||||
inst_.cryptomatte.bind_resources(&opaque_ps_);
|
||||
}
|
||||
|
||||
opaque_single_sided_ps_ = &opaque_ps_.sub("SingleSided");
|
||||
|
|
|
@ -72,6 +72,20 @@ void RenderBuffers::acquire(int2 extent)
|
|||
color_format, (aovs.color_len > 0) ? extent : int2(1), max_ii(1, aovs.color_len));
|
||||
aov_value_tx.ensure_2d_array(
|
||||
float_format, (aovs.value_len > 0) ? extent : int2(1), max_ii(1, aovs.value_len));
|
||||
|
||||
eGPUTextureFormat cryptomatte_format = GPU_R32F;
|
||||
const int cryptomatte_layer_len = inst_.film.cryptomatte_layer_max_get();
|
||||
if (cryptomatte_layer_len == 2) {
|
||||
cryptomatte_format = GPU_RG32F;
|
||||
}
|
||||
else if (cryptomatte_layer_len == 3) {
|
||||
cryptomatte_format = GPU_RGBA32F;
|
||||
}
|
||||
cryptomatte_tx.acquire(
|
||||
pass_extent(static_cast<eViewLayerEEVEEPassType>(EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT |
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET |
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL)),
|
||||
cryptomatte_format);
|
||||
}
|
||||
|
||||
void RenderBuffers::release()
|
||||
|
@ -88,6 +102,7 @@ void RenderBuffers::release()
|
|||
environment_tx.release();
|
||||
shadow_tx.release();
|
||||
ambient_occlusion_tx.release();
|
||||
cryptomatte_tx.release();
|
||||
}
|
||||
|
||||
} // namespace blender::eevee
|
||||
|
|
|
@ -35,7 +35,7 @@ class RenderBuffers {
|
|||
TextureFromPool environment_tx;
|
||||
TextureFromPool shadow_tx;
|
||||
TextureFromPool ambient_occlusion_tx;
|
||||
// TextureFromPool cryptomatte_tx; /* TODO */
|
||||
TextureFromPool cryptomatte_tx;
|
||||
/* TODO(fclem): Use texture from pool once they support texture array. */
|
||||
Texture light_tx;
|
||||
Texture aov_color_tx;
|
||||
|
|
|
@ -84,6 +84,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
|
|||
return "eevee_film_frag";
|
||||
case FILM_COMP:
|
||||
return "eevee_film_comp";
|
||||
case FILM_CRYPTOMATTE_POST:
|
||||
return "eevee_film_cryptomatte_post";
|
||||
case HIZ_DEBUG:
|
||||
return "eevee_hiz_debug";
|
||||
case HIZ_UPDATE:
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace blender::eevee {
|
|||
enum eShaderType {
|
||||
FILM_FRAG = 0,
|
||||
FILM_COMP,
|
||||
FILM_CRYPTOMATTE_POST,
|
||||
|
||||
DOF_BOKEH_LUT,
|
||||
DOF_DOWNSAMPLE,
|
||||
|
|
|
@ -199,6 +199,12 @@ enum eFilmWeightLayerIndex : uint32_t {
|
|||
FILM_WEIGHT_LAYER_DISTANCE = 1u,
|
||||
};
|
||||
|
||||
enum ePassStorageType : uint32_t {
|
||||
PASS_STORAGE_COLOR = 0u,
|
||||
PASS_STORAGE_VALUE = 1u,
|
||||
PASS_STORAGE_CRYPTOMATTE = 2u,
|
||||
};
|
||||
|
||||
struct FilmSample {
|
||||
int2 texel;
|
||||
float weight;
|
||||
|
@ -255,13 +261,19 @@ struct FilmData {
|
|||
int combined_id;
|
||||
/** Id of the render-pass to be displayed. -1 for combined. */
|
||||
int display_id;
|
||||
/** True if the render-pass to be displayed is from the value accum buffer. */
|
||||
bool1 display_is_value;
|
||||
/** Storage type of the render-pass to be displayed. */
|
||||
ePassStorageType display_storage_type;
|
||||
/** True if we bypass the accumulation and directly output the accumulation buffer. */
|
||||
bool1 display_only;
|
||||
/** Start of AOVs and number of aov. */
|
||||
int aov_color_id, aov_color_len;
|
||||
int aov_value_id, aov_value_len;
|
||||
/** Start of cryptomatte per layer (-1 if pass is not enabled). */
|
||||
int cryptomatte_object_id;
|
||||
int cryptomatte_asset_id;
|
||||
int cryptomatte_material_id;
|
||||
/** Max number of samples stored per layer (is even number). */
|
||||
int cryptomatte_samples_len;
|
||||
/** Settings to render mist pass */
|
||||
float mist_scale, mist_bias, mist_exponent;
|
||||
/** Scene exposure used for better noise reduction. */
|
||||
|
@ -750,6 +762,7 @@ using SamplingDataBuf = draw::StorageBuffer<SamplingData>;
|
|||
using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>;
|
||||
using VelocityIndexBuf = draw::StorageArrayBuffer<VelocityIndex, 16>;
|
||||
using VelocityObjectBuf = draw::StorageArrayBuffer<float4x4, 16>;
|
||||
using CryptomatteObjectBuf = draw::StorageArrayBuffer<float2, 16>;
|
||||
|
||||
} // namespace blender::eevee
|
||||
#endif
|
||||
|
|
|
@ -120,10 +120,14 @@ void SyncModule::sync_mesh(Object *ob,
|
|||
|
||||
is_shadow_caster = is_shadow_caster || material->shadow.sub_pass != nullptr;
|
||||
is_alpha_blend = is_alpha_blend || material->is_alpha_blend_transparent;
|
||||
|
||||
GPUMaterial *gpu_material = material_array.gpu_materials[i];
|
||||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
inst_.cryptomatte.sync_material(mat);
|
||||
}
|
||||
|
||||
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
|
||||
|
||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||
// shadows.sync_object(ob, ob_handle, is_shadow_caster, is_alpha_blend);
|
||||
}
|
||||
|
||||
|
@ -320,6 +324,12 @@ void SyncModule::sync_curves(Object *ob,
|
|||
shgroup_curves_call(material.prepass, ob, part_sys, modifier_data);
|
||||
shgroup_curves_call(material.shadow, ob, part_sys, modifier_data);
|
||||
|
||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||
GPUMaterial *gpu_material =
|
||||
inst_.materials.material_array_get(ob, has_motion).gpu_materials[mat_nr - 1];
|
||||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
inst_.cryptomatte.sync_material(mat);
|
||||
|
||||
/* TODO(fclem) Hair velocity. */
|
||||
// shading_passes.velocity.gpencil_add(ob, ob_handle);
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/** Storing/merging and sorting cryptomatte samples. */
|
||||
|
||||
bool cryptomatte_can_merge_sample(vec2 dst, vec2 src)
|
||||
{
|
||||
if (dst == vec2(0.0, 0.0)) {
|
||||
return true;
|
||||
}
|
||||
if (dst.x == src.x) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
vec2 cryptomatte_merge_sample(vec2 dst, vec2 src)
|
||||
{
|
||||
return vec2(src.x, dst.y + src.y);
|
||||
}
|
||||
|
||||
vec4 cryptomatte_false_color(float hash)
|
||||
{
|
||||
uint m3hash = floatBitsToUint(hash);
|
||||
return vec4(hash,
|
||||
float(m3hash << 8) / float(0xFFFFFFFFu),
|
||||
float(m3hash << 16) / float(0xFFFFFFFFu),
|
||||
1.0);
|
||||
}
|
||||
|
||||
void cryptomatte_clear_samples(FilmSample dst)
|
||||
{
|
||||
int layer_len = imageSize(cryptomatte_img).z;
|
||||
for (int i = 0; i < layer_len; i++) {
|
||||
imageStore(cryptomatte_img, ivec3(dst.texel, i), vec4(0.0));
|
||||
}
|
||||
}
|
||||
|
||||
void cryptomatte_store_film_sample(FilmSample dst,
|
||||
int cryptomatte_layer_id,
|
||||
vec2 crypto_sample,
|
||||
out vec4 out_color)
|
||||
{
|
||||
if (crypto_sample.y == 0.0) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < film_buf.cryptomatte_samples_len / 2; i++) {
|
||||
ivec3 img_co = ivec3(dst.texel, cryptomatte_layer_id + i);
|
||||
vec4 sample_pair = imageLoad(cryptomatte_img, img_co);
|
||||
if (cryptomatte_can_merge_sample(sample_pair.xy, crypto_sample)) {
|
||||
sample_pair.xy = cryptomatte_merge_sample(sample_pair.xy, crypto_sample);
|
||||
/* In viewport only one layer is active. */
|
||||
/* TODO(jbakker): we are displaying the first sample, but we should display the highest
|
||||
* weighted one. */
|
||||
if (cryptomatte_layer_id + i == 0) {
|
||||
out_color = cryptomatte_false_color(sample_pair.x);
|
||||
}
|
||||
}
|
||||
else if (cryptomatte_can_merge_sample(sample_pair.zw, crypto_sample)) {
|
||||
sample_pair.zw = cryptomatte_merge_sample(sample_pair.zw, crypto_sample);
|
||||
}
|
||||
else if (i == film_buf.cryptomatte_samples_len / 2 - 1) {
|
||||
/* TODO(jbakker): New hash detected, but there is no space left to store it. Currently we
|
||||
* will ignore this sample, but ideally we could replace a sample with a lowest weight. */
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
imageStore(cryptomatte_img, img_co, sample_pair);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
|
||||
#define CRYPTOMATTE_LEVELS_MAX 16
|
||||
|
||||
void cryptomatte_load_samples(ivec2 texel, int layer, out vec2 samples[CRYPTOMATTE_LEVELS_MAX])
|
||||
{
|
||||
int pass_len = divide_ceil(cryptomatte_samples_per_layer, 2);
|
||||
int layer_id = layer * pass_len;
|
||||
|
||||
/* Read all samples from the cryptomatte layer. */
|
||||
for (int p = 0; p < pass_len; p++) {
|
||||
vec4 pass_sample = imageLoad(cryptomatte_img, ivec3(texel, p + layer_id));
|
||||
samples[p * 2] = pass_sample.xy;
|
||||
samples[p * 2 + 1] = pass_sample.zw;
|
||||
}
|
||||
for (int i = pass_len * 2; i < CRYPTOMATTE_LEVELS_MAX; i++) {
|
||||
samples[i] = vec2(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void cryptomatte_sort_samples(inout vec2 samples[CRYPTOMATTE_LEVELS_MAX])
|
||||
{
|
||||
/* Sort samples. Lame implementation, can be replaced with a more efficient algorithm. */
|
||||
for (int i = 0; i < cryptomatte_samples_per_layer - 1 && samples[i].y != 0.0; i++) {
|
||||
int highest_index = i;
|
||||
float highest_weight = samples[i].y;
|
||||
for (int j = i + 1; j < cryptomatte_samples_per_layer && samples[j].y != 0.0; j++) {
|
||||
if (samples[j].y > highest_weight) {
|
||||
highest_index = j;
|
||||
highest_weight = samples[j].y;
|
||||
}
|
||||
};
|
||||
|
||||
if (highest_index != i) {
|
||||
vec2 tmp = samples[i];
|
||||
samples[i] = samples[highest_index];
|
||||
samples[highest_index] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
void cryptomatte_normalize_weight(float total_weight, inout vec2 samples[CRYPTOMATTE_LEVELS_MAX])
|
||||
{
|
||||
for (int i = 0; i < CRYPTOMATTE_LEVELS_MAX; i++) {
|
||||
samples[i].y /= total_weight;
|
||||
}
|
||||
}
|
||||
|
||||
void cryptomatte_store_samples(ivec2 texel, int layer, in vec2 samples[CRYPTOMATTE_LEVELS_MAX])
|
||||
{
|
||||
int pass_len = divide_ceil(cryptomatte_samples_per_layer, 2);
|
||||
int layer_id = layer * pass_len;
|
||||
|
||||
/* Store samples back to the cryptomatte layer. */
|
||||
for (int p = 0; p < pass_len; p++) {
|
||||
vec4 pass_sample;
|
||||
pass_sample.xy = samples[p * 2];
|
||||
pass_sample.zw = samples[p * 2 + 1];
|
||||
imageStore(cryptomatte_img, ivec3(texel, p + layer_id), pass_sample);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
for (int layer = 0; layer < cryptomatte_layer_len; layer++) {
|
||||
vec2 samples[CRYPTOMATTE_LEVELS_MAX];
|
||||
cryptomatte_load_samples(texel, layer, samples);
|
||||
cryptomatte_sort_samples(samples);
|
||||
/* Repeat texture coordinates as the weight can be optimized to a small portion of the film. */
|
||||
float weight = imageLoad(
|
||||
weight_img,
|
||||
ivec3(texel % imageSize(weight_img).xy, FILM_WEIGHT_LAYER_ACCUMULATION))
|
||||
.x;
|
||||
cryptomatte_normalize_weight(weight, samples);
|
||||
cryptomatte_store_samples(texel, layer, samples);
|
||||
}
|
||||
}
|
|
@ -13,13 +13,17 @@ void main()
|
|||
if (film_buf.display_id == -1) {
|
||||
out_color = texelFetch(in_combined_tx, texel_film, 0);
|
||||
}
|
||||
else if (film_buf.display_is_value) {
|
||||
else if (film_buf.display_storage_type == PASS_STORAGE_VALUE) {
|
||||
out_color.rgb = imageLoad(value_accum_img, ivec3(texel_film, film_buf.display_id)).rrr;
|
||||
out_color.a = 1.0;
|
||||
}
|
||||
else {
|
||||
else if (film_buf.display_storage_type == PASS_STORAGE_COLOR) {
|
||||
out_color = imageLoad(color_accum_img, ivec3(texel_film, film_buf.display_id));
|
||||
}
|
||||
else /* PASS_STORAGE_CRYPTOMATTE */ {
|
||||
out_color = cryptomatte_false_color(
|
||||
imageLoad(cryptomatte_img, ivec3(texel_film, film_buf.display_id)).r);
|
||||
}
|
||||
}
|
||||
else {
|
||||
film_process_data(texel_film, out_color, out_depth);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#pragma BLENDER_REQUIRE(eevee_camera_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_cryptomatte_lib.glsl)
|
||||
|
||||
/* Return scene linear Z depth from the camera or radial depth for panoramic cameras. */
|
||||
float film_depth_convert_to_scene(float depth)
|
||||
|
@ -158,6 +159,45 @@ void film_sample_accum_combined(FilmSample samp, inout vec4 accum, inout float w
|
|||
weight_accum += weight;
|
||||
}
|
||||
|
||||
void film_sample_cryptomatte_accum(FilmSample samp,
|
||||
int layer,
|
||||
sampler2D tex,
|
||||
inout vec2 crypto_samples[4])
|
||||
{
|
||||
float hash = texelFetch(tex, samp.texel, 0)[layer];
|
||||
/* Find existing entry. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (crypto_samples[i].x == hash) {
|
||||
crypto_samples[i].y += samp.weight;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Overwrite entry with less weight. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (crypto_samples[i].y < samp.weight) {
|
||||
crypto_samples[i] = vec2(hash, samp.weight);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void film_cryptomatte_layer_accum_and_store(
|
||||
FilmSample dst, ivec2 texel_film, int pass_id, int layer_component, inout vec4 out_color)
|
||||
{
|
||||
if (pass_id == -1) {
|
||||
return;
|
||||
}
|
||||
/* x = hash, y = accumed weight. Only keep track of 4 highest weighted samples. */
|
||||
vec2 crypto_samples[4] = vec2[4](vec2(0.0), vec2(0.0), vec2(0.0), vec2(0.0));
|
||||
for (int i = 0; i < film_buf.samples_len; i++) {
|
||||
FilmSample src = film_sample_get(i, texel_film);
|
||||
film_sample_cryptomatte_accum(src, layer_component, cryptomatte_tx, crypto_samples);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
cryptomatte_store_film_sample(dst, pass_id, crypto_samples[i], out_color);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -698,4 +738,18 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth
|
|||
}
|
||||
film_store_value(dst, film_buf.aov_value_id + aov, aov_accum, out_color);
|
||||
}
|
||||
|
||||
if (film_buf.cryptomatte_samples_len != 0) {
|
||||
/* Cryptomatte passes cannot be cleared by a weighted store like other passes. */
|
||||
if (!film_buf.use_history || film_buf.use_reprojection) {
|
||||
cryptomatte_clear_samples(dst);
|
||||
}
|
||||
|
||||
film_cryptomatte_layer_accum_and_store(
|
||||
dst, texel_film, film_buf.cryptomatte_object_id, 0, out_color);
|
||||
film_cryptomatte_layer_accum_and_store(
|
||||
dst, texel_film, film_buf.cryptomatte_asset_id, 1, out_color);
|
||||
film_cryptomatte_layer_accum_and_store(
|
||||
dst, texel_film, film_buf.cryptomatte_material_id, 2, out_color);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,9 @@ void main()
|
|||
imageStore(rp_diffuse_color_img, out_texel, vec4(g_diffuse_data.color, 1.0));
|
||||
imageStore(rp_specular_color_img, out_texel, vec4(specular_color, 1.0));
|
||||
imageStore(rp_emission_img, out_texel, vec4(g_emission, 1.0));
|
||||
imageStore(rp_cryptomatte_img,
|
||||
out_texel,
|
||||
vec4(cryptomatte_object_buf[resource_id], node_tree.crypto_hash, 0.0));
|
||||
#endif
|
||||
|
||||
out_radiance.rgb *= 1.0 - g_holdout;
|
||||
|
|
|
@ -33,6 +33,7 @@ void main()
|
|||
imageStore(rp_diffuse_color_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
|
||||
imageStore(rp_specular_color_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
|
||||
imageStore(rp_emission_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
|
||||
imageStore(rp_cryptomatte_img, out_texel, vec4(0.0));
|
||||
|
||||
out_background.rgb = safe_color(g_emission) * (1.0 - g_holdout);
|
||||
out_background.a = saturate(avg(g_transmittance)) * g_holdout;
|
||||
|
|
|
@ -21,7 +21,7 @@ GPU_SHADER_CREATE_INFO(eevee_film)
|
|||
.sampler(13, ImageType::FLOAT_2D_ARRAY, "aov_value_tx")
|
||||
/* Color History for TAA needs to be sampler to leverage bilinear sampling. */
|
||||
.sampler(14, ImageType::FLOAT_2D, "in_combined_tx")
|
||||
// .sampler(15, ImageType::FLOAT_2D, "cryptomatte_tx") /* TODO */
|
||||
.sampler(15, ImageType::FLOAT_2D, "cryptomatte_tx")
|
||||
.image(0, GPU_R32F, Qualifier::READ, ImageType::FLOAT_2D_ARRAY, "in_weight_img")
|
||||
.image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img")
|
||||
/* Color History for TAA needs to be sampler to leverage bilinear sampling. */
|
||||
|
@ -30,6 +30,7 @@ GPU_SHADER_CREATE_INFO(eevee_film)
|
|||
.image(4, GPU_R32F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "depth_img")
|
||||
.image(5, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D_ARRAY, "color_accum_img")
|
||||
.image(6, GPU_R16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D_ARRAY, "value_accum_img")
|
||||
.image(7, GPU_RGBA32F, Qualifier::READ_WRITE, ImageType::FLOAT_2D_ARRAY, "cryptomatte_img")
|
||||
.additional_info("eevee_shared")
|
||||
.additional_info("eevee_velocity_camera")
|
||||
.additional_info("draw_view");
|
||||
|
@ -45,3 +46,13 @@ GPU_SHADER_CREATE_INFO(eevee_film_comp)
|
|||
.local_group_size(FILM_GROUP_SIZE, FILM_GROUP_SIZE)
|
||||
.compute_source("eevee_film_comp.glsl")
|
||||
.additional_info("eevee_film");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_film_cryptomatte_post)
|
||||
.do_static_compilation(true)
|
||||
.image(0, GPU_RGBA32F, Qualifier::READ_WRITE, ImageType::FLOAT_2D_ARRAY, "cryptomatte_img")
|
||||
.image(1, GPU_R32F, Qualifier::READ, ImageType::FLOAT_2D_ARRAY, "weight_img")
|
||||
.push_constant(Type::INT, "cryptomatte_layer_len")
|
||||
.push_constant(Type::INT, "cryptomatte_samples_per_layer")
|
||||
.local_group_size(FILM_GROUP_SIZE, FILM_GROUP_SIZE)
|
||||
.compute_source("eevee_film_cryptomatte_post_comp.glsl")
|
||||
.additional_info("eevee_shared");
|
||||
|
|
|
@ -92,6 +92,10 @@ GPU_SHADER_CREATE_INFO(eevee_render_pass_out)
|
|||
.image_out(RBUFS_SPEC_COLOR_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img")
|
||||
.image_out(RBUFS_EMISSION_SLOT, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_cryptomatte_out)
|
||||
.storage_buf(7, Qualifier::READ, "vec2", "cryptomatte_object_buf[]", Frequency::PASS)
|
||||
.image_out(7, Qualifier::WRITE, GPU_RGBA32F, "rp_cryptomatte_img");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
|
||||
.vertex_out(eevee_surf_iface)
|
||||
/* NOTE: This removes the possibility of using gl_FragDepth. */
|
||||
|
@ -121,7 +125,10 @@ GPU_SHADER_CREATE_INFO(eevee_surf_forward)
|
|||
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
|
||||
.fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
|
||||
.fragment_source("eevee_surf_forward_frag.glsl")
|
||||
.additional_info("eevee_light_data", "eevee_utility_texture", "eevee_sampling_data"
|
||||
.additional_info("eevee_cryptomatte_out",
|
||||
"eevee_light_data",
|
||||
"eevee_utility_texture",
|
||||
"eevee_sampling_data"
|
||||
// "eevee_lightprobe_data",
|
||||
// "eevee_shadow_data"
|
||||
/* Optionally added depending on the material. */
|
||||
|
@ -141,7 +148,10 @@ GPU_SHADER_CREATE_INFO(eevee_surf_world)
|
|||
.push_constant(Type::FLOAT, "world_opacity_fade")
|
||||
.fragment_out(0, Type::VEC4, "out_background")
|
||||
.fragment_source("eevee_surf_world_frag.glsl")
|
||||
.additional_info("eevee_aov_out", "eevee_render_pass_out", "eevee_utility_texture");
|
||||
.additional_info("eevee_aov_out",
|
||||
"eevee_cryptomatte_out",
|
||||
"eevee_render_pass_out",
|
||||
"eevee_utility_texture");
|
||||
|
||||
#undef image_out
|
||||
#undef image_array_out
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_hash_mm2a.h"
|
||||
|
@ -20,6 +21,7 @@
|
|||
|
||||
#include "PIL_time.h"
|
||||
|
||||
#include "BKE_cryptomatte.hh"
|
||||
#include "BKE_material.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
|
@ -238,6 +240,7 @@ class GPUCodegen {
|
|||
uint32_t hash_ = 0;
|
||||
BLI_HashMurmur2A hm2a_;
|
||||
ListBase ubo_inputs_ = {nullptr, nullptr};
|
||||
GPUInput *cryptomatte_input_ = nullptr;
|
||||
|
||||
public:
|
||||
GPUCodegen(GPUMaterial *mat_, GPUNodeGraph *graph_) : mat(*mat_), graph(*graph_)
|
||||
|
@ -262,11 +265,13 @@ class GPUCodegen {
|
|||
MEM_SAFE_FREE(output.displacement);
|
||||
MEM_SAFE_FREE(output.composite);
|
||||
MEM_SAFE_FREE(output.material_functions);
|
||||
MEM_SAFE_FREE(cryptomatte_input_);
|
||||
delete create_info;
|
||||
BLI_freelistN(&ubo_inputs_);
|
||||
};
|
||||
|
||||
void generate_graphs();
|
||||
void generate_cryptomatte();
|
||||
void generate_uniform_buffer();
|
||||
void generate_attribs();
|
||||
void generate_resources();
|
||||
|
@ -399,7 +404,12 @@ void GPUCodegen::generate_resources()
|
|||
ss << "struct NodeTree {\n";
|
||||
LISTBASE_FOREACH (LinkData *, link, &ubo_inputs_) {
|
||||
GPUInput *input = (GPUInput *)(link->data);
|
||||
ss << input->type << " u" << input->id << ";\n";
|
||||
if (input->source == GPU_SOURCE_CRYPTOMATTE) {
|
||||
ss << input->type << " crypto_hash;\n";
|
||||
}
|
||||
else {
|
||||
ss << input->type << " u" << input->id << ";\n";
|
||||
}
|
||||
}
|
||||
ss << "};\n\n";
|
||||
|
||||
|
@ -535,6 +545,24 @@ char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag)
|
|||
return eval_c_str;
|
||||
}
|
||||
|
||||
void GPUCodegen::generate_cryptomatte()
|
||||
{
|
||||
cryptomatte_input_ = static_cast<GPUInput *>(MEM_callocN(sizeof(GPUInput), __func__));
|
||||
cryptomatte_input_->type = GPU_FLOAT;
|
||||
cryptomatte_input_->source = GPU_SOURCE_CRYPTOMATTE;
|
||||
|
||||
float material_hash = 0.0f;
|
||||
Material *material = GPU_material_get_material(&mat);
|
||||
if (material) {
|
||||
blender::bke::cryptomatte::CryptomatteHash hash(material->id.name,
|
||||
BLI_strnlen(material->id.name, MAX_NAME - 2));
|
||||
material_hash = hash.float_encoded();
|
||||
}
|
||||
cryptomatte_input_->vec[0] = material_hash;
|
||||
|
||||
BLI_addtail(&ubo_inputs_, BLI_genericNodeN(cryptomatte_input_));
|
||||
}
|
||||
|
||||
void GPUCodegen::generate_uniform_buffer()
|
||||
{
|
||||
/* Extract uniform inputs. */
|
||||
|
@ -615,6 +643,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
|
|||
|
||||
GPUCodegen codegen(material, graph);
|
||||
codegen.generate_graphs();
|
||||
codegen.generate_cryptomatte();
|
||||
codegen.generate_uniform_buffer();
|
||||
|
||||
/* Cache lookup: Reuse shaders already compiled. */
|
||||
|
|
|
@ -35,6 +35,7 @@ typedef enum eGPUDataSource {
|
|||
GPU_SOURCE_TEX,
|
||||
GPU_SOURCE_TEX_TILED_MAPPING,
|
||||
GPU_SOURCE_FUNCTION_CALL,
|
||||
GPU_SOURCE_CRYPTOMATTE,
|
||||
} eGPUDataSource;
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -34,10 +34,18 @@ typedef enum eViewLayerEEVEEPassType {
|
|||
EEVEE_RENDER_PASS_AO = (1 << 13),
|
||||
EEVEE_RENDER_PASS_BLOOM = (1 << 14),
|
||||
EEVEE_RENDER_PASS_AOV = (1 << 15),
|
||||
/*
|
||||
* TODO(jbakker): Clean up confliting bits after EEVEE has been removed.
|
||||
* EEVEE_RENDER_PASS_CRYPTOMATTE is for EEVEE, EEVEE_RENDER_PASS_CRYTPOMATTE_* are for
|
||||
* EEVEE-Next.
|
||||
*/
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE = (1 << 16),
|
||||
EEVEE_RENDER_PASS_VECTOR = (1 << 17),
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT = (1 << 16),
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET = (1 << 17),
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL = (1 << 18),
|
||||
EEVEE_RENDER_PASS_VECTOR = (1 << 19),
|
||||
} eViewLayerEEVEEPassType;
|
||||
#define EEVEE_RENDER_PASS_MAX_BIT 18
|
||||
#define EEVEE_RENDER_PASS_MAX_BIT 20
|
||||
|
||||
/* #ViewLayerAOV.type */
|
||||
typedef enum eViewLayerAOVType {
|
||||
|
|
|
@ -304,6 +304,10 @@ typedef enum eScenePassType {
|
|||
#define RE_PASSNAME_BLOOM "BloomCol"
|
||||
#define RE_PASSNAME_VOLUME_LIGHT "VolumeDir"
|
||||
|
||||
#define RE_PASSNAME_CRYPTOMATTE_OBJECT "CryptoObject"
|
||||
#define RE_PASSNAME_CRYPTOMATTE_ASSET "CryptoAsset"
|
||||
#define RE_PASSNAME_CRYPTOMATTE_MATERIAL "CryptoMaterial"
|
||||
|
||||
/** View - MultiView. */
|
||||
typedef struct SceneRenderView {
|
||||
struct SceneRenderView *next, *prev;
|
||||
|
|
|
@ -455,6 +455,9 @@ static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] =
|
|||
RNA_ENUM_ITEM_HEADING(N_("Data"), NULL),
|
||||
{EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
|
||||
{EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""},
|
||||
{EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT, "CryptoObject", 0, "CryptoObject", ""},
|
||||
{EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET, "CryptoAsset", 0, "CryptoAsset", ""},
|
||||
{EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL, "CryptoMaterial", 0, "CryptoMaterial", ""},
|
||||
|
||||
RNA_ENUM_ITEM_HEADING(N_("Shader AOV"), NULL),
|
||||
{EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""},
|
||||
|
@ -1423,6 +1426,7 @@ static const EnumPropertyItem *rna_3DViewShading_render_pass_itemf(bContext *C,
|
|||
|
||||
const bool bloom_enabled = scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED;
|
||||
const bool aov_available = BKE_view_layer_has_valid_aov(view_layer);
|
||||
const bool eevee_next_active = STREQ(scene->r.engine, "BLENDER_EEVEE_NEXT");
|
||||
|
||||
int totitem = 0;
|
||||
EnumPropertyItem *result = NULL;
|
||||
|
@ -1443,6 +1447,12 @@ static const EnumPropertyItem *rna_3DViewShading_render_pass_itemf(bContext *C,
|
|||
aov_template.value++;
|
||||
}
|
||||
}
|
||||
else if (ELEM(item->value,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET,
|
||||
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL) &&
|
||||
!eevee_next_active) {
|
||||
}
|
||||
else if (!((!bloom_enabled &&
|
||||
(item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))) ||
|
||||
(!aov_available && STREQ(item->name, "Shader AOV")))) {
|
||||
|
|
Loading…
Reference in New Issue