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:
authorJacques Lucke <jacques@blender.org>2021-05-19 11:23:09 +0300
committerJacques Lucke <jacques@blender.org>2021-05-19 11:23:09 +0300
commit1a81d268a19f2f1402f408ad1dadf92c7a399607 (patch)
treed3f1b657efc1676b6b1f4b1cc34b4623529c379c
parentd373b43f07f5403826035b5dee71b09f433b0540 (diff)
Materials: support changing materials during evaluation
This commit allows that the evaluated geometry of an object has different materials from the original geometry. This is needed for geometry nodes. The main thing that changes for render engines and exporters is that the number of material slots on an object and its geometry might not match anymore. For original data, the slot counts are still equal, but not for evaluated data. Accessing material slots though rna stays the same. The behavior adapts automatically depending on whether the object is evaluated. When accessing materials of an object through `BKE_object_material_*` one has to use a new api for evaluated objects: `BKE_object_material_get_eval` and `BKE_object_material_count_eval`. In the future, the different behavior might be hidden behind a more general C api, but that would require quite a few more changes. The ground truth for the number of materials is the number of materials on the geometry now. This is important in the current design, because Eevee needs to know the number of materials just based on the mesh in `mesh_render_mat_len_get` and similar places. In a few places I had to add a special case for mesh edit mode to get it to work properly. This is unfortunate, but I don't see a way around that for now. Differential Revision: https://developer.blender.org/D11236
-rw-r--r--source/blender/blenkernel/BKE_material.h5
-rw-r--r--source/blender/blenkernel/intern/material.c68
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_paint.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_particle.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c2
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h4
-rw-r--r--source/blender/makesrna/intern/rna_object.c90
14 files changed, 164 insertions, 30 deletions
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 14ea50f808a..96aae2d2d42 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -105,6 +105,11 @@ struct Material *BKE_id_material_pop(struct Main *bmain,
/* index is an int because of RNA. */
int index);
void BKE_id_material_clear(struct Main *bmain, struct ID *id);
+
+/* eval api */
+struct Material *BKE_object_material_get_eval(struct Object *ob, short act);
+int BKE_object_material_count_eval(struct Object *ob);
+
/* rendering */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3]);
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 37d47a984cc..73afea98163 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -77,6 +77,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "GPU_material.h"
@@ -700,6 +701,73 @@ Material *BKE_object_material_get(Object *ob, short act)
return ma_p ? *ma_p : NULL;
}
+static ID *get_evaluated_object_data_with_materials(Object *ob)
+{
+ ID *data = ob->data;
+ /* Meshes in edit mode need special handling. */
+ if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) {
+ Mesh *mesh = ob->data;
+ if (mesh->edit_mesh && mesh->edit_mesh->mesh_eval_final) {
+ data = &mesh->edit_mesh->mesh_eval_final->id;
+ }
+ }
+ return data;
+}
+
+/**
+ * On evaluated objects the number of materials on an object and its data might go out of sync.
+ * This is because during evaluation materials can be added/removed on the object data.
+ *
+ * For rendering or exporting we generally use the materials on the object data. However, some
+ * material indices might be overwritten by the object.
+ */
+Material *BKE_object_material_get_eval(Object *ob, short act)
+{
+ BLI_assert(DEG_is_evaluated_object(ob));
+ const int slot_index = act - 1;
+
+ if (slot_index < 0) {
+ return NULL;
+ }
+ ID *data = get_evaluated_object_data_with_materials(ob);
+ const short *tot_slots_data_ptr = BKE_id_material_len_p(data);
+ const int tot_slots_data = tot_slots_data_ptr ? *tot_slots_data_ptr : 0;
+ if (slot_index >= tot_slots_data) {
+ return NULL;
+ }
+ const int tot_slots_object = ob->totcol;
+
+ Material ***materials_data_ptr = BKE_id_material_array_p(data);
+ Material **materials_data = materials_data_ptr ? *materials_data_ptr : NULL;
+ Material **materials_object = ob->mat;
+
+ /* Check if slot is overwritten by object. */
+ if (slot_index < tot_slots_object) {
+ if (ob->matbits) {
+ if (ob->matbits[slot_index]) {
+ Material *material = materials_object[slot_index];
+ if (material != NULL) {
+ return material;
+ }
+ }
+ }
+ }
+ /* Otherwise use data from object-data. */
+ if (slot_index < tot_slots_data) {
+ Material *material = materials_data[slot_index];
+ return material;
+ }
+ return NULL;
+}
+
+int BKE_object_material_count_eval(Object *ob)
+{
+ BLI_assert(DEG_is_evaluated_object(ob));
+ ID *id = get_evaluated_object_data_with_materials(ob);
+ const short *len_p = BKE_id_material_len_p(id);
+ return len_p ? *len_p : 0;
+}
+
Material *BKE_gpencil_material(Object *ob, short act)
{
Material *ma = BKE_object_material_get(ob, act);
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 70d48ea6040..7fe984b4397 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -265,8 +265,7 @@ void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata,
Object *ob)
{
BLI_assert(ob->type == OB_HAIR);
- Hair *hair = ob->data;
- Material *material = hair->mat ? hair->mat[HAIR_MATERIAL_NR - 1] : NULL;
+ Material *material = BKE_object_material_get_eval(ob, HAIR_MATERIAL_NR);
eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, NULL, NULL, material);
}
@@ -291,8 +290,7 @@ void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata,
if (draw_as != PART_DRAW_PATH) {
continue;
}
- Mesh *mesh = ob->data;
- Material *material = part->omat - 1 < mesh->totcol ? NULL : mesh->mat[part->omat - 1];
+ Material *material = BKE_object_material_get_eval(ob, part->omat);
eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, psys, md, material);
}
}
@@ -318,7 +316,7 @@ void EEVEE_cryptomatte_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *s
if (geom == NULL) {
continue;
}
- Material *material = BKE_object_material_get(ob, i + 1);
+ Material *material = BKE_object_material_get_eval(ob, i + 1);
DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create(
vedata, sldata, ob, material, false);
DRW_shgroup_call(grp, geom, ob);
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index a4325675ea9..d2e0c8308c5 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -723,7 +723,7 @@ BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot, bool holdou
if (holdout) {
return BKE_material_default_holdout();
}
- Material *ma = BKE_object_material_get(ob, slot + 1);
+ Material *ma = BKE_object_material_get_eval(ob, slot + 1);
if (ma == NULL) {
if (ob->type == OB_VOLUME) {
ma = BKE_material_default_volume();
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 809d6010f10..eed36221fcb 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -501,7 +501,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
Scene *scene,
Object *ob)
{
- Material *ma = BKE_object_material_get(ob, 1);
+ Material *ma = BKE_object_material_get_eval(ob, 1);
if (ma == NULL) {
if (ob->type == OB_VOLUME) {
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index ee51b751187..adb70f97585 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -60,7 +60,8 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob)
/* Check if any material with holdout flag enabled. */
tgp_ob->do_mat_holdout = false;
- for (int i = 0; i < ob->totcol; i++) {
+ const int tot_materials = BKE_object_material_count_eval(ob);
+ for (int i = 0; i < tot_materials; i++) {
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, i + 1);
if (((gp_style != NULL) && (gp_style->flag & GP_MATERIAL_IS_STROKE_HOLDOUT)) ||
((gp_style->flag & GP_MATERIAL_IS_FILL_HOLDOUT))) {
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index 526f553329e..e3e84dd4c8c 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -186,7 +186,7 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje
{
GPENCIL_MaterialPool *matpool = pd->last_material_pool;
- int mat_len = max_ii(1, ob->totcol);
+ int mat_len = max_ii(1, BKE_object_material_count_eval(ob));
bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GP_MATERIAL_BUFFER_LEN);
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 891142fe0a2..aa26aa47faa 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -382,7 +382,7 @@ static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl),
void *thunk)
{
Object *ob = (Object *)thunk;
- Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
+ Material *ma = BKE_object_material_get_eval(ob, gps->mat_nr + 1);
if (ma == NULL) {
return;
}
diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c
index 89e724bcfcc..d52640ed174 100644
--- a/source/blender/draw/engines/overlay/overlay_paint.c
+++ b/source/blender/draw/engines/overlay/overlay_paint.c
@@ -48,7 +48,7 @@ static bool paint_object_is_rendered_transparent(View3D *v3d, Object *ob)
v3d->shading.color_type == V3D_SHADING_MATERIAL_COLOR) {
Mesh *me = ob->data;
for (int i = 0; i < me->totcol; i++) {
- Material *mat = me->mat[i];
+ Material *mat = BKE_object_material_get_eval(ob, i + 1);
if (mat && mat->a < 1.0f) {
return true;
}
diff --git a/source/blender/draw/engines/overlay/overlay_particle.c b/source/blender/draw/engines/overlay/overlay_particle.c
index 71064e7ff47..5fa74a8c3a6 100644
--- a/source/blender/draw/engines/overlay/overlay_particle.c
+++ b/source/blender/draw/engines/overlay/overlay_particle.c
@@ -186,7 +186,7 @@ void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
/* TODO(fclem): Here would be a good place for preemptive culling. */
/* NOTE(fclem): Is color even useful in our modern context? */
- Material *ma = BKE_object_material_get(ob, part->omat);
+ Material *ma = BKE_object_material_get_eval(ob, part->omat);
float color[4] = {0.6f, 0.6f, 0.6f, part->draw_size};
if (ma != NULL) {
copy_v3_v3(color, &ma->r);
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 6e9118bfe46..800d1085505 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -93,7 +93,7 @@ void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
/* Return correct material or empty default material if slot is empty. */
BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr)
{
- Material *ma = BKE_object_material_get(ob, mat_nr);
+ Material *ma = BKE_object_material_get_eval(ob, mat_nr);
if (ma == NULL) {
ma = BKE_material_default_empty();
}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 525a81b5581..ddda6d7b58e 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -202,7 +202,7 @@ static void workbench_volume_material_color(WORKBENCH_PrivateData *wpd,
eV3DShadingColorType color_type,
float color[3])
{
- Material *ma = BKE_object_material_get(ob, VOLUME_MATERIAL_NR);
+ Material *ma = BKE_object_material_get_eval(ob, VOLUME_MATERIAL_NR);
WORKBENCH_UBO_Material ubo_data;
workbench_material_ubo_data(wpd, ob, ma, &ubo_data, color_type);
copy_v3_v3(color, ubo_data.base_color);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index c929fe7dfd3..bbb97fc09a3 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -88,6 +88,10 @@ typedef enum eMRExtractType {
BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
{
+ /* In edit mode, the displayed mesh is stored in the edit-mesh. */
+ if (me->edit_mesh && me->edit_mesh->mesh_eval_final) {
+ return MAX2(1, me->edit_mesh->mesh_eval_final->totcol);
+ }
return MAX2(1, me->totcol);
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 3edfd5c44f4..3126b45cb82 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -62,6 +62,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph_query.h"
+
const EnumPropertyItem rna_enum_object_mode_items[] = {
{OB_MODE_OBJECT, "OBJECT", ICON_OBJECT_DATAMODE, "Object Mode", ""},
{OB_MODE_EDIT, "EDIT", ICON_EDITMODE_HLT, "Edit Mode", ""},
@@ -1253,10 +1255,15 @@ static int rna_Object_rotation_4d_editable(PointerRNA *ptr, int index)
return PROP_EDITABLE;
}
+static int rna_MaterialSlot_index(PointerRNA *ptr)
+{
+ return POINTER_AS_INT(ptr->data);
+}
+
static int rna_MaterialSlot_material_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Object *ob = (Object *)ptr->owner_id;
- const int index = (Material **)ptr->data - ob->mat;
+ const int index = rna_MaterialSlot_index(ptr);
bool is_editable;
if ((ob->matbits == NULL) || ob->matbits[index]) {
@@ -1273,9 +1280,14 @@ static PointerRNA rna_MaterialSlot_material_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
Material *ma;
- const int index = (Material **)ptr->data - ob->mat;
+ const int index = rna_MaterialSlot_index(ptr);
- ma = BKE_object_material_get(ob, index + 1);
+ if (DEG_is_evaluated_object(ob)) {
+ ma = BKE_object_material_get_eval(ob, index + 1);
+ }
+ else {
+ ma = BKE_object_material_get(ob, index + 1);
+ }
return rna_pointer_inherit_refine(ptr, &RNA_Material, ma);
}
@@ -1284,7 +1296,7 @@ static void rna_MaterialSlot_material_set(PointerRNA *ptr,
struct ReportList *UNUSED(reports))
{
Object *ob = (Object *)ptr->owner_id;
- int index = (Material **)ptr->data - ob->mat;
+ int index = rna_MaterialSlot_index(ptr);
BLI_assert(BKE_id_is_in_global_main(&ob->id));
BLI_assert(BKE_id_is_in_global_main(value.data));
@@ -1309,15 +1321,17 @@ static bool rna_MaterialSlot_material_poll(PointerRNA *ptr, PointerRNA value)
static int rna_MaterialSlot_link_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
- int index = (Material **)ptr->data - ob->mat;
-
- return ob->matbits[index] != 0;
+ int index = rna_MaterialSlot_index(ptr);
+ if (index < ob->totcol) {
+ return ob->matbits[index] != 0;
+ }
+ return false;
}
static void rna_MaterialSlot_link_set(PointerRNA *ptr, int value)
{
Object *ob = (Object *)ptr->owner_id;
- int index = (Material **)ptr->data - ob->mat;
+ int index = rna_MaterialSlot_index(ptr);
if (value) {
ob->matbits[index] = 1;
@@ -1335,7 +1349,7 @@ static int rna_MaterialSlot_name_length(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
Material *ma;
- int index = (Material **)ptr->data - ob->mat;
+ int index = rna_MaterialSlot_index(ptr);
ma = BKE_object_material_get(ob, index + 1);
@@ -1350,7 +1364,7 @@ static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *str)
{
Object *ob = (Object *)ptr->owner_id;
Material *ma;
- int index = (Material **)ptr->data - ob->mat;
+ int index = rna_MaterialSlot_index(ptr);
ma = BKE_object_material_get(ob, index + 1);
@@ -1373,10 +1387,48 @@ static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr)
static char *rna_MaterialSlot_path(PointerRNA *ptr)
{
+ int index = rna_MaterialSlot_index(ptr);
+ return BLI_sprintfN("material_slots[%d]", index);
+}
+
+static int rna_Object_material_slots_length(PointerRNA *ptr)
+{
Object *ob = (Object *)ptr->owner_id;
- int index = (Material **)ptr->data - ob->mat;
+ if (DEG_is_evaluated_object(ob)) {
+ return BKE_object_material_count_eval(ob);
+ }
+ else {
+ return ob->totcol;
+ }
+}
- return BLI_sprintfN("material_slots[%d]", index);
+static void rna_Object_material_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const int length = rna_Object_material_slots_length(ptr);
+ iter->internal.count.item = 0;
+ iter->internal.count.ptr = ptr->owner_id;
+ iter->valid = length > 0;
+}
+
+static void rna_Object_material_slots_next(CollectionPropertyIterator *iter)
+{
+ const int length = rna_Object_material_slots_length(&iter->ptr);
+ iter->internal.count.item++;
+ iter->valid = iter->internal.count.item < length;
+}
+
+static PointerRNA rna_Object_material_slots_get(CollectionPropertyIterator *iter)
+{
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)iter->internal.count.ptr,
+ &RNA_MaterialSlot,
+ POINTER_FROM_INT(iter->internal.count.item),
+ &ptr);
+ return ptr;
+}
+
+static void rna_Object_material_slots_end(CollectionPropertyIterator *UNUSED(iter))
+{
}
static PointerRNA rna_Object_display_get(PointerRNA *ptr)
@@ -2958,12 +3010,18 @@ static void rna_def_object(BlenderRNA *brna)
/* materials */
prop = RNA_def_property(srna, "material_slots", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
RNA_def_property_struct_type(prop, "MaterialSlot");
RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_PROP_NAME);
- /* don't dereference pointer! */
- RNA_def_property_collection_funcs(
- prop, NULL, NULL, NULL, "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ /* Don't dereference the material slot pointer, it is the slot index encoded in a pointer. */
+ RNA_def_property_collection_funcs(prop,
+ "rna_Object_material_slots_begin",
+ "rna_Object_material_slots_next",
+ "rna_Object_material_slots_end",
+ "rna_Object_material_slots_get",
+ "rna_Object_material_slots_length",
+ NULL,
+ NULL,
+ NULL);
RNA_def_property_ui_text(prop, "Material Slots", "Material slots in the object");
prop = RNA_def_property(srna, "active_material", PROP_POINTER, PROP_NONE);