Blender V5.0
blender/mesh.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <algorithm>
6#include <optional>
7
9#include "blender/session.h"
10#include "blender/sync.h"
11#include "blender/util.h"
12
13#include "scene/camera.h"
14#include "scene/mesh.h"
15#include "scene/object.h"
16#include "scene/scene.h"
17
18#include "subd/split.h"
19
20#include "util/algorithm.h"
21#include "util/disjoint_set.h"
22
23#include "util/hash.h"
24#include "util/log.h"
25#include "util/math.h"
26
28#include "BKE_attribute.hh"
29#include "BKE_attribute_math.hh"
30#include "BKE_customdata.hh"
31#include "BKE_mesh.hh"
32
34
37 const float motion_scale)
38{
39 const int numverts = mesh->get_verts().size();
40
41 /* Override motion steps to fixed number. */
42 mesh->set_motion_steps(3);
43
44 AttributeSet &attributes = mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE ?
45 mesh->attributes :
46 mesh->subd_attributes;
47
48 /* Find or add attribute */
49 float3 *P = mesh->get_verts().data();
50 Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
51
52 if (!attr_mP) {
53 attr_mP = attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
54 }
55
56 /* Only export previous and next frame, we don't have any in between data. */
57 const float motion_times[2] = {-1.0f, 1.0f};
58 for (int step = 0; step < 2; step++) {
59 const float relative_time = motion_times[step] * 0.5f * motion_scale;
60 float3 *mP = attr_mP->data_float3() + step * numverts;
61
62 for (int i = 0; i < numverts; i++) {
63 mP[i] = P[i] + make_float3(b_attr[i][0], b_attr[i][1], b_attr[i][2]) * relative_time;
64 }
65 }
66}
67
68static void attr_create_generic(Scene *scene,
69 Mesh *mesh,
70 const ::Mesh &b_mesh,
71 const bool subdivision,
72 const bool need_motion,
73 const float motion_scale)
74{
76 blender::Span<int> tri_faces;
77 if (!subdivision) {
78 corner_tris = b_mesh.corner_tris();
79 tri_faces = b_mesh.corner_tri_faces();
80 }
81 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
82 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
83 static const ustring u_velocity("velocity");
84 const ustring default_color_name{
85 std::string_view(BKE_id_attributes_default_color_name(&b_mesh.id).value_or(""))};
86
87 b_attributes.foreach_attribute([&](const blender::bke::AttributeIter &iter) {
88 const ustring name{std::string_view(iter.name)};
89 const bool is_render_color = name == default_color_name;
90
91 if (need_motion && name == u_velocity) {
92 const blender::VArraySpan b_attribute = *iter.get<blender::float3>(
94 attr_create_motion_from_velocity(mesh, b_attribute, motion_scale);
95 }
96
97 if (!(mesh->need_attribute(scene, name) ||
98 (is_render_color && mesh->need_attribute(scene, ATTR_STD_VERTEX_COLOR))))
99 {
100 return;
101 }
102 if (attributes.find(name)) {
103 return;
104 }
105
106 blender::bke::AttrDomain b_domain = iter.domain;
107 if (b_domain == blender::bke::AttrDomain::Edge) {
108 /* Blender's attribute API handles edge to vertex attribute domain interpolation. */
110 }
111
112 const blender::bke::GAttributeReader b_attr = iter.get(b_domain);
113 if (b_attr.varray.is_empty()) {
114 return;
115 }
116
119 {
120 Attribute *attr = attributes.add(name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
121 if (is_render_color) {
123 }
124
125 uchar4 *data = attr->data_uchar4();
127 if (subdivision) {
128 for (const int i : src.index_range()) {
129 data[i] = make_uchar4(src[i][0], src[i][1], src[i][2], src[i][3]);
130 }
131 }
132 else {
133 for (const int i : corner_tris.index_range()) {
134 const blender::int3 &tri = corner_tris[i];
135 data[i * 3 + 0] = make_uchar4(
136 src[tri[0]][0], src[tri[0]][1], src[tri[0]][2], src[tri[0]][3]);
137 data[i * 3 + 1] = make_uchar4(
138 src[tri[1]][0], src[tri[1]][1], src[tri[1]][2], src[tri[1]][3]);
139 data[i * 3 + 2] = make_uchar4(
140 src[tri[2]][0], src[tri[2]][1], src[tri[2]][2], src[tri[2]][3]);
141 }
142 }
143 return;
144 }
145
147 switch (b_domain) {
150 break;
153 break;
156 break;
157 default:
158 assert(false);
159 return;
160 }
161
163 using BlenderT = decltype(dummy);
164 using Converter = typename ccl::AttributeConverter<BlenderT>;
165 using CyclesT = typename Converter::CyclesT;
166 if constexpr (!std::is_void_v<CyclesT>) {
167 Attribute *attr = attributes.add(name, Converter::type_desc, element);
168 if (is_render_color) {
169 attr->std = ATTR_STD_VERTEX_COLOR;
170 }
171
172 CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
173
174 const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
175 switch (b_attr.domain) {
176 case blender::bke::AttrDomain::Corner: {
177 if (subdivision) {
178 for (const int i : src.index_range()) {
179 data[i] = Converter::convert(src[i]);
180 }
181 }
182 else {
183 for (const int i : corner_tris.index_range()) {
184 const blender::int3 &tri = corner_tris[i];
185 data[i * 3 + 0] = Converter::convert(src[tri[0]]);
186 data[i * 3 + 1] = Converter::convert(src[tri[1]]);
187 data[i * 3 + 2] = Converter::convert(src[tri[2]]);
188 }
189 }
190 break;
191 }
192 case blender::bke::AttrDomain::Point: {
193 for (const int i : src.index_range()) {
194 data[i] = Converter::convert(src[i]);
195 }
196 break;
197 }
198 case blender::bke::AttrDomain::Face: {
199 if (subdivision) {
200 for (const int i : src.index_range()) {
201 data[i] = Converter::convert(src[i]);
202 }
203 }
204 else {
205 for (const int i : corner_tris.index_range()) {
206 data[i] = Converter::convert(src[tri_faces[i]]);
207 }
208 }
209 break;
210 }
211 default: {
212 assert(false);
213 break;
214 }
215 }
216 }
217 });
218 });
219}
220
221static set<ustring> get_blender_uv_names(const ::Mesh &b_mesh)
222{
223 set<ustring> uv_names;
224 b_mesh.attributes().foreach_attribute([&](const blender::bke::AttributeIter &iter) {
227 {
229 uv_names.emplace(std::string_view(iter.name));
230 }
231 }
232 });
233 return uv_names;
234}
235
236/* Create uv map attributes. */
237static void attr_create_uv_map(Scene *scene,
238 Mesh *mesh,
239 const ::Mesh &b_mesh,
240 const set<ustring> &blender_uv_names)
241{
242 const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
243 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
244 const ustring render_name(CustomData_get_render_layer_name(&b_mesh.corner_data, CD_PROP_FLOAT2));
245 if (blender_uv_names.empty()) {
246 return;
247 }
248
249 for (const ustring &uv_name : blender_uv_names) {
250 const bool active_render = uv_name == render_name;
251 const AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
252
253 /* Denotes whether UV map was requested directly. */
254 const bool need_uv = mesh->need_attribute(scene, uv_name) ||
255 (active_render && mesh->need_attribute(scene, uv_std));
256
257 /* UV map */
258 Attribute *uv_attr = nullptr;
259 if (need_uv) {
260 if (active_render) {
261 uv_attr = mesh->attributes.add(uv_std, uv_name);
262 }
263 else {
264 uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
265 }
266
267 const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
268 uv_name.c_str(), blender::bke::AttrDomain::Corner);
269 float2 *fdata = uv_attr->data_float2();
270 for (const int i : corner_tris.index_range()) {
271 const blender::int3 &tri = corner_tris[i];
272 fdata[i * 3 + 0] = make_float2(b_uv_map[tri[0]][0], b_uv_map[tri[0]][1]);
273 fdata[i * 3 + 1] = make_float2(b_uv_map[tri[1]][0], b_uv_map[tri[1]][1]);
274 fdata[i * 3 + 2] = make_float2(b_uv_map[tri[2]][0], b_uv_map[tri[2]][1]);
275 }
276 }
277 }
278}
279
281 Mesh *mesh,
282 const ::Mesh &b_mesh,
283 const set<ustring> &blender_uv_names)
284{
285 const blender::OffsetIndices faces = b_mesh.faces();
286 if (faces.is_empty()) {
287 return;
288 }
289
290 if (blender_uv_names.empty()) {
291 return;
292 }
293
294 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
295 const ustring render_name(CustomData_get_render_layer_name(&b_mesh.corner_data, CD_PROP_FLOAT2));
296 for (const ustring &uv_name : blender_uv_names) {
297 const bool active_render = uv_name == render_name;
298 const AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
299
300 /* Denotes whether UV map was requested directly. */
301 const bool need_uv = mesh->need_attribute(scene, uv_name) ||
302 (active_render && mesh->need_attribute(scene, uv_std));
303
304 Attribute *uv_attr = nullptr;
305
306 /* UV map */
307 if (need_uv) {
308 if (active_render) {
309 uv_attr = mesh->subd_attributes.add(uv_std, uv_name);
310 }
311 else {
312 uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
313 }
314
316
317 const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
318 uv_name.c_str(), blender::bke::AttrDomain::Corner);
319 float2 *fdata = uv_attr->data_float2();
320
321 for (const int i : faces.index_range()) {
322 const blender::IndexRange face = faces[i];
323 for (const int corner : face) {
324 *(fdata++) = make_float2(b_uv_map[corner][0], b_uv_map[corner][1]);
325 }
326 }
327 }
328 }
329}
330
331/* Create vertex pointiness attributes. */
332
333/* Compare vertices by sum of their coordinates. */
335 public:
337
338 bool operator()(const int &vert_idx_a, const int &vert_idx_b)
339 {
340 const float3 &vert_a = verts_[vert_idx_a];
341 const float3 &vert_b = verts_[vert_idx_b];
342 if (vert_a == vert_b) {
343 /* Special case for doubles, so we ensure ordering. */
344 return vert_idx_a > vert_idx_b;
345 }
346 const float x1 = vert_a.x + vert_a.y + vert_a.z;
347 const float x2 = vert_b.x + vert_b.y + vert_b.z;
348 return x1 < x2;
349 }
350
351 protected:
353};
354
355static void attr_create_pointiness(Mesh *mesh,
356 const blender::Span<blender::float3> positions,
357 const blender::Span<blender::float3> b_vert_normals,
359 bool subdivision)
360{
361 const int num_verts = positions.size();
362 if (positions.is_empty()) {
363 return;
364 }
365
366 /* STEP 1: Find out duplicated vertices and point duplicates to a single
367 * original vertex.
368 */
369 vector<int> sorted_vert_indeices(num_verts);
370 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
371 sorted_vert_indeices[vert_index] = vert_index;
372 }
373 const VertexAverageComparator compare(mesh->get_verts());
374 sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare);
375 /* This array stores index of the original vertex for the given vertex
376 * index.
377 */
378 vector<int> vert_orig_index(num_verts);
379 for (int sorted_vert_index = 0; sorted_vert_index < num_verts; ++sorted_vert_index) {
380 const int vert_index = sorted_vert_indeices[sorted_vert_index];
381 const float3 &vert_co = mesh->get_verts()[vert_index];
382 bool found = false;
383 for (int other_sorted_vert_index = sorted_vert_index + 1; other_sorted_vert_index < num_verts;
384 ++other_sorted_vert_index)
385 {
386 const int other_vert_index = sorted_vert_indeices[other_sorted_vert_index];
387 const float3 &other_vert_co = mesh->get_verts()[other_vert_index];
388 /* We are too far away now, we wouldn't have duplicate. */
389 if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) -
390 (vert_co.x + vert_co.y + vert_co.z) >
391 3 * FLT_EPSILON)
392 {
393 break;
394 }
395 /* Found duplicate. */
396 if (len_squared(other_vert_co - vert_co) < FLT_EPSILON) {
397 found = true;
398 vert_orig_index[vert_index] = other_vert_index;
399 break;
400 }
401 }
402 if (!found) {
403 vert_orig_index[vert_index] = vert_index;
404 }
405 }
406 /* Make sure we always points to the very first orig vertex. */
407 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
408 int orig_index = vert_orig_index[vert_index];
409 while (orig_index != vert_orig_index[orig_index]) {
410 orig_index = vert_orig_index[orig_index];
411 }
412 vert_orig_index[vert_index] = orig_index;
413 }
414 sorted_vert_indeices.free_memory();
415 /* STEP 2: Calculate vertex normals taking into account their possible
416 * duplicates which gets "welded" together.
417 */
418 vector<float3> vert_normal(num_verts, zero_float3());
419 /* First we accumulate all vertex normals in the original index. */
420 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
421 const float *b_vert_normal = b_vert_normals[vert_index];
422 const int orig_index = vert_orig_index[vert_index];
423 vert_normal[orig_index] += make_float3(b_vert_normal[0], b_vert_normal[1], b_vert_normal[2]);
424 }
425 /* Then we normalize the accumulated result and flush it to all duplicates
426 * as well.
427 */
428 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
429 const int orig_index = vert_orig_index[vert_index];
430 vert_normal[vert_index] = normalize(vert_normal[orig_index]);
431 }
432 /* STEP 3: Calculate pointiness using single ring neighborhood. */
433 vector<int> counter(num_verts, 0);
434 vector<float> raw_data(num_verts, 0.0f);
435 vector<float3> edge_accum(num_verts, zero_float3());
436 EdgeMap visited_edges;
437 memset(counter.data(), 0, sizeof(int) * counter.size());
438
439 for (const int i : edges.index_range()) {
440 const blender::int2 b_edge = edges[i];
441 const int v0 = vert_orig_index[b_edge[0]];
442 const int v1 = vert_orig_index[b_edge[1]];
443 if (visited_edges.exists(v0, v1)) {
444 continue;
445 }
446 visited_edges.insert(v0, v1);
447 const float3 co0 = make_float3(positions[v0][0], positions[v0][1], positions[v0][2]);
448 const float3 co1 = make_float3(positions[v1][0], positions[v1][1], positions[v1][2]);
449 const float3 edge = safe_normalize(co1 - co0);
450 edge_accum[v0] += edge;
451 edge_accum[v1] += -edge;
452 ++counter[v0];
453 ++counter[v1];
454 }
455 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
456 const int orig_index = vert_orig_index[vert_index];
457 if (orig_index != vert_index) {
458 /* Skip duplicates, they'll be overwritten later on. */
459 continue;
460 }
461 if (counter[vert_index] > 0) {
462 const float3 normal = vert_normal[vert_index];
463 const float angle = safe_acosf(dot(normal, edge_accum[vert_index] / counter[vert_index]));
464 raw_data[vert_index] = angle * M_1_PI_F;
465 }
466 else {
467 raw_data[vert_index] = 0.0f;
468 }
469 }
470 /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */
471 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
472 Attribute *attr = attributes.add(ATTR_STD_POINTINESS);
473 float *data = attr->data_float();
474 memcpy(data, raw_data.data(), sizeof(float) * raw_data.size());
475 memset(counter.data(), 0, sizeof(int) * counter.size());
476 visited_edges.clear();
477 for (const int i : edges.index_range()) {
478 const blender::int2 b_edge = edges[i];
479 const int v0 = vert_orig_index[b_edge[0]];
480 const int v1 = vert_orig_index[b_edge[1]];
481 if (visited_edges.exists(v0, v1)) {
482 continue;
483 }
484 visited_edges.insert(v0, v1);
485 data[v0] += raw_data[v1];
486 data[v1] += raw_data[v0];
487 ++counter[v0];
488 ++counter[v1];
489 }
490 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
491 data[vert_index] /= counter[vert_index] + 1;
492 }
493 /* STEP 4: Copy attribute to the duplicated vertices. */
494 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
495 const int orig_index = vert_orig_index[vert_index];
496 data[vert_index] = data[orig_index];
497 }
498}
499
500/* The Random Per Island attribute is a random float associated with each
501 * connected component (island) of the mesh. The attribute is computed by
502 * first classifying the vertices into different sets using a Disjoint Set
503 * data structure. Then the index of the root of each vertex (Which is the
504 * representative of the set the vertex belongs to) is hashed and stored.
505 *
506 * We are using a face attribute to avoid interpolation during rendering,
507 * allowing the user to safely hash the output further. Had we used vertex
508 * attribute, the interpolation will introduce very slight variations,
509 * making the output unsafe to hash. */
511 Mesh *mesh,
512 const ::Mesh &b_mesh,
513 bool subdivision)
514{
515 if (!mesh->need_attribute(scene, ATTR_STD_RANDOM_PER_ISLAND)) {
516 return;
517 }
518
519 if (b_mesh.verts_num == 0) {
520 return;
521 }
522
523 DisjointSet vertices_sets(b_mesh.verts_num);
524
525 const blender::Span<blender::int2> edges = b_mesh.edges();
526 const blender::Span<int> corner_verts = b_mesh.corner_verts();
527
528 for (const int i : edges.index_range()) {
529 vertices_sets.join(edges[i][0], edges[i][1]);
530 }
531
532 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
533 Attribute *attribute = attributes.add(ATTR_STD_RANDOM_PER_ISLAND);
534 float *data = attribute->data_float();
535
536 if (!subdivision) {
537 const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
538 if (!corner_tris.is_empty()) {
539 for (const int i : corner_tris.index_range()) {
540 const int vert = corner_verts[corner_tris[i][0]];
541 data[i] = hash_uint_to_float(vertices_sets.find(vert));
542 }
543 }
544 }
545 else {
546 const blender::OffsetIndices<int> faces = b_mesh.faces();
547 if (!faces.is_empty()) {
548 for (const int i : faces.index_range()) {
549 const int vert = corner_verts[faces[i].start()];
550 data[i] = hash_uint_to_float(vertices_sets.find(vert));
551 }
552 }
553 }
554}
555
556/* Create Mesh */
557
558static void create_mesh(Scene *scene,
559 Mesh *mesh,
560 const ::Mesh &b_mesh,
561 const array<Node *> &used_shaders,
562 const bool need_motion,
563 const float motion_scale,
564 const bool subdivision = false)
565{
566 const blender::Span<blender::float3> positions = b_mesh.vert_positions();
567 const blender::OffsetIndices faces = b_mesh.faces();
568 const blender::Span<int> corner_verts = b_mesh.corner_verts();
569 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
570 const blender::bke::MeshNormalDomain normals_domain = b_mesh.normals_domain(true);
571 const int numfaces = (!subdivision) ? b_mesh.corner_tris().size() : faces.size();
572
573 const bool use_corner_normals = normals_domain == blender::bke::MeshNormalDomain::Corner &&
574 (mesh->get_subdivision_type() !=
576
577 /* If no faces, create empty mesh. */
578 if (faces.is_empty()) {
579 return;
580 }
581
582 const blender::VArraySpan material_indices = *b_attributes.lookup<int>(
583 "material_index", blender::bke::AttrDomain::Face);
584 const blender::VArraySpan sharp_faces = *b_attributes.lookup<bool>(
585 "sharp_face", blender::bke::AttrDomain::Face);
586 blender::Span<blender::float3> corner_normals;
587 if (use_corner_normals) {
588 corner_normals = b_mesh.corner_normals();
589 }
590
591 int numtris = 0;
592 if (!subdivision) {
593 numtris = numfaces;
594 }
595 /* allocate memory */
596 if (subdivision) {
597 mesh->resize_subd_faces(numfaces, corner_verts.size());
598 }
599 mesh->resize_mesh(positions.size(), numtris);
600
601 float3 *verts = mesh->get_verts().data();
602 for (const int i : positions.index_range()) {
603 verts[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
604 }
605
606 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
607 Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
608 float3 *N = attr_N->data_float3();
609
610 if (subdivision || !(use_corner_normals && !corner_normals.is_empty())) {
611 const blender::Span<blender::float3> vert_normals = b_mesh.vert_normals();
612 for (const int i : vert_normals.index_range()) {
613 N[i] = make_float3(vert_normals[i][0], vert_normals[i][1], vert_normals[i][2]);
614 }
615 }
616
617 const set<ustring> blender_uv_names = get_blender_uv_names(b_mesh);
618
619 /* create generated coordinates from undeformed coordinates */
620 const bool need_default_tangent = (subdivision == false) && (blender_uv_names.empty()) &&
621 (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
622 if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) {
623 const float (*orco)[3] = static_cast<const float (*)[3]>(
624 CustomData_get_layer(&b_mesh.vert_data, CD_ORCO));
625 Attribute *attr = attributes.add(ATTR_STD_GENERATED);
626
627 float3 loc;
628 float3 size;
629 mesh_texture_space(b_mesh, loc, size);
630
631 float texspace_location[3];
632 float texspace_size[3];
633 BKE_mesh_texspace_get(const_cast<::Mesh *>(b_mesh.texcomesh ? b_mesh.texcomesh : &b_mesh),
634 texspace_location,
635 texspace_size);
636
637 float3 *generated = attr->data_float3();
638
639 for (const int i : positions.index_range()) {
640 blender::float3 value;
641 if (orco) {
642 madd_v3_v3v3v3(value, texspace_location, orco[i], texspace_size);
643 }
644 else {
645 value = positions[i];
646 }
647 generated[i] = make_float3(value[0], value[1], value[2]) * size - loc;
648 }
649 }
650
651 auto clamp_material_index = [&](const int material_index) -> int {
652 return clamp(material_index, 0, used_shaders.size() - 1);
653 };
654
655 /* create faces */
656 if (!subdivision) {
657 int *triangles = mesh->get_triangles().data();
658 bool *smooth = mesh->get_smooth().data();
659 int *shader = mesh->get_shader().data();
660
661 const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
662 for (const int i : corner_tris.index_range()) {
663 const blender::int3 &tri = corner_tris[i];
664 triangles[i * 3 + 0] = corner_verts[tri[0]];
665 triangles[i * 3 + 1] = corner_verts[tri[1]];
666 triangles[i * 3 + 2] = corner_verts[tri[2]];
667 }
668
669 if (!material_indices.is_empty()) {
670 const blender::Span<int> tri_faces = b_mesh.corner_tri_faces();
671 for (const int i : corner_tris.index_range()) {
672 shader[i] = clamp_material_index(material_indices[tri_faces[i]]);
673 }
674 }
675 else {
676 std::fill(shader, shader + numtris, 0);
677 }
678
679 if (!sharp_faces.is_empty() && !(use_corner_normals && !corner_normals.is_empty())) {
680 const blender::Span<int> tri_faces = b_mesh.corner_tri_faces();
681 for (const int i : corner_tris.index_range()) {
682 smooth[i] = !sharp_faces[tri_faces[i]];
683 }
684 }
685 else {
686 /* If only face normals are needed, all faces are sharp. */
687 std::fill(smooth, smooth + numtris, normals_domain != blender::bke::MeshNormalDomain::Face);
688 }
689
690 if (use_corner_normals && !corner_normals.is_empty()) {
691 for (const int i : corner_tris.index_range()) {
692 const blender::int3 &tri = corner_tris[i];
693 for (int i = 0; i < 3; i++) {
694 const int corner = tri[i];
695 const int vert = corner_verts[corner];
696 const float *normal = corner_normals[corner];
697 N[vert] = make_float3(normal[0], normal[1], normal[2]);
698 }
699 }
700 }
701
702 mesh->tag_triangles_modified();
703 mesh->tag_shader_modified();
704 mesh->tag_smooth_modified();
705 }
706 else {
707 int *subd_start_corner = mesh->get_subd_start_corner().data();
708 int *subd_num_corners = mesh->get_subd_num_corners().data();
709 int *subd_shader = mesh->get_subd_shader().data();
710 bool *subd_smooth = mesh->get_subd_smooth().data();
711 int *subd_ptex_offset = mesh->get_subd_ptex_offset().data();
712 int *subd_face_corners = mesh->get_subd_face_corners().data();
713
714 if (!sharp_faces.is_empty() && !use_corner_normals) {
715 for (int i = 0; i < numfaces; i++) {
716 subd_smooth[i] = !sharp_faces[i];
717 }
718 }
719 else {
720 std::fill(subd_smooth, subd_smooth + numfaces, true);
721 }
722
723 if (!material_indices.is_empty()) {
724 for (int i = 0; i < numfaces; i++) {
725 subd_shader[i] = clamp_material_index(material_indices[i]);
726 }
727 }
728 else {
729 std::fill(subd_shader, subd_shader + numfaces, 0);
730 }
731
732 std::copy(corner_verts.data(), corner_verts.data() + corner_verts.size(), subd_face_corners);
733
734 const blender::OffsetIndices faces = b_mesh.faces();
735 int ptex_offset = 0;
736 for (const int i : faces.index_range()) {
737 const blender::IndexRange face = faces[i];
738
739 subd_start_corner[i] = face.start();
740 subd_num_corners[i] = face.size();
741 subd_ptex_offset[i] = ptex_offset;
742 const int num_ptex = (face.size() == 4) ? 1 : face.size();
743 ptex_offset += num_ptex;
744 }
745
746 mesh->tag_subd_face_corners_modified();
747 mesh->tag_subd_start_corner_modified();
748 mesh->tag_subd_num_corners_modified();
749 mesh->tag_subd_shader_modified();
750 mesh->tag_subd_smooth_modified();
751 mesh->tag_subd_ptex_offset_modified();
752 }
753
754 /* Create all needed attributes.
755 * The calculate functions will check whether they're needed or not.
756 */
757 if (mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
758 attr_create_pointiness(mesh, positions, b_mesh.vert_normals(), b_mesh.edges(), subdivision);
759 }
760 attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
761 attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
762
763 if (subdivision) {
764 attr_create_subd_uv_map(scene, mesh, b_mesh, blender_uv_names);
765 }
766 else {
767 attr_create_uv_map(scene, mesh, b_mesh, blender_uv_names);
768 }
769
770 /* For volume objects, create a matrix to transform from object space to
771 * mesh texture space. this does not work with deformations but that can
772 * probably only be done well with a volume grid mapping of coordinates. */
775 Transform *tfm = attr->data_transform();
776
777 float3 loc;
778 float3 size;
779 mesh_texture_space(b_mesh, loc, size);
780
782 }
783}
784
785static void create_subd_mesh(Scene *scene,
786 Mesh *mesh,
787 BObjectInfo &b_ob_info,
788 const ::Mesh &b_mesh,
789 const array<Node *> &used_shaders,
790 const bool need_motion,
791 const float motion_scale,
792 const float dicing_rate,
793 const int max_subdivisions)
794{
795 BL::Object b_ob = b_ob_info.real_object;
796
797 BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]);
798 const bool use_creases = subsurf_mod.use_creases();
799
800 create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true);
801
802 if (use_creases) {
803 const blender::VArraySpan creases = *b_mesh.attributes().lookup<float>(
804 "crease_edge", blender::bke::AttrDomain::Edge);
805 if (!creases.is_empty()) {
806 size_t num_creases = 0;
807 for (const int i : creases.index_range()) {
808 if (creases[i] != 0.0f) {
809 num_creases++;
810 }
811 }
812
813 mesh->reserve_subd_creases(num_creases);
814
815 const blender::Span<blender::int2> edges = b_mesh.edges();
816 for (const int i : edges.index_range()) {
817 const float crease = creases[i];
818 if (crease != 0.0f) {
819 const blender::int2 &b_edge = edges[i];
820 mesh->add_edge_crease(b_edge[0], b_edge[1], crease);
821 }
822 }
823 }
824
825 const blender::VArraySpan vert_creases = *b_mesh.attributes().lookup<float>(
826 "crease_vert", blender::bke::AttrDomain::Point);
827 if (!vert_creases.is_empty()) {
828 for (const int i : vert_creases.index_range()) {
829 if (vert_creases[i] != 0.0f) {
830 mesh->add_vertex_crease(i, vert_creases[i]);
831 }
832 }
833 }
834 }
835
836 /* Set subd parameters. */
838 switch (subsurf_mod.adaptive_space()) {
839 case BL::SubsurfModifier::adaptive_space_OBJECT:
841 break;
842 case BL::SubsurfModifier::adaptive_space_PIXEL:
844 break;
845 }
846 const float subd_dicing_rate = (space == Mesh::SUBDIVISION_ADAPTIVE_SPACE_PIXEL) ?
847 max(0.1f, subsurf_mod.adaptive_pixel_size() * dicing_rate) :
848 subsurf_mod.adaptive_object_edge_length() * dicing_rate;
849
850 mesh->set_subd_adaptive_space(space);
851 mesh->set_subd_dicing_rate(subd_dicing_rate);
852 mesh->set_subd_max_level(max_subdivisions);
853 mesh->set_subd_objecttoworld(get_transform(b_ob.matrix_world()));
854}
855
856/* Sync */
857
858void BlenderSync::sync_mesh(BObjectInfo &b_ob_info, Mesh *mesh)
859{
860 /* make a copy of the shaders as the caller in the main thread still need them for syncing the
861 * attributes */
862 array<Node *> used_shaders = mesh->get_used_shaders();
863
864 Mesh new_mesh;
865 new_mesh.set_used_shaders(used_shaders);
866
867 if (view_layer.use_surfaces) {
868 object_subdivision_to_mesh(b_ob_info.real_object, new_mesh, preview, use_adaptive_subdivision);
869 BL::Mesh b_mesh = object_to_mesh(b_ob_info);
870
871 if (b_mesh) {
872 /* Motion blur attribute is relative to seconds, we need it relative to frames. */
873 const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
874 const float motion_scale = (need_motion) ?
875 scene->motion_shutter_time() /
876 (b_scene.render().fps() / b_scene.render().fps_base()) :
877 0.0f;
878
879 /* Sync mesh itself. */
880 if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
881 create_subd_mesh(scene,
882 &new_mesh,
883 b_ob_info,
884 *static_cast<const ::Mesh *>(b_mesh.ptr.data),
885 new_mesh.get_used_shaders(),
886 need_motion,
887 motion_scale,
888 dicing_rate,
889 max_subdivisions);
890 }
891 else {
892 create_mesh(scene,
893 &new_mesh,
894 *static_cast<const ::Mesh *>(b_mesh.ptr.data),
895 new_mesh.get_used_shaders(),
896 need_motion,
897 motion_scale,
898 false);
899 }
900
901 free_object_to_mesh(b_ob_info, b_mesh);
902 }
903 }
904
905 /* update original sockets */
906
907 mesh->clear_non_sockets();
908
909 for (const SocketType &socket : new_mesh.type->inputs) {
910 /* Those sockets are updated in sync_object, so do not modify them. */
911 if (socket.name == "use_motion_blur" || socket.name == "used_shaders") {
912 continue;
913 }
914 mesh->set_value(socket, new_mesh, socket);
915 }
916
917 mesh->attributes.update(std::move(new_mesh.attributes));
918 mesh->subd_attributes.update(std::move(new_mesh.subd_attributes));
919
920 mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
921
922 /* tag update */
923 const bool rebuild = (mesh->triangles_is_modified()) || (mesh->subd_num_corners_is_modified()) ||
924 (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
925 (mesh->subd_ptex_offset_is_modified()) ||
926 (mesh->subd_start_corner_is_modified()) ||
927 (mesh->subd_face_corners_is_modified());
928
929 mesh->tag_update(scene, rebuild);
930}
931
932void BlenderSync::sync_mesh_motion(BObjectInfo &b_ob_info, Mesh *mesh, const int motion_step)
933{
934 /* Skip if no vertices were exported. */
935 const size_t numverts = mesh->get_verts().size();
936 if (numverts == 0) {
937 return;
938 }
939
940 /* Skip objects without deforming modifiers. this is not totally reliable,
941 * would need a more extensive check to see which objects are animated. */
942 BL::Mesh b_mesh_rna(PointerRNA_NULL);
943 if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
944 /* get derived mesh */
945 b_mesh_rna = object_to_mesh(b_ob_info);
946 }
947
948 const std::string ob_name = b_ob_info.real_object.name();
949
950 /* TODO(sergey): Perform preliminary check for number of vertices. */
951 if (b_mesh_rna) {
952 const ::Mesh &b_mesh = *static_cast<const ::Mesh *>(b_mesh_rna.ptr.data);
953 const int b_verts_num = b_mesh.verts_num;
954 const blender::Span<blender::float3> positions = b_mesh.vert_positions();
955 if (positions.is_empty()) {
956 free_object_to_mesh(b_ob_info, b_mesh_rna);
957 return;
958 }
959
960 AttributeSet &attributes = mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE ?
961 mesh->attributes :
962 mesh->subd_attributes;
963
964 /* Export deformed coordinates. */
965 /* Find attributes. */
966 Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
967 Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
968 Attribute *attr_N = attributes.find(ATTR_STD_VERTEX_NORMAL);
969 bool new_attribute = false;
970 /* Add new attributes if they don't exist already. */
971 if (!attr_mP) {
972 attr_mP = attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
973 if (attr_N) {
974 attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
975 }
976
977 new_attribute = true;
978 }
979 /* Load vertex data from mesh. */
980 float3 *mP = attr_mP->data_float3() + motion_step * numverts;
981 float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : nullptr;
982
983 /* NOTE: We don't copy more that existing amount of vertices to prevent
984 * possible memory corruption.
985 */
986 for (int i = 0; i < std::min<size_t>(b_verts_num, numverts); i++) {
987 mP[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
988 }
989 if (mN) {
990 const blender::Span<blender::float3> b_vert_normals = b_mesh.vert_normals();
991 for (int i = 0; i < std::min<size_t>(b_verts_num, numverts); i++) {
992 mN[i] = make_float3(b_vert_normals[i][0], b_vert_normals[i][1], b_vert_normals[i][2]);
993 }
994 }
995 if (new_attribute) {
996 /* In case of new attribute, we verify if there really was any motion. */
997 if (b_verts_num != numverts ||
998 memcmp(mP, mesh->get_verts().data(), sizeof(float3) * numverts) == 0)
999 {
1000 /* no motion, remove attributes again */
1001 if (b_verts_num != numverts) {
1002 LOG_WARNING << "Topology differs, disabling motion blur for object " << ob_name;
1003 }
1004 else {
1005 LOG_TRACE << "No actual deformation motion for object " << ob_name;
1006 }
1008 if (attr_mN) {
1010 }
1011 }
1012 else if (motion_step > 0) {
1013 LOG_TRACE << "Filling deformation motion for object " << ob_name;
1014 /* motion, fill up previous steps that we might have skipped because
1015 * they had no motion, but we need them anyway now */
1016 const float3 *P = mesh->get_verts().data();
1017 const float3 *N = (attr_N) ? attr_N->data_float3() : nullptr;
1018 for (int step = 0; step < motion_step; step++) {
1019 std::copy_n(P, numverts, attr_mP->data_float3() + step * numverts);
1020 if (attr_mN) {
1021 std::copy_n(N, numverts, attr_mN->data_float3() + step * numverts);
1022 }
1023 }
1024 }
1025 }
1026 else {
1027 if (b_verts_num != numverts) {
1028 LOG_WARNING << "Topology differs, discarding motion blur for object " << ob_name
1029 << " at time " << motion_step;
1030 const float3 *P = mesh->get_verts().data();
1031 const float3 *N = (attr_N) ? attr_N->data_float3() : nullptr;
1032 std::copy_n(P, numverts, mP);
1033 if (mN != nullptr) {
1034 std::copy_n(N, numverts, mN);
1035 }
1036 }
1037 }
1038
1039 free_object_to_mesh(b_ob_info, b_mesh_rna);
1040 return;
1041 }
1042
1043 /* No deformation on this frame, copy coordinates if other frames did have it. */
1044 mesh->copy_center_to_motion_step(motion_step);
1045}
1046
std::optional< blender::StringRef > BKE_id_attributes_default_color_name(const struct ID *id)
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
const char * CustomData_get_render_layer_name(const CustomData *data, eCustomDataType type)
void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
MINLINE float safe_acosf(float a)
MINLINE void madd_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
@ CD_PROP_FLOAT2
struct Mesh Mesh
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
static void attr_create_generic(Scene *scene, Mesh *mesh, const ::Mesh &b_mesh, const bool subdivision, const bool need_motion, const float motion_scale)
static void attr_create_random_per_island(Scene *scene, Mesh *mesh, const ::Mesh &b_mesh, bool subdivision)
static void create_mesh(Scene *scene, Mesh *mesh, const ::Mesh &b_mesh, const array< Node * > &used_shaders, const bool need_motion, const float motion_scale, const bool subdivision=false)
static void create_subd_mesh(Scene *scene, Mesh *mesh, BObjectInfo &b_ob_info, const ::Mesh &b_mesh, const array< Node * > &used_shaders, const bool need_motion, const float motion_scale, const float dicing_rate, const int max_subdivisions)
static void attr_create_pointiness(Mesh *mesh, const blender::Span< blender::float3 > positions, const blender::Span< blender::float3 > b_vert_normals, const blender::Span< blender::int2 > edges, bool subdivision)
static void attr_create_uv_map(Scene *scene, Mesh *mesh, const ::Mesh &b_mesh, const set< ustring > &blender_uv_names)
static set< ustring > get_blender_uv_names(const ::Mesh &b_mesh)
static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, const ::Mesh &b_mesh, const set< ustring > &blender_uv_names)
static CCL_NAMESPACE_BEGIN void attr_create_motion_from_velocity(Mesh *mesh, const blender::Span< blender::float3 > b_attr, const float motion_scale)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const void * element
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
Definition btDbvt.cpp:418
void update(AttributeSet &&new_attributes)
Attribute * find(ustring name) const
Attribute * add(ustring name, const TypeDesc type, AttributeElement element)
void remove(ustring name)
size_t find(size_t x)
void join(const size_t x, const size_t y)
void insert(int v0, int v1)
bool exists(int v0, int v1)
void tag_update(Scene *scene, bool rebuild)
bool need_attribute(Scene *scene, AttributeStandard std)
AttributeSet attributes
VertexAverageComparator(const array< float3 > &verts)
bool operator()(const int &vert_idx_a, const int &vert_idx_b)
const array< float3 > & verts_
size_t size() const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader get() const
void free_memory()
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
static BL::Mesh object_to_mesh(BObjectInfo &b_ob_info)
static void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
static void free_object_to_mesh(BObjectInfo &b_ob_info, BL::Mesh &mesh)
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
static void object_subdivision_to_mesh(BL::Object &b_ob, Mesh &mesh, const bool preview, const bool use_adaptive_subdivision)
static Transform get_transform(const BL::Array< float, 16 > &array)
#define M_1_PI_F
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline uchar4 make_uchar4(const uchar x, const uchar y, const uchar z, const uchar w)
static float verts[][3]
#define assert(assertion)
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
constexpr T clamp(T, U, U) RET
VecBase< float, 3 > float3
ccl_device_inline float hash_uint_to_float(const uint kx)
Definition hash.h:192
AttributeStandard
@ ATTR_STD_GENERATED_TRANSFORM
@ ATTR_STD_UV
@ ATTR_STD_MOTION_VERTEX_NORMAL
@ ATTR_STD_VERTEX_NORMAL
@ ATTR_STD_UV_TANGENT
@ ATTR_STD_NONE
@ ATTR_STD_VERTEX_COLOR
@ ATTR_STD_MOTION_VERTEX_POSITION
@ ATTR_STD_POINTINESS
@ ATTR_STD_GENERATED
@ ATTR_STD_RANDOM_PER_ISLAND
@ ATTR_SUBDIVIDE_SMOOTH_FVAR
AttributeElement
@ ATTR_ELEMENT_NONE
@ ATTR_ELEMENT_CORNER_BYTE
@ ATTR_ELEMENT_CORNER
@ ATTR_ELEMENT_VERTEX
@ ATTR_ELEMENT_FACE
#define LOG_WARNING
Definition log.h:103
#define LOG_TRACE
Definition log.h:108
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline float2 safe_normalize(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:17
#define N
static char faces[256]
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
bool attribute_name_is_anonymous(const StringRef name)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
const char * name
#define make_float2
const PointerRNA PointerRNA_NULL
uchar4 * data_uchar4()
float * data_float()
AttributeStandard std
float3 * data_float3()
Transform * data_transform()
float2 * data_float2()
BL::Object real_object
size_t get_num_subd_faces() const
Definition scene/mesh.h:235
SubdivisionAdaptiveSpace
Definition scene/mesh.h:138
@ SUBDIVISION_ADAPTIVE_SPACE_OBJECT
Definition scene/mesh.h:140
@ SUBDIVISION_ADAPTIVE_SPACE_PIXEL
Definition scene/mesh.h:139
void reserve_subd_creases(const size_t num_creases)
AttributeSet subd_attributes
Definition scene/mesh.h:174
void copy_center_to_motion_step(const int motion_step)
void set_num_subd_faces(const size_t num_subd_faces_)
Definition scene/mesh.h:239
void add_vertex_crease(const int v, const float weight)
@ SUBDIVISION_NONE
Definition scene/mesh.h:118
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:120
void clear_non_sockets()
void resize_subd_faces(const int numfaces, const int numcorners)
void resize_mesh(const int numverts, const int numtris)
void add_edge_crease(const int v0, const int v1, const float weight)
int verts_num
vector< SocketType, std::allocator< SocketType > > inputs
Definition node_type.h:128
const NodeType * type
Definition graph/node.h:178
void set_value(const SocketType &socket, const Node &other, const SocketType &other_socket)
ustring name
Definition node_type.h:81
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
ccl_device_inline Transform transform_scale(const float3 s)
Definition transform.h:280
ccl_device_inline Transform transform_translate(const float3 t)
Definition transform.h:270