Geometry Nodes: take materials into account when joining geometries

Materials are now kept intact when using the Join Geometry node
or when realizing instaces.
This commit is contained in:
Jacques Lucke 2021-05-19 11:02:25 +02:00
parent 02b80276b3
commit 5e6f3b8564
4 changed files with 79 additions and 0 deletions

View File

@ -109,6 +109,7 @@ 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);
void BKE_id_material_eval_assign(struct ID *id, int slot, struct Material *material);
/* rendering */

View File

@ -15,6 +15,7 @@
*/
#include "BKE_geometry_set_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
@ -361,6 +362,8 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
int64_t cd_dirty_poly = 0;
int64_t cd_dirty_edge = 0;
int64_t cd_dirty_loop = 0;
VectorSet<Material *> materials;
for (const GeometryInstanceGroup &set_group : set_groups) {
const GeometrySet &set = set_group.geometry_set;
const int tot_transforms = set_group.transforms.size();
@ -374,6 +377,10 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
cd_dirty_poly |= mesh.runtime.cd_dirty_poly;
cd_dirty_edge |= mesh.runtime.cd_dirty_edge;
cd_dirty_loop |= mesh.runtime.cd_dirty_loop;
for (const int slot_index : IndexRange(mesh.totcol)) {
Material *material = mesh.mat[slot_index];
materials.add(material);
}
}
if (convert_points_to_vertices && set.has_pointcloud()) {
const PointCloud &pointcloud = *set.get_pointcloud_for_read();
@ -396,6 +403,10 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
break;
}
}
for (const int i : IndexRange(materials.size())) {
Material *material = materials[i];
BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
}
new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
@ -409,6 +420,14 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
const GeometrySet &set = set_group.geometry_set;
if (set.has_mesh()) {
const Mesh &mesh = *set.get_mesh_for_read();
Array<int> material_index_map(mesh.totcol);
for (const int i : IndexRange(mesh.totcol)) {
Material *material = mesh.mat[i];
const int new_material_index = materials.index_of(material);
material_index_map[i] = new_material_index;
}
for (const float4x4 &transform : set_group.transforms) {
for (const int i : IndexRange(mesh.totvert)) {
const MVert &old_vert = mesh.mvert[i];
@ -438,6 +457,13 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
new_poly = old_poly;
new_poly.loopstart += loop_offset;
if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh.totcol) {
new_poly.mat_nr = material_index_map[new_poly.mat_nr];
}
else {
/* The material index was invalid before. */
new_poly.mat_nr = 0;
}
}
vert_offset += mesh.totvert;

View File

@ -768,6 +768,31 @@ int BKE_object_material_count_eval(Object *ob)
return len_p ? *len_p : 0;
}
void BKE_id_material_eval_assign(ID *id, int slot, Material *material)
{
Material ***materials_ptr = BKE_id_material_array_p(id);
short *len_ptr = BKE_id_material_len_p(id);
if (ELEM(NULL, materials_ptr, len_ptr)) {
BLI_assert_unreachable();
return;
}
const int slot_index = slot - 1;
const int old_length = *len_ptr;
if (slot_index >= old_length) {
/* Need to grow slots array. */
const int new_length = slot_index + 1;
*materials_ptr = MEM_reallocN(*materials_ptr, sizeof(void *) * new_length);
*len_ptr = new_length;
for (int i = old_length; i < new_length; i++) {
(*materials_ptr)[i] = NULL;
}
}
(*materials_ptr)[slot_index] = material;
}
Material *BKE_gpencil_material(Object *ob, short act)
{
Material *ma = BKE_object_material_get(ob, act);

View File

@ -14,6 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
@ -57,6 +58,8 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent
int64_t cd_dirty_edge = 0;
int64_t cd_dirty_loop = 0;
VectorSet<Material *> materials;
for (const MeshComponent *mesh_component : src_components) {
const Mesh *mesh = mesh_component->get_for_read();
totverts += mesh->totvert;
@ -67,12 +70,22 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent
cd_dirty_poly |= mesh->runtime.cd_dirty_poly;
cd_dirty_edge |= mesh->runtime.cd_dirty_edge;
cd_dirty_loop |= mesh->runtime.cd_dirty_loop;
for (const int slot_index : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[slot_index];
materials.add(material);
}
}
const Mesh *first_input_mesh = src_components[0]->get_for_read();
Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
BKE_mesh_copy_settings(new_mesh, first_input_mesh);
for (const int i : IndexRange(materials.size())) {
Material *material = materials[i];
BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
}
new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
@ -88,6 +101,13 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent
continue;
}
Array<int> material_index_map(mesh->totcol);
for (const int i : IndexRange(mesh->totcol)) {
Material *material = mesh->mat[i];
const int new_material_index = materials.index_of(material);
material_index_map[i] = new_material_index;
}
for (const int i : IndexRange(mesh->totvert)) {
const MVert &old_vert = mesh->mvert[i];
MVert &new_vert = new_mesh->mvert[vert_offset + i];
@ -113,6 +133,13 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent
MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
new_poly = old_poly;
new_poly.loopstart += loop_offset;
if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh->totcol) {
new_poly.mat_nr = material_index_map[new_poly.mat_nr];
}
else {
/* The material index was invalid before. */
new_poly.mat_nr = 0;
}
}
vert_offset += mesh->totvert;