Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/engines/eevee_next/eevee_material.cc')
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.cc320
1 files changed, 320 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc
new file mode 100644
index 00000000000..f3132185683
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_material.cc
@@ -0,0 +1,320 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ */
+
+#include "DNA_material_types.h"
+
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
+#include "NOD_shader.h"
+
+#include "eevee_instance.hh"
+
+#include "eevee_material.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name Default Material
+ *
+ * \{ */
+
+DefaultSurfaceNodeTree::DefaultSurfaceNodeTree()
+{
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
+ bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_PRINCIPLED);
+ bNode *output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL);
+ bNodeSocket *bsdf_out = nodeFindSocket(bsdf, SOCK_OUT, "BSDF");
+ bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface");
+ nodeAddLink(ntree, bsdf, bsdf_out, output, output_in);
+ nodeSetActive(ntree, output);
+
+ color_socket_ =
+ (bNodeSocketValueRGBA *)nodeFindSocket(bsdf, SOCK_IN, "Base Color")->default_value;
+ metallic_socket_ =
+ (bNodeSocketValueFloat *)nodeFindSocket(bsdf, SOCK_IN, "Metallic")->default_value;
+ roughness_socket_ =
+ (bNodeSocketValueFloat *)nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value;
+ specular_socket_ =
+ (bNodeSocketValueFloat *)nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value;
+ ntree_ = ntree;
+}
+
+DefaultSurfaceNodeTree::~DefaultSurfaceNodeTree()
+{
+ ntreeFreeEmbeddedTree(ntree_);
+ MEM_SAFE_FREE(ntree_);
+}
+
+/* Configure a default nodetree with the given material. */
+bNodeTree *DefaultSurfaceNodeTree::nodetree_get(::Material *ma)
+{
+ /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
+ copy_v3_fl3(color_socket_->value, ma->r, ma->g, ma->b);
+ metallic_socket_->value = ma->metallic;
+ roughness_socket_->value = ma->roughness;
+ specular_socket_->value = ma->spec;
+
+ return ntree_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Material
+ *
+ * \{ */
+
+MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
+{
+ {
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
+
+ diffuse_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default diffuse");
+ diffuse_mat_->nodetree = ntree;
+ diffuse_mat_->use_nodes = true;
+ /* To use the forward pipeline. */
+ diffuse_mat_->blend_method = MA_BM_BLEND;
+
+ bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_DIFFUSE);
+ bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
+ copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 0.8f);
+
+ bNode *output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL);
+
+ nodeAddLink(ntree,
+ bsdf,
+ nodeFindSocket(bsdf, SOCK_OUT, "BSDF"),
+ output,
+ nodeFindSocket(output, SOCK_IN, "Surface"));
+
+ nodeSetActive(ntree, output);
+ }
+ {
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
+
+ glossy_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default metal");
+ glossy_mat_->nodetree = ntree;
+ glossy_mat_->use_nodes = true;
+ /* To use the forward pipeline. */
+ glossy_mat_->blend_method = MA_BM_BLEND;
+
+ bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_GLOSSY);
+ bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
+ copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 1.0f);
+ bNodeSocket *roughness = nodeFindSocket(bsdf, SOCK_IN, "Roughness");
+ ((bNodeSocketValueFloat *)roughness->default_value)->value = 0.0f;
+
+ bNode *output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL);
+
+ nodeAddLink(ntree,
+ bsdf,
+ nodeFindSocket(bsdf, SOCK_OUT, "BSDF"),
+ output,
+ nodeFindSocket(output, SOCK_IN, "Surface"));
+
+ nodeSetActive(ntree, output);
+ }
+ {
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
+
+ error_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default error");
+ error_mat_->nodetree = ntree;
+ error_mat_->use_nodes = true;
+
+ /* Use emission and output material to be compatible with both World and Material. */
+ bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_EMISSION);
+ bNodeSocket *color = nodeFindSocket(bsdf, SOCK_IN, "Color");
+ copy_v3_fl3(((bNodeSocketValueRGBA *)color->default_value)->value, 1.0f, 0.0f, 1.0f);
+
+ bNode *output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL);
+
+ nodeAddLink(ntree,
+ bsdf,
+ nodeFindSocket(bsdf, SOCK_OUT, "Emission"),
+ output,
+ nodeFindSocket(output, SOCK_IN, "Surface"));
+
+ nodeSetActive(ntree, output);
+ }
+}
+
+MaterialModule::~MaterialModule()
+{
+ for (Material *mat : material_map_.values()) {
+ delete mat;
+ }
+ BKE_id_free(nullptr, glossy_mat_);
+ BKE_id_free(nullptr, diffuse_mat_);
+ BKE_id_free(nullptr, error_mat_);
+}
+
+void MaterialModule::begin_sync(void)
+{
+ queued_shaders_count_ = 0;
+
+ for (Material *mat : material_map_.values()) {
+ mat->init = false;
+ }
+ shader_map_.clear();
+}
+
+MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
+ eMaterialPipeline pipeline_type,
+ eMaterialGeometry geometry_type)
+{
+ bNodeTree *ntree = (blender_mat->use_nodes && blender_mat->nodetree != nullptr) ?
+ blender_mat->nodetree :
+ default_surface_ntree_.nodetree_get(blender_mat);
+
+ MaterialPass matpass;
+ matpass.gpumat = inst_.shaders.material_shader_get(
+ blender_mat, ntree, pipeline_type, geometry_type, true);
+
+ switch (GPU_material_status(matpass.gpumat)) {
+ case GPU_MAT_SUCCESS:
+ break;
+ case GPU_MAT_QUEUED:
+ queued_shaders_count_++;
+ blender_mat = (geometry_type == MAT_GEOM_VOLUME) ? BKE_material_default_volume() :
+ BKE_material_default_surface();
+ matpass.gpumat = inst_.shaders.material_shader_get(
+ blender_mat, blender_mat->nodetree, pipeline_type, geometry_type, false);
+ break;
+ case GPU_MAT_FAILED:
+ default:
+ matpass.gpumat = inst_.shaders.material_shader_get(
+ error_mat_, error_mat_->nodetree, pipeline_type, geometry_type, false);
+ break;
+ }
+ /* Returned material should be ready to be drawn. */
+ BLI_assert(GPU_material_status(matpass.gpumat) == GPU_MAT_SUCCESS);
+
+ if (GPU_material_recalc_flag_get(matpass.gpumat)) {
+ // inst_.sampling.reset();
+ }
+
+ if ((pipeline_type == MAT_PIPE_DEFERRED) &&
+ GPU_material_flag_get(matpass.gpumat, GPU_MATFLAG_SHADER_TO_RGBA)) {
+ pipeline_type = MAT_PIPE_FORWARD;
+ }
+
+ if ((pipeline_type == MAT_PIPE_FORWARD) &&
+ GPU_material_flag_get(matpass.gpumat, GPU_MATFLAG_TRANSPARENT)) {
+ /* Transparent needs to use one shgroup per object to support reordering. */
+ matpass.shgrp = inst_.pipelines.material_add(blender_mat, matpass.gpumat, pipeline_type);
+ }
+ else {
+ ShaderKey shader_key(matpass.gpumat, geometry_type, pipeline_type);
+
+ auto add_cb = [&]() -> DRWShadingGroup * {
+ /* First time encountering this shader. Create a shading group. */
+ return inst_.pipelines.material_add(blender_mat, matpass.gpumat, pipeline_type);
+ };
+ DRWShadingGroup *grp = shader_map_.lookup_or_add_cb(shader_key, add_cb);
+
+ if (grp != nullptr) {
+ /* Shading group for this shader already exists. Create a sub one for this material. */
+ /* IMPORTANT: We always create a subgroup so that all subgroups are inserted after the
+ * first "empty" shgroup. This avoids messing the order of subgroups when there is more
+ * nested subgroup (i.e: hair drawing). */
+ /* TODO(fclem) Remove material resource binding from the first group creation. */
+ matpass.shgrp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_add_material_resources(matpass.shgrp, matpass.gpumat);
+ }
+ }
+
+ return matpass;
+}
+
+Material &MaterialModule::material_sync(::Material *blender_mat, eMaterialGeometry geometry_type)
+{
+ eMaterialPipeline surface_pipe = (blender_mat->blend_method == MA_BM_BLEND) ? MAT_PIPE_FORWARD :
+ MAT_PIPE_DEFERRED;
+ eMaterialPipeline prepass_pipe = (blender_mat->blend_method == MA_BM_BLEND) ?
+ MAT_PIPE_FORWARD_PREPASS :
+ MAT_PIPE_DEFERRED_PREPASS;
+
+ /* Test */
+ surface_pipe = MAT_PIPE_FORWARD;
+ prepass_pipe = MAT_PIPE_FORWARD_PREPASS;
+
+ MaterialKey material_key(blender_mat, geometry_type, surface_pipe);
+
+ /* TODO allocate in blocks to avoid memory fragmentation. */
+ auto add_cb = [&]() { return new Material(); };
+ Material &mat = *material_map_.lookup_or_add_cb(material_key, add_cb);
+
+ /* Forward pipeline needs to use one shgroup per object. */
+ if (mat.init == false || (surface_pipe == MAT_PIPE_FORWARD)) {
+ mat.init = true;
+ /* Order is important for transparent. */
+ mat.prepass = material_pass_get(blender_mat, prepass_pipe, geometry_type);
+ mat.shading = material_pass_get(blender_mat, surface_pipe, geometry_type);
+ if (blender_mat->blend_shadow == MA_BS_NONE) {
+ mat.shadow = MaterialPass();
+ }
+ else {
+ mat.shadow = material_pass_get(blender_mat, MAT_PIPE_SHADOW, geometry_type);
+ }
+
+ mat.is_alpha_blend_transparent = (blender_mat->blend_method == MA_BM_BLEND) &&
+ GPU_material_flag_get(mat.prepass.gpumat,
+ GPU_MATFLAG_TRANSPARENT);
+ }
+ return mat;
+}
+
+/* Return correct material or empty default material if slot is empty. */
+::Material *MaterialModule::material_from_slot(Object *ob, int slot)
+{
+ if (ob->base_flag & BASE_HOLDOUT) {
+ return BKE_material_default_holdout();
+ }
+ ::Material *ma = BKE_object_material_get(ob, slot + 1);
+ if (ma == nullptr) {
+ if (ob->type == OB_VOLUME) {
+ return BKE_material_default_volume();
+ }
+ else {
+ return BKE_material_default_surface();
+ }
+ }
+ return ma;
+}
+
+/* Returned Material references are valid until the next call to this function or
+ * material_get(). */
+MaterialArray &MaterialModule::material_array_get(Object *ob)
+{
+ material_array_.materials.clear();
+ material_array_.gpu_materials.clear();
+
+ const int materials_len = DRW_cache_object_material_count_get(ob);
+
+ for (auto i : IndexRange(materials_len)) {
+ ::Material *blender_mat = material_from_slot(ob, i);
+ Material &mat = material_sync(blender_mat, to_material_geometry(ob));
+ material_array_.materials.append(&mat);
+ material_array_.gpu_materials.append(mat.shading.gpumat);
+ }
+ return material_array_;
+}
+
+/* Returned Material references are valid until the next call to this function or
+ * material_array_get(). */
+Material &MaterialModule::material_get(Object *ob, int mat_nr, eMaterialGeometry geometry_type)
+{
+ ::Material *blender_mat = material_from_slot(ob, mat_nr);
+ Material &mat = material_sync(blender_mat, geometry_type);
+ return mat;
+}
+
+/** \} */
+
+} // namespace blender::eevee \ No newline at end of file