diff options
Diffstat (limited to 'source/blender/draw/engines/eevee_next/eevee_material.hh')
-rw-r--r-- | source/blender/draw/engines/eevee_next/eevee_material.hh | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh new file mode 100644 index 00000000000..0c454128aba --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_material.hh @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + */ + +#pragma once + +#include "DRW_render.h" + +#include "BLI_map.hh" +#include "BLI_vector.hh" +#include "GPU_material.h" + +#include "eevee_sync.hh" + +namespace blender::eevee { + +class Instance; + +/* -------------------------------------------------------------------- */ +/** \name MaterialKey + * + * \{ */ + +enum eMaterialPipeline { + MAT_PIPE_DEFERRED = 0, + MAT_PIPE_FORWARD = 1, + MAT_PIPE_DEFERRED_PREPASS = 2, + MAT_PIPE_FORWARD_PREPASS = 3, + MAT_PIPE_VOLUME = 4, + MAT_PIPE_SHADOW = 5, +}; + +enum eMaterialGeometry { + MAT_GEOM_MESH = 0, + MAT_GEOM_CURVES = 1, + MAT_GEOM_GPENCIL = 2, + MAT_GEOM_VOLUME = 3, + MAT_GEOM_WORLD = 4, +}; + +static inline void material_type_from_shader_uuid(uint64_t shader_uuid, + eMaterialPipeline &pipeline_type, + eMaterialGeometry &geometry_type) +{ + const uint64_t geometry_mask = ((1u << 3u) - 1u); + const uint64_t pipeline_mask = ((1u << 3u) - 1u); + geometry_type = static_cast<eMaterialGeometry>(shader_uuid & geometry_mask); + pipeline_type = static_cast<eMaterialPipeline>((shader_uuid >> 3u) & pipeline_mask); +} + +static inline uint64_t shader_uuid_from_material_type(eMaterialPipeline pipeline_type, + eMaterialGeometry geometry_type) +{ + return geometry_type | (pipeline_type << 3); +} + +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_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_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; + } + 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_GPENCIL: + return MAT_GEOM_GPENCIL; + default: + return MAT_GEOM_MESH; + } +} + +/** Unique key to identify each material in the hashmap. */ +struct MaterialKey { + Material *mat; + uint64_t options; + + MaterialKey(::Material *mat_, eMaterialGeometry geometry, eMaterialPipeline surface_pipeline) + : mat(mat_) + { + options = shader_uuid_from_material_type(surface_pipeline, geometry); + } + + uint64_t hash(void) const + { + BLI_assert(options < sizeof(*mat)); + return (uint64_t)mat + options; + } + + bool operator<(const MaterialKey &k) const + { + return (mat < k.mat) || (options < k.options); + } + + bool operator==(const MaterialKey &k) const + { + return (mat == k.mat) && (options == k.options); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ShaderKey + * + * \{ */ + +struct ShaderKey { + GPUShader *shader; + uint64_t options; + + ShaderKey(GPUMaterial *gpumat, eMaterialGeometry geometry, eMaterialPipeline pipeline) + { + shader = GPU_material_get_shader(gpumat); + options = shader_uuid_from_material_type(pipeline, geometry); + options = (options << 16u) | shader_closure_bits_from_flag(gpumat); + } + + uint64_t hash(void) 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 Nodetree + * + * 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(); + + bNodeTree *nodetree_get(::Material *ma); +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Material + * + * \{ */ + +struct MaterialPass { + GPUMaterial *gpumat = nullptr; + DRWShadingGroup *shgrp = nullptr; +}; + +struct Material { + bool init = false; + bool is_alpha_blend_transparent; + MaterialPass shadow, shading, prepass; +}; + +struct MaterialArray { + Vector<Material *> materials; + Vector<GPUMaterial *> gpu_materials; +}; + +class MaterialModule { + public: + ::Material *diffuse_mat_; + ::Material *glossy_mat_; + + private: + Instance &inst_; + + Map<MaterialKey, Material *> material_map_; + Map<ShaderKey, DRWShadingGroup *> shader_map_; + + MaterialArray material_array_; + + DefaultSurfaceNodeTree default_surface_ntree_; + + ::Material *error_mat_; + + int64_t queued_shaders_count_ = 0; + + public: + MaterialModule(Instance &inst); + ~MaterialModule(); + + void begin_sync(void); + + MaterialArray &material_array_get(Object *ob); + Material &material_get(Object *ob, int mat_nr, eMaterialGeometry geometry_type); + + private: + Material &material_sync(::Material *blender_mat, eMaterialGeometry geometry_type); + + ::Material *material_from_slot(Object *ob, int slot); + MaterialPass material_pass_get(::Material *blender_mat, + eMaterialPipeline pipeline_type, + eMaterialGeometry geometry_type); +}; + +/** \} */ + +} // namespace blender::eevee
\ No newline at end of file |