Files
test2/source/blender/draw/engines/eevee/eevee_material.hh
Clément Foucault 894c7fa4e2 EEVEE: Remove EEVEE Next mention inside the code
This only changes file and function names.
The EEVEE identifier is still `BLENDER_EEVEE_NEXT`.

No functional changes.
2025-03-17 15:37:04 +01:00

405 lines
11 KiB
C++

/* SPDX-FileCopyrightText: 2021 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup eevee
*/
#pragma once
#include "DNA_material_types.h"
#include "DRW_render.hh"
#include "BLI_map.hh"
#include "BLI_vector.hh"
#include "GPU_material.hh"
#include "eevee_sync.hh"
struct bNodeSocketValueFloat;
struct bNodeSocketValueRGBA;
namespace blender::eevee {
class Instance;
/* -------------------------------------------------------------------- */
/** \name MaterialKey
*
* \{ */
enum eMaterialPipeline {
MAT_PIPE_DEFERRED = 0,
MAT_PIPE_FORWARD,
/* These all map to the depth shader. */
MAT_PIPE_PREPASS_DEFERRED,
MAT_PIPE_PREPASS_DEFERRED_VELOCITY,
MAT_PIPE_PREPASS_OVERLAP,
MAT_PIPE_PREPASS_FORWARD,
MAT_PIPE_PREPASS_FORWARD_VELOCITY,
MAT_PIPE_PREPASS_PLANAR,
MAT_PIPE_VOLUME_MATERIAL,
MAT_PIPE_VOLUME_OCCUPANCY,
MAT_PIPE_SHADOW,
MAT_PIPE_CAPTURE,
};
enum eMaterialGeometry {
/* These maps directly to object types. */
MAT_GEOM_MESH = 0,
MAT_GEOM_POINTCLOUD,
MAT_GEOM_CURVES,
MAT_GEOM_GPENCIL,
MAT_GEOM_VOLUME,
/* These maps to special shader. */
MAT_GEOM_WORLD,
};
static inline bool geometry_type_has_surface(eMaterialGeometry geometry_type)
{
return geometry_type < MAT_GEOM_VOLUME;
}
enum eMaterialDisplacement {
MAT_DISPLACEMENT_BUMP = 0,
MAT_DISPLACEMENT_VERTEX_WITH_BUMP,
};
static inline eMaterialDisplacement to_displacement_type(int displacement_method)
{
switch (displacement_method) {
case MA_DISPLACEMENT_DISPLACE:
/* Currently unsupported. Revert to vertex displacement + bump. */
ATTR_FALLTHROUGH;
case MA_DISPLACEMENT_BOTH:
return MAT_DISPLACEMENT_VERTEX_WITH_BUMP;
default:
return MAT_DISPLACEMENT_BUMP;
}
}
enum eMaterialThickness {
/* These maps directly to thickness mode. */
MAT_THICKNESS_SPHERE = 0,
MAT_THICKNESS_SLAB,
};
static inline eMaterialThickness to_thickness_type(int thickness_mode)
{
switch (thickness_mode) {
case MA_THICKNESS_SLAB:
return MAT_THICKNESS_SLAB;
default:
return MAT_THICKNESS_SPHERE;
}
}
enum eMaterialProbe {
MAT_PROBE_NONE = 0,
MAT_PROBE_REFLECTION,
MAT_PROBE_PLANAR,
};
static inline void material_type_from_shader_uuid(uint64_t shader_uuid,
eMaterialPipeline &pipeline_type,
eMaterialGeometry &geometry_type,
eMaterialDisplacement &displacement_type,
eMaterialThickness &thickness_type,
bool &transparent_shadows)
{
const uint64_t geometry_mask = ((1u << 4u) - 1u);
const uint64_t pipeline_mask = ((1u << 4u) - 1u);
const uint64_t thickness_mask = ((1u << 1u) - 1u);
const uint64_t displacement_mask = ((1u << 1u) - 1u);
geometry_type = static_cast<eMaterialGeometry>(shader_uuid & geometry_mask);
pipeline_type = static_cast<eMaterialPipeline>((shader_uuid >> 4u) & pipeline_mask);
displacement_type = static_cast<eMaterialDisplacement>((shader_uuid >> 8u) & displacement_mask);
thickness_type = static_cast<eMaterialThickness>((shader_uuid >> 9u) & thickness_mask);
transparent_shadows = (shader_uuid >> 10u) & 1u;
}
static inline uint64_t shader_uuid_from_material_type(
eMaterialPipeline pipeline_type,
eMaterialGeometry geometry_type,
eMaterialDisplacement displacement_type = MAT_DISPLACEMENT_BUMP,
eMaterialThickness thickness_type = MAT_THICKNESS_SPHERE,
char blend_flags = 0)
{
BLI_assert(displacement_type < (1 << 1));
BLI_assert(thickness_type < (1 << 1));
BLI_assert(geometry_type < (1 << 4));
BLI_assert(pipeline_type < (1 << 4));
uint64_t transparent_shadows = blend_flags & MA_BL_TRANSPARENT_SHADOW ? 1 : 0;
uint64_t uuid;
uuid = geometry_type;
uuid |= pipeline_type << 4;
uuid |= displacement_type << 8;
uuid |= thickness_type << 9;
uuid |= transparent_shadows << 10;
return uuid;
}
ENUM_OPERATORS(eClosureBits, CLOSURE_AMBIENT_OCCLUSION)
static inline eClosureBits shader_closure_bits_from_flag(const GPUMaterial *gpumat)
{
eClosureBits closure_bits = eClosureBits(0);
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE)) {
closure_bits |= CLOSURE_DIFFUSE;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
closure_bits |= CLOSURE_TRANSPARENCY;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSLUCENT)) {
closure_bits |= CLOSURE_TRANSLUCENT;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_EMISSION)) {
closure_bits |= CLOSURE_EMISSION;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY)) {
closure_bits |= CLOSURE_REFLECTION;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_COAT)) {
closure_bits |= CLOSURE_CLEARCOAT;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE)) {
closure_bits |= CLOSURE_SSS;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT)) {
closure_bits |= CLOSURE_REFRACTION;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_HOLDOUT)) {
closure_bits |= CLOSURE_HOLDOUT;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_AO)) {
closure_bits |= CLOSURE_AMBIENT_OCCLUSION;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SHADER_TO_RGBA)) {
closure_bits |= CLOSURE_SHADER_TO_RGBA;
}
return closure_bits;
}
static inline eMaterialGeometry to_material_geometry(const Object *ob)
{
switch (ob->type) {
case OB_CURVES:
return MAT_GEOM_CURVES;
case OB_VOLUME:
return MAT_GEOM_VOLUME;
case OB_GREASE_PENCIL:
return MAT_GEOM_GPENCIL;
case OB_POINTCLOUD:
return MAT_GEOM_POINTCLOUD;
default:
return MAT_GEOM_MESH;
}
}
/**
* Unique key to identify each material in the hash-map.
* This is above the shader binning.
*/
struct MaterialKey {
::Material *mat;
uint64_t options;
MaterialKey(::Material *mat_,
eMaterialGeometry geometry,
eMaterialPipeline pipeline,
short visibility_flags)
: mat(mat_)
{
options = shader_uuid_from_material_type(pipeline,
geometry,
to_displacement_type(mat_->displacement_method),
to_thickness_type(mat_->thickness_mode),
mat_->blend_flag);
options = (options << 1) | (visibility_flags & OB_HIDE_CAMERA ? 0 : 1);
options = (options << 1) | (visibility_flags & OB_HIDE_SHADOW ? 0 : 1);
options = (options << 1) | (visibility_flags & OB_HIDE_PROBE_CUBEMAP ? 0 : 1);
options = (options << 1) | (visibility_flags & OB_HIDE_PROBE_PLANAR ? 0 : 1);
}
uint64_t hash() const
{
return uint64_t(mat) + options;
}
bool operator<(const MaterialKey &k) const
{
if (mat == k.mat) {
return options < k.options;
}
return mat < k.mat;
}
bool operator==(const MaterialKey &k) const
{
return (mat == k.mat) && (options == k.options);
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name ShaderKey
*
* \{ */
/**
* Key used to find the sub-pass that already renders objects with the same shader.
* This avoids the cost associated with shader switching.
* This is below the material binning.
* Should only include pipeline options that are not baked in the shader itself.
*/
struct ShaderKey {
GPUShader *shader;
uint64_t options;
ShaderKey(GPUMaterial *gpumat, ::Material *blender_mat, eMaterialProbe probe_capture)
{
shader = GPU_material_get_shader(gpumat);
options = uint64_t(shader_closure_bits_from_flag(gpumat));
options = (options << 8) | blender_mat->blend_flag;
options = (options << 2) | uint64_t(probe_capture);
}
uint64_t hash() const
{
return uint64_t(shader) + options;
}
bool operator<(const ShaderKey &k) const
{
return (shader == k.shader) ? (options < k.options) : (shader < k.shader);
}
bool operator==(const ShaderKey &k) const
{
return (shader == k.shader) && (options == k.options);
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name Default Material Node-Tree
*
* In order to support materials without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the Material even if
* it does not use the same nodetree.
*
* \{ */
class DefaultSurfaceNodeTree {
private:
bNodeTree *ntree_;
bNodeSocketValueRGBA *color_socket_;
bNodeSocketValueFloat *metallic_socket_;
bNodeSocketValueFloat *roughness_socket_;
bNodeSocketValueFloat *specular_socket_;
public:
DefaultSurfaceNodeTree();
~DefaultSurfaceNodeTree();
/** Configure a default node-tree with the given material. */
bNodeTree *nodetree_get(::Material *ma);
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name Material
*
* \{ */
struct MaterialPass {
GPUMaterial *gpumat;
PassMain::Sub *sub_pass;
};
struct Material {
bool is_alpha_blend_transparent;
bool has_transparent_shadows;
bool has_surface;
bool has_volume;
MaterialPass shadow;
MaterialPass shading;
MaterialPass prepass;
MaterialPass overlap_masking;
MaterialPass capture;
MaterialPass lightprobe_sphere_prepass;
MaterialPass lightprobe_sphere_shading;
MaterialPass planar_probe_prepass;
MaterialPass planar_probe_shading;
MaterialPass volume_occupancy;
MaterialPass volume_material;
};
struct MaterialArray {
Vector<Material> materials;
Vector<GPUMaterial *> gpu_materials;
};
class MaterialModule {
public:
::Material *diffuse_mat;
::Material *metallic_mat;
int64_t queued_shaders_count = 0;
int64_t queued_optimize_shaders_count = 0;
private:
Instance &inst_;
Map<MaterialKey, Material> material_map_;
Map<ShaderKey, PassMain::Sub *> shader_map_;
MaterialArray material_array_;
DefaultSurfaceNodeTree default_surface_ntree_;
::Material *error_mat_;
public:
MaterialModule(Instance &inst);
~MaterialModule();
void begin_sync();
/**
* Returned Material references are valid until the next call to this function or material_get().
*/
MaterialArray &material_array_get(Object *ob, bool has_motion);
/**
* Returned Material references are valid until the next call to this function or
* material_array_get().
*/
Material &material_get(Object *ob, bool has_motion, int mat_nr, eMaterialGeometry geometry_type);
private:
Material &material_sync(Object *ob,
::Material *blender_mat,
eMaterialGeometry geometry_type,
bool has_motion);
/** Return correct material or empty default material if slot is empty. */
::Material *material_from_slot(Object *ob, int slot);
MaterialPass material_pass_get(Object *ob,
::Material *blender_mat,
eMaterialPipeline pipeline_type,
eMaterialGeometry geometry_type,
eMaterialProbe probe_capture = MAT_PROBE_NONE);
};
/** \} */
} // namespace blender::eevee