Blender  V2.93
workbench_materials.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2018, Blender Foundation.
17  */
18 
23 #include "workbench_private.h"
24 
25 #include "BLI_memblock.h"
26 
27 #include "BKE_image.h"
28 #include "BKE_node.h"
29 
30 #include "BLI_dynstr.h"
31 #include "BLI_hash.h"
32 
33 #include "DNA_mesh_types.h"
34 #include "DNA_node_types.h"
35 
36 #include "GPU_uniform_buffer.h"
37 
38 #include "ED_uvedit.h"
39 
40 #define HSV_SATURATION 0.5
41 #define HSV_VALUE 0.8
42 
44  Object *ob,
45  Material *mat,
47  eV3DShadingColorType color_type)
48 {
49  float metallic = 0.0f;
50  float roughness = 0.632455532f; /* sqrtf(0.4f); */
51  float alpha = wpd->shading.xray_alpha;
52 
53  switch (color_type) {
55  copy_v3_v3(data->base_color, wpd->shading.single_color);
56  break;
59  if (ob->id.lib) {
61  }
62  float hue = BLI_hash_int_01(hash);
63  const float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
64  hsv_to_rgb_v(hsv, data->base_color);
65  break;
66  }
69  alpha *= ob->color[3];
70  copy_v3_v3(data->base_color, ob->color);
71  break;
74  default:
75  if (mat) {
76  alpha *= mat->a;
77  copy_v3_v3(data->base_color, &mat->r);
78  metallic = mat->metallic;
79  roughness = sqrtf(mat->roughness); /* Remap to Disney roughness. */
80  }
81  else {
82  copy_v3_fl(data->base_color, 0.8f);
83  }
84  break;
85  }
86 
87  uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic);
88  uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness);
90  data->packed_data = (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic;
91 }
92 
93 /* Return correct material or empty default material if slot is empty. */
95 {
96  Material *ma = BKE_object_material_get(ob, mat_nr);
97  if (ma == NULL) {
99  }
100  return ma;
101 }
102 
104  Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, eGPUSamplerState *r_sampler)
105 {
106  bNode *node;
107  *r_sampler = 0;
108 
109  ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL);
110  if (node && *r_image) {
111  switch (node->type) {
112  case SH_NODE_TEX_IMAGE: {
113  NodeTexImage *storage = node->storage;
114  const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
115  const bool use_repeat = (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
116  const bool use_clip = (storage->extension == SHD_IMAGE_EXTENSION_CLIP);
117  SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
118  SET_FLAG_FROM_TEST(*r_sampler, use_repeat, GPU_SAMPLER_REPEAT);
119  SET_FLAG_FROM_TEST(*r_sampler, use_clip, GPU_SAMPLER_CLAMP_BORDER);
120  break;
121  }
123  NodeTexEnvironment *storage = node->storage;
124  const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
125  SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
126  break;
127  }
128  default:
129  BLI_assert(!"Node type not supported by workbench");
130  }
131  }
132 }
133 
134 /* Return true if the current material ubo has changed and needs to be rebind. */
136  uint32_t id,
137  uint32_t *r_mat_id)
138 {
139  bool resource_changed = false;
140  /* Divide in chunks of MAX_MATERIAL. */
141  uint32_t chunk = id >> 12u;
142  *r_mat_id = id & 0xFFFu;
143  /* We need to add a new chunk. */
144  while (chunk >= wpd->material_chunk_count) {
145  wpd->material_chunk_count++;
148  wpd->material_chunk_curr = chunk;
149  resource_changed = true;
150  }
151  /* We need to go back to a previous chunk. */
152  if (wpd->material_chunk_curr != chunk) {
155  wpd->material_chunk_curr = chunk;
156  resource_changed = true;
157  }
158  return resource_changed;
159 }
160 
162  Object *ob,
163  int mat_nr,
164  eV3DShadingColorType color_type,
165  eWORKBENCH_DataType datatype,
166  bool *r_transp)
167 {
168  Image *ima = NULL;
169  ImageUser *iuser = NULL;
170  eGPUSamplerState sampler;
171  const bool infront = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
172 
173  if (color_type == V3D_SHADING_TEXTURE_COLOR) {
174  workbench_material_get_image(ob, mat_nr, &ima, &iuser, &sampler);
175  if (ima == NULL) {
176  /* Fallback to material color. */
177  color_type = V3D_SHADING_MATERIAL_COLOR;
178  }
179  }
180 
181  switch (color_type) {
183  return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, sampler, datatype);
184  }
186  /* For now, we use the same ubo for material and object coloring but with different indices.
187  * This means they are mutually exclusive. */
188  BLI_assert(
190 
191  Material *ma = workbench_object_material_get(ob, mat_nr);
192 
193  const bool transp = wpd->shading.xray_alpha < 1.0f || ma->a < 1.0f;
194  WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][datatype];
195 
196  if (r_transp && transp) {
197  *r_transp = true;
198  }
199 
200  DRWShadingGroup **grp_mat = NULL;
201  /* A hashmap stores material shgroups to pack all similar drawcalls together. */
202  if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) {
203  return *grp_mat;
204  }
205 
206  uint32_t mat_id, id = wpd->material_index++;
207 
208  workbench_material_chunk_select(wpd, id, &mat_id);
209  workbench_material_ubo_data(wpd, ob, ma, &wpd->material_ubo_data_curr[mat_id], color_type);
210 
211  DRWShadingGroup *grp = prepass->common_shgrp;
212  *grp_mat = grp = DRW_shgroup_create_sub(grp);
213  DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
214  DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id);
215  return grp;
216  }
218  const bool transp = wpd->shading.xray_alpha < 1.0f;
219  DRWShadingGroup *grp = wpd->prepass[transp][infront][datatype].vcol_shgrp;
220  return grp;
221  }
222  default: {
223  /* For now, we use the same ubo for material and object coloring but with different indices.
224  * This means they are mutually exclusive. */
225  BLI_assert(
227 
228  uint32_t mat_id, id = DRW_object_resource_id_get(ob);
229 
230  bool resource_changed = workbench_material_chunk_select(wpd, id, &mat_id);
231  workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[mat_id], color_type);
232 
233  const bool transp = wpd->shading.xray_alpha < 1.0f || ob->color[3] < 1.0f;
234  DRWShadingGroup **grp = &wpd->prepass[transp][infront][datatype].common_shgrp;
235  if (resource_changed) {
236  *grp = DRW_shgroup_create_sub(*grp);
237  DRW_shgroup_uniform_block(*grp, "material_block", wpd->material_ubo_curr);
238  }
239  if (r_transp && transp) {
240  *r_transp = true;
241  }
242  return *grp;
243  }
244  }
245 }
246 
247 /* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */
249  Object *ob,
250  int mat_nr,
251  Image *ima,
252  ImageUser *iuser,
253  eGPUSamplerState sampler,
254  eWORKBENCH_DataType datatype)
255 {
256  GPUTexture *tex = NULL, *tex_tile_data = NULL;
257 
258  if (ima == NULL) {
259  workbench_material_get_image(ob, mat_nr, &ima, &iuser, &sampler);
260  }
261 
262  if (ima) {
263  if (ima->source == IMA_SRC_TILED) {
264  tex = BKE_image_get_gpu_tiles(ima, iuser, NULL);
265  tex_tile_data = BKE_image_get_gpu_tilemap(ima, iuser, NULL);
266  }
267  else {
268  tex = BKE_image_get_gpu_texture(ima, iuser, NULL);
269  }
270  }
271 
272  if (tex == NULL) {
273  tex = wpd->dummy_image_tx;
274  }
275 
276  const bool infront = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
277  const bool transp = wpd->shading.xray_alpha < 1.0f;
278  WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][datatype];
279 
280  DRWShadingGroup **grp_tex = NULL;
281  /* A hashmap stores image shgroups to pack all similar drawcalls together. */
282  if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) {
283  return *grp_tex;
284  }
285 
286  DRWShadingGroup *grp = (tex_tile_data) ? prepass->image_tiled_shgrp : prepass->image_shgrp;
287 
288  *grp_tex = grp = DRW_shgroup_create_sub(grp);
289  if (tex_tile_data) {
290  DRW_shgroup_uniform_texture_ex(grp, "imageTileArray", tex, sampler);
291  DRW_shgroup_uniform_texture(grp, "imageTileData", tex_tile_data);
292  }
293  else {
294  DRW_shgroup_uniform_texture_ex(grp, "imageTexture", tex, sampler);
295  }
296  DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
297  return grp;
298 }
struct GPUTexture * BKE_image_get_gpu_tiles(struct Image *image, struct ImageUser *iuser, struct ImBuf *ibuf)
Definition: image_gpu.c:444
struct GPUTexture * BKE_image_get_gpu_texture(struct Image *image, struct ImageUser *iuser, struct ImBuf *ibuf)
Definition: image_gpu.c:439
struct GPUTexture * BKE_image_get_gpu_tilemap(struct Image *image, struct ImageUser *iuser, struct ImBuf *ibuf)
Definition: image_gpu.c:449
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
struct Material * BKE_material_default_empty(void)
Definition: material.c:1819
#define SH_NODE_TEX_ENVIRONMENT
Definition: BKE_node.h:1022
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
A dynamically sized string ADT.
unsigned int BLI_ghashutil_strhash_p_murmur(const void *ptr)
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:851
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition: BLI_hash.h:108
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition: math_color.c:68
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
void * BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_memblock.c:197
void * BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_memblock.c:133
unsigned int uint
Definition: BLI_sys_types.h:83
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
@ IMA_ALPHA_PREMUL
@ IMA_SRC_TILED
#define SHD_IMAGE_EXTENSION_CLIP
#define SHD_IMAGE_EXTENSION_REPEAT
#define SHD_INTERP_CLOSEST
@ OB_DRAW_IN_FRONT
eV3DShadingColorType
@ V3D_SHADING_TEXTURE_COLOR
@ V3D_SHADING_VERTEX_COLOR
@ V3D_SHADING_MATERIAL_COLOR
@ V3D_SHADING_OBJECT_COLOR
@ V3D_SHADING_RANDOM_COLOR
@ V3D_SHADING_SINGLE_COLOR
bool ED_object_get_active_image(struct Object *ob, int mat_nr, struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree)
Definition: uvedit_ops.c:125
eGPUSamplerState
Definition: GPU_texture.h:40
@ GPU_SAMPLER_REPEAT
Definition: GPU_texture.h:52
@ GPU_SAMPLER_FILTER
Definition: GPU_texture.h:42
@ GPU_SAMPLER_CLAMP_BORDER
Definition: GPU_texture.h:47
struct GPUTexture GPUTexture
Definition: GPU_texture.h:33
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume SH_NODE_TEX_IMAGE
short source
char alpha_mode
OperationNode * node
static CCL_NAMESPACE_BEGIN const double alpha
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuf *ubo)
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex, eGPUSamplerState sampler_state)
uint32_t DRW_object_resource_id_get(Object *UNUSED(ob))
DRWShadingGroup * DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
#define sqrtf(x)
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal)
static const pxr::TfToken metallic("metallic", pxr::TfToken::Immortal)
#define hash
Definition: noise.c:169
unsigned int uint32_t
Definition: stdint.h:83
struct Library * lib
Definition: DNA_ID.h:277
char name[66]
Definition: DNA_ID.h:283
char filepath[1024]
Definition: DNA_ID.h:352
float color[4]
float single_color[3]
struct DRWShadingGroup * vcol_shgrp
struct DRWShadingGroup * image_tiled_shgrp
struct DRWShadingGroup * common_shgrp
struct GHash * material_hash
struct DRWShadingGroup * image_shgrp
struct GPUUniformBuf * material_ubo_curr
struct BLI_memblock * material_ubo_data
struct BLI_memblock * material_ubo
struct GPUTexture * dummy_image_tx
WORKBENCH_UBO_Material * material_ubo_data_curr
WORKBENCH_Prepass prepass[2][2][WORKBENCH_DATATYPE_MAX]
GPUUniformBuf * workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd)
BLI_INLINE void workbench_material_get_image(Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, eGPUSamplerState *r_sampler)
DRWShadingGroup * workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, Object *ob, int mat_nr, Image *ima, ImageUser *iuser, eGPUSamplerState sampler, eWORKBENCH_DataType datatype)
BLI_INLINE Material * workbench_object_material_get(Object *ob, int mat_nr)
void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_UBO_Material *data, eV3DShadingColorType color_type)
BLI_INLINE bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd, uint32_t id, uint32_t *r_mat_id)
DRWShadingGroup * workbench_material_setup_ex(WORKBENCH_PrivateData *wpd, Object *ob, int mat_nr, eV3DShadingColorType color_type, eWORKBENCH_DataType datatype, bool *r_transp)
#define HSV_VALUE
#define HSV_SATURATION
eWORKBENCH_DataType