Blender  V3.3
eevee_material.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation.
3  */
4 
9 #include "DNA_material_types.h"
10 
11 #include "BKE_lib_id.h"
12 #include "BKE_material.h"
13 #include "BKE_node.h"
14 #include "NOD_shader.h"
15 
16 #include "eevee_instance.hh"
17 
18 #include "eevee_material.hh"
19 
20 namespace blender::eevee {
21 
22 /* -------------------------------------------------------------------- */
28 {
29  bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
32  bNodeSocket *bsdf_out = nodeFindSocket(bsdf, SOCK_OUT, "BSDF");
33  bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface");
34  nodeAddLink(ntree, bsdf, bsdf_out, output, output_in);
36 
37  color_socket_ =
39  metallic_socket_ =
41  roughness_socket_ =
43  specular_socket_ =
45  ntree_ = ntree;
46 }
47 
49 {
50  ntreeFreeEmbeddedTree(ntree_);
51  MEM_SAFE_FREE(ntree_);
52 }
53 
55 {
56  /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
57  copy_v3_fl3(color_socket_->value, ma->r, ma->g, ma->b);
58  metallic_socket_->value = ma->metallic;
59  roughness_socket_->value = ma->roughness;
60  specular_socket_->value = ma->spec;
61 
62  return ntree_;
63 }
64 
67 /* -------------------------------------------------------------------- */
73 {
74  {
75  bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
76 
77  diffuse_mat = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default diffuse");
78  diffuse_mat->nodetree = ntree;
79  diffuse_mat->use_nodes = true;
80  /* To use the forward pipeline. */
81  diffuse_mat->blend_method = MA_BM_BLEND;
82 
84  bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
85  copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 0.8f);
86 
88 
90  bsdf,
91  nodeFindSocket(bsdf, SOCK_OUT, "BSDF"),
92  output,
93  nodeFindSocket(output, SOCK_IN, "Surface"));
94 
96  }
97  {
98  bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
99 
100  glossy_mat = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default metal");
101  glossy_mat->nodetree = ntree;
102  glossy_mat->use_nodes = true;
103  /* To use the forward pipeline. */
104  glossy_mat->blend_method = MA_BM_BLEND;
105 
107  bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
108  copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 1.0f);
109  bNodeSocket *roughness = nodeFindSocket(bsdf, SOCK_IN, "Roughness");
110  ((bNodeSocketValueFloat *)roughness->default_value)->value = 0.0f;
111 
113 
115  bsdf,
116  nodeFindSocket(bsdf, SOCK_OUT, "BSDF"),
117  output,
118  nodeFindSocket(output, SOCK_IN, "Surface"));
119 
121  }
122  {
123  bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
124 
125  error_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default error");
126  error_mat_->nodetree = ntree;
127  error_mat_->use_nodes = true;
128 
129  /* Use emission and output material to be compatible with both World and Material. */
130  bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_EMISSION);
131  bNodeSocket *color = nodeFindSocket(bsdf, SOCK_IN, "Color");
132  copy_v3_fl3(((bNodeSocketValueRGBA *)color->default_value)->value, 1.0f, 0.0f, 1.0f);
133 
135 
137  bsdf,
138  nodeFindSocket(bsdf, SOCK_OUT, "Emission"),
139  output,
140  nodeFindSocket(output, SOCK_IN, "Surface"));
141 
143  }
144 }
145 
147 {
148  for (Material *mat : material_map_.values()) {
149  delete mat;
150  }
151  BKE_id_free(nullptr, glossy_mat);
152  BKE_id_free(nullptr, diffuse_mat);
153  BKE_id_free(nullptr, error_mat_);
154 }
155 
157 {
159 
160  for (Material *mat : material_map_.values()) {
161  mat->init = false;
162  }
163  shader_map_.clear();
164 }
165 
166 MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
167  eMaterialPipeline pipeline_type,
168  eMaterialGeometry geometry_type)
169 {
170  bNodeTree *ntree = (blender_mat->use_nodes && blender_mat->nodetree != nullptr) ?
171  blender_mat->nodetree :
172  default_surface_ntree_.nodetree_get(blender_mat);
173 
174  MaterialPass matpass;
175  matpass.gpumat = inst_.shaders.material_shader_get(
176  blender_mat, ntree, pipeline_type, geometry_type, true);
177 
178  switch (GPU_material_status(matpass.gpumat)) {
179  case GPU_MAT_SUCCESS:
180  break;
181  case GPU_MAT_QUEUED:
183  blender_mat = (geometry_type == MAT_GEOM_VOLUME) ? BKE_material_default_volume() :
185  matpass.gpumat = inst_.shaders.material_shader_get(
186  blender_mat, blender_mat->nodetree, pipeline_type, geometry_type, false);
187  break;
188  case GPU_MAT_FAILED:
189  default:
190  matpass.gpumat = inst_.shaders.material_shader_get(
191  error_mat_, error_mat_->nodetree, pipeline_type, geometry_type, false);
192  break;
193  }
194  /* Returned material should be ready to be drawn. */
196 
197  if (GPU_material_recalc_flag_get(matpass.gpumat)) {
198  inst_.sampling.reset();
199  }
200 
201  if ((pipeline_type == MAT_PIPE_DEFERRED) &&
203  pipeline_type = MAT_PIPE_FORWARD;
204  }
205 
206  if ((pipeline_type == MAT_PIPE_FORWARD) &&
208  /* Transparent needs to use one shgroup per object to support reordering. */
209  matpass.shgrp = inst_.pipelines.material_add(blender_mat, matpass.gpumat, pipeline_type);
210  }
211  else {
212  ShaderKey shader_key(matpass.gpumat, geometry_type, pipeline_type);
213 
214  auto add_cb = [&]() -> DRWShadingGroup * {
215  /* First time encountering this shader. Create a shading group. */
216  return inst_.pipelines.material_add(blender_mat, matpass.gpumat, pipeline_type);
217  };
218  DRWShadingGroup *grp = shader_map_.lookup_or_add_cb(shader_key, add_cb);
219 
220  if (grp != nullptr) {
221  /* Shading group for this shader already exists. Create a sub one for this material. */
222  /* IMPORTANT: We always create a subgroup so that all subgroups are inserted after the
223  * first "empty" shgroup. This avoids messing the order of subgroups when there is more
224  * nested subgroup (i.e: hair drawing). */
225  /* TODO(@fclem): Remove material resource binding from the first group creation. */
226  matpass.shgrp = DRW_shgroup_create_sub(grp);
228  }
229  }
230 
231  return matpass;
232 }
233 
234 Material &MaterialModule::material_sync(::Material *blender_mat,
235  eMaterialGeometry geometry_type,
236  bool has_motion)
237 {
238  eMaterialPipeline surface_pipe = (blender_mat->blend_method == MA_BM_BLEND) ? MAT_PIPE_FORWARD :
240  eMaterialPipeline prepass_pipe = (blender_mat->blend_method == MA_BM_BLEND) ?
241  (has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY :
243  (has_motion ? MAT_PIPE_DEFERRED_PREPASS_VELOCITY :
245 
246  /* TEST until we have deferred pipeline up and running. */
247  surface_pipe = MAT_PIPE_FORWARD;
248  prepass_pipe = has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY : MAT_PIPE_FORWARD_PREPASS;
249 
250  MaterialKey material_key(blender_mat, geometry_type, surface_pipe);
251 
252  /* TODO: allocate in blocks to avoid memory fragmentation. */
253  auto add_cb = [&]() { return new Material(); };
254  Material &mat = *material_map_.lookup_or_add_cb(material_key, add_cb);
255 
256  /* Forward pipeline needs to use one shgroup per object. */
257  if (mat.init == false || (surface_pipe == MAT_PIPE_FORWARD)) {
258  mat.init = true;
259  /* Order is important for transparent. */
260  mat.prepass = material_pass_get(blender_mat, prepass_pipe, geometry_type);
261  mat.shading = material_pass_get(blender_mat, surface_pipe, geometry_type);
262  if (blender_mat->blend_shadow == MA_BS_NONE) {
263  mat.shadow = MaterialPass();
264  }
265  else {
266  mat.shadow = material_pass_get(blender_mat, MAT_PIPE_SHADOW, geometry_type);
267  }
268 
269  mat.is_alpha_blend_transparent = (blender_mat->blend_method == MA_BM_BLEND) &&
270  GPU_material_flag_get(mat.prepass.gpumat,
272  }
273  return mat;
274 }
275 
276 ::Material *MaterialModule::material_from_slot(Object *ob, int slot)
277 {
278  if (ob->base_flag & BASE_HOLDOUT) {
280  }
281  ::Material *ma = BKE_object_material_get(ob, slot + 1);
282  if (ma == nullptr) {
283  if (ob->type == OB_VOLUME) {
285  }
287  }
288  return ma;
289 }
290 
292 {
293  material_array_.materials.clear();
294  material_array_.gpu_materials.clear();
295 
296  const int materials_len = DRW_cache_object_material_count_get(ob);
297 
298  for (auto i : IndexRange(materials_len)) {
299  ::Material *blender_mat = material_from_slot(ob, i);
300  Material &mat = material_sync(blender_mat, to_material_geometry(ob), has_motion);
301  material_array_.materials.append(&mat);
302  material_array_.gpu_materials.append(mat.shading.gpumat);
303  }
304  return material_array_;
305 }
306 
308  bool has_motion,
309  int mat_nr,
310  eMaterialGeometry geometry_type)
311 {
312  ::Material *blender_mat = material_from_slot(ob, mat_nr);
313  Material &mat = material_sync(blender_mat, geometry_type, has_motion);
314  return mat;
315 }
316 
319 } // namespace blender::eevee
void * BKE_id_new_nomain(short type, const char *name)
Definition: lib_id.c:1173
void BKE_id_free(struct Main *bmain, void *idv)
General operations, lookup, etc. for materials.
struct Material * BKE_material_default_surface(void)
Definition: material.c:2051
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:687
struct Material * BKE_material_default_holdout(void)
Definition: material.c:2046
struct Material * BKE_material_default_volume(void)
Definition: material.c:2056
#define SH_NODE_BSDF_PRINCIPLED
Definition: BKE_node.h:1164
#define SH_NODE_EMISSION
Definition: BKE_node.h:1115
#define SH_NODE_BSDF_DIFFUSE
Definition: BKE_node.h:1109
#define SH_NODE_OUTPUT_MATERIAL
Definition: BKE_node.h:1101
void ntreeFreeEmbeddedTree(struct bNodeTree *ntree)
Definition: node.cc:3112
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2296
struct bNodeSocket * nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier)
#define SH_NODE_BSDF_GLOSSY
Definition: BKE_node.h:1110
struct bNodeTree * ntreeAddTree(struct Main *bmain, const char *name, const char *idname)
Definition: node.cc:2674
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2151
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:3644
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE void copy_v3_fl(float r[3], float f)
@ ID_MA
Definition: DNA_ID_enums.h:51
@ BASE_HOLDOUT
@ MA_BS_NONE
struct Material Material
@ MA_BM_BLEND
@ SOCK_OUT
@ SOCK_IN
@ OB_VOLUME
bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
Definition: gpu_material.c:601
bool GPU_material_recalc_flag_get(GPUMaterial *mat)
Definition: gpu_material.c:612
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
Definition: gpu_material.c:574
@ GPU_MATFLAG_SHADER_TO_RGBA
Definition: GPU_material.h:78
@ GPU_MATFLAG_TRANSPARENT
Definition: GPU_material.h:76
@ GPU_MAT_QUEUED
Definition: GPU_material.h:116
@ GPU_MAT_FAILED
Definition: GPU_material.h:114
@ GPU_MAT_SUCCESS
Definition: GPU_material.h:117
#define MEM_SAFE_FREE(v)
struct bNodeTreeType * ntreeType_Shader
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
void append(const T &value)
Definition: BLI_vector.hh:433
bNodeTree * nodetree_get(::Material *ma)
A running instance of the engine.
Material & material_get(Object *ob, bool has_motion, int mat_nr, eMaterialGeometry geometry_type)
MaterialArray & material_array_get(Object *ob, bool has_motion)
DRWShadingGroup * material_add(::Material *blender_mat, GPUMaterial *gpumat, eMaterialPipeline pipeline_type)
GPUMaterial * material_shader_get(::Material *blender_mat, struct bNodeTree *nodetree, eMaterialPipeline pipeline_type, eMaterialGeometry geometry_type, bool deferred_compilation)
int DRW_cache_object_material_count_get(struct Object *ob)
Definition: draw_cache.c:936
void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material)
DRWShadingGroup * DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
bNodeTree * ntree
ccl_global KernelShaderEvalInput ccl_global float * output
static eMaterialGeometry to_material_geometry(const Object *ob)
@ MAT_PIPE_DEFERRED_PREPASS_VELOCITY
@ MAT_PIPE_FORWARD_PREPASS_VELOCITY
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
short base_flag
void * default_value
char idname[64]
Definition: BKE_node.h:375
Vector< Material * > materials
Vector< GPUMaterial * > gpu_materials