Blender V4.3
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 <optional>
6
8#include "blender/session.h"
9#include "blender/sync.h"
10#include "blender/util.h"
11
12#include "scene/camera.h"
13#include "scene/colorspace.h"
14#include "scene/mesh.h"
15#include "scene/object.h"
16#include "scene/scene.h"
17
18#include "subd/patch.h"
19#include "subd/split.h"
20
21#include "util/algorithm.h"
22#include "util/color.h"
23#include "util/disjoint_set.h"
24#include "util/foreach.h"
25#include "util/hash.h"
26#include "util/log.h"
27#include "util/math.h"
28
29#include "mikktspace.hh"
30
31#include "BKE_attribute.hh"
32#include "BKE_attribute_math.hh"
33#include "BKE_customdata.hh"
34#include "BKE_mesh.hh"
35
37
38/* Tangent Space */
39
40template<bool is_subd> struct MikkMeshWrapper {
41 MikkMeshWrapper(const ::Mesh &b_mesh,
42 const char *layer_name,
43 const Mesh *mesh,
44 float3 *tangent,
45 float *tangent_sign)
46 : mesh(mesh), uv(NULL), orco(NULL), tangent(tangent), tangent_sign(tangent_sign)
47 {
48 const AttributeSet &attributes = is_subd ? mesh->subd_attributes : mesh->attributes;
49
50 Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
51 vertex_normal = attr_vN->data_float3();
52
53 if (layer_name == NULL) {
54 Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED);
55
56 if (attr_orco) {
57 orco = attr_orco->data_float3();
58 float3 orco_size;
59 mesh_texture_space(b_mesh, orco_loc, orco_size);
60 inv_orco_size = 1.0f / orco_size;
61 }
62 }
63 else {
64 Attribute *attr_uv = attributes.find(ustring(layer_name));
65 if (attr_uv != NULL) {
66 uv = attr_uv->data_float2();
67 }
68 }
69 }
70
72 {
73 if constexpr (is_subd) {
74 return mesh->get_num_subd_faces();
75 }
76 else {
77 return mesh->num_triangles();
78 }
79 }
80
81 int GetNumVerticesOfFace(const int face_num)
82 {
83 if constexpr (is_subd) {
84 return mesh->get_subd_num_corners()[face_num];
85 }
86 else {
87 return 3;
88 }
89 }
90
91 int CornerIndex(const int face_num, const int vert_num)
92 {
93 if constexpr (is_subd) {
94 const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
95 return face.start_corner + vert_num;
96 }
97 else {
98 return face_num * 3 + vert_num;
99 }
100 }
101
102 int VertexIndex(const int face_num, const int vert_num)
103 {
104 int corner = CornerIndex(face_num, vert_num);
105 if constexpr (is_subd) {
106 return mesh->get_subd_face_corners()[corner];
107 }
108 else {
109 return mesh->get_triangles()[corner];
110 }
111 }
112
113 mikk::float3 GetPosition(const int face_num, const int vert_num)
114 {
115 const float3 vP = mesh->get_verts()[VertexIndex(face_num, vert_num)];
116 return mikk::float3(vP.x, vP.y, vP.z);
117 }
118
119 mikk::float3 GetTexCoord(const int face_num, const int vert_num)
120 {
121 /* TODO: Check whether introducing a template boolean in order to
122 * turn this into a constexpr is worth it. */
123 if (uv != NULL) {
124 const int corner_index = CornerIndex(face_num, vert_num);
125 float2 tfuv = uv[corner_index];
126 return mikk::float3(tfuv.x, tfuv.y, 1.0f);
127 }
128 else if (orco != NULL) {
129 const int vertex_index = VertexIndex(face_num, vert_num);
130 const float2 uv = map_to_sphere((orco[vertex_index] + orco_loc) * inv_orco_size);
131 return mikk::float3(uv.x, uv.y, 1.0f);
132 }
133 else {
134 return mikk::float3(0.0f, 0.0f, 1.0f);
135 }
136 }
137
138 mikk::float3 GetNormal(const int face_num, const int vert_num)
139 {
140 float3 vN;
141 if (is_subd) {
142 const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
143 if (face.smooth) {
144 const int vertex_index = VertexIndex(face_num, vert_num);
145 vN = vertex_normal[vertex_index];
146 }
147 else {
148 vN = face.normal(mesh);
149 }
150 }
151 else {
152 if (mesh->get_smooth()[face_num]) {
153 const int vertex_index = VertexIndex(face_num, vert_num);
154 vN = vertex_normal[vertex_index];
155 }
156 else {
157 const Mesh::Triangle tri = mesh->get_triangle(face_num);
158 vN = tri.compute_normal(&mesh->get_verts()[0]);
159 }
160 }
161 return mikk::float3(vN.x, vN.y, vN.z);
162 }
163
164 void SetTangentSpace(const int face_num, const int vert_num, mikk::float3 T, bool orientation)
165 {
166 const int corner_index = CornerIndex(face_num, vert_num);
167 tangent[corner_index] = make_float3(T.x, T.y, T.z);
168 if (tangent_sign != NULL) {
169 tangent_sign[corner_index] = orientation ? 1.0f : -1.0f;
170 }
171 }
172
173 const Mesh *mesh;
175
181
184};
185
187 const ::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render)
188{
189 /* Create tangent attributes. */
190 const bool is_subd = mesh->get_num_subd_faces();
191 AttributeSet &attributes = is_subd ? mesh->subd_attributes : mesh->attributes;
192 Attribute *attr;
193 ustring name;
194 if (layer_name != NULL) {
195 name = ustring((string(layer_name) + ".tangent").c_str());
196 }
197 else {
198 name = ustring("orco.tangent");
199 }
200 if (active_render) {
201 attr = attributes.add(ATTR_STD_UV_TANGENT, name);
202 }
203 else {
204 attr = attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
205 }
206 float3 *tangent = attr->data_float3();
207 /* Create bitangent sign attribute. */
208 float *tangent_sign = NULL;
209 if (need_sign) {
210 Attribute *attr_sign;
211 ustring name_sign;
212 if (layer_name != NULL) {
213 name_sign = ustring((string(layer_name) + ".tangent_sign").c_str());
214 }
215 else {
216 name_sign = ustring("orco.tangent_sign");
217 }
218
219 if (active_render) {
220 attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
221 }
222 else {
223 attr_sign = attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
224 }
225 tangent_sign = attr_sign->data_float();
226 }
227
228 /* Setup userdata. */
229 if (is_subd) {
230 MikkMeshWrapper<true> userdata(b_mesh, layer_name, mesh, tangent, tangent_sign);
231 /* Compute tangents. */
232 mikk::Mikktspace(userdata).genTangSpace();
233 }
234 else {
235 MikkMeshWrapper<false> userdata(b_mesh, layer_name, mesh, tangent, tangent_sign);
236 /* Compute tangents. */
237 mikk::Mikktspace(userdata).genTangSpace();
238 }
239}
240
243 const float motion_scale)
244{
245 const int numverts = mesh->get_verts().size();
246
247 /* Override motion steps to fixed number. */
248 mesh->set_motion_steps(3);
249
250 /* Find or add attribute */
251 float3 *P = &mesh->get_verts()[0];
252 Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
253
254 if (!attr_mP) {
255 attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
256 }
257
258 /* Only export previous and next frame, we don't have any in between data. */
259 float motion_times[2] = {-1.0f, 1.0f};
260 for (int step = 0; step < 2; step++) {
261 const float relative_time = motion_times[step] * 0.5f * motion_scale;
262 float3 *mP = attr_mP->data_float3() + step * numverts;
263
264 for (int i = 0; i < numverts; i++) {
265 mP[i] = P[i] + make_float3(b_attr[i][0], b_attr[i][1], b_attr[i][2]) * relative_time;
266 }
267 }
268}
269
270static void attr_create_generic(Scene *scene,
271 Mesh *mesh,
272 const ::Mesh &b_mesh,
273 const bool subdivision,
274 const bool need_motion,
275 const float motion_scale)
276{
278 blender::Span<int> tri_faces;
279 if (!subdivision) {
280 corner_tris = b_mesh.corner_tris();
281 tri_faces = b_mesh.corner_tri_faces();
282 }
283 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
284 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
285 static const ustring u_velocity("velocity");
286 const ustring default_color_name{BKE_id_attributes_default_color_name(&b_mesh.id)};
287
288 b_attributes.foreach_attribute([&](const blender::bke::AttributeIter &iter) {
289 const ustring name{std::string_view(iter.name)};
290 const bool is_render_color = name == default_color_name;
291
292 if (need_motion && name == u_velocity) {
293 const blender::VArraySpan b_attribute = *iter.get<blender::float3>(
295 attr_create_motion_from_velocity(mesh, b_attribute, motion_scale);
296 }
297
298 if (!(mesh->need_attribute(scene, name) ||
299 (is_render_color && mesh->need_attribute(scene, ATTR_STD_VERTEX_COLOR))))
300 {
301 return;
302 }
303 if (attributes.find(name)) {
304 return;
305 }
306
307 blender::bke::AttrDomain b_domain = iter.domain;
308 if (b_domain == blender::bke::AttrDomain::Edge) {
309 /* Blender's attribute API handles edge to vertex attribute domain interpolation. */
311 }
312
313 const blender::bke::GAttributeReader b_attr = iter.get(b_domain);
314 if (b_attr.varray.is_empty()) {
315 return;
316 }
317
319 {
320 Attribute *attr = attributes.add(name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
321 if (is_render_color) {
323 }
324
325 uchar4 *data = attr->data_uchar4();
327 if (subdivision) {
328 for (const int i : src.index_range()) {
329 data[i] = make_uchar4(src[i][0], src[i][1], src[i][2], src[i][3]);
330 }
331 }
332 else {
333 for (const int i : corner_tris.index_range()) {
334 const blender::int3 &tri = corner_tris[i];
335 data[i * 3 + 0] = make_uchar4(
336 src[tri[0]][0], src[tri[0]][1], src[tri[0]][2], src[tri[0]][3]);
337 data[i * 3 + 1] = make_uchar4(
338 src[tri[1]][0], src[tri[1]][1], src[tri[1]][2], src[tri[1]][3]);
339 data[i * 3 + 2] = make_uchar4(
340 src[tri[2]][0], src[tri[2]][1], src[tri[2]][2], src[tri[2]][3]);
341 }
342 }
343 return;
344 }
345
347 switch (b_domain) {
349 element = ATTR_ELEMENT_CORNER;
350 break;
352 element = ATTR_ELEMENT_VERTEX;
353 break;
355 element = ATTR_ELEMENT_FACE;
356 break;
357 default:
358 assert(false);
359 return;
360 }
361
363 using BlenderT = decltype(dummy);
364 using Converter = typename ccl::AttributeConverter<BlenderT>;
365 using CyclesT = typename Converter::CyclesT;
366 if constexpr (!std::is_void_v<CyclesT>) {
367 Attribute *attr = attributes.add(name, Converter::type_desc, element);
368 if (is_render_color) {
369 attr->std = ATTR_STD_VERTEX_COLOR;
370 }
371
372 CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
373
374 const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
375 switch (b_attr.domain) {
376 case blender::bke::AttrDomain::Corner: {
377 if (subdivision) {
378 for (const int i : src.index_range()) {
379 data[i] = Converter::convert(src[i]);
380 }
381 }
382 else {
383 for (const int i : corner_tris.index_range()) {
384 const blender::int3 &tri = corner_tris[i];
385 data[i * 3 + 0] = Converter::convert(src[tri[0]]);
386 data[i * 3 + 1] = Converter::convert(src[tri[1]]);
387 data[i * 3 + 2] = Converter::convert(src[tri[2]]);
388 }
389 }
390 break;
391 }
392 case blender::bke::AttrDomain::Point: {
393 for (const int i : src.index_range()) {
394 data[i] = Converter::convert(src[i]);
395 }
396 break;
397 }
398 case blender::bke::AttrDomain::Face: {
399 if (subdivision) {
400 for (const int i : src.index_range()) {
401 data[i] = Converter::convert(src[i]);
402 }
403 }
404 else {
405 for (const int i : corner_tris.index_range()) {
406 data[i] = Converter::convert(src[tri_faces[i]]);
407 }
408 }
409 break;
410 }
411 default: {
412 assert(false);
413 break;
414 }
415 }
416 }
417 });
418 });
419}
420
421static set<ustring> get_blender_uv_names(const ::Mesh &b_mesh)
422{
423 set<ustring> uv_names;
424 b_mesh.attributes().foreach_attribute([&](const blender::bke::AttributeIter &iter) {
426 if (!blender::bke::attribute_name_is_anonymous(iter.name)) {
427 uv_names.emplace(std::string_view(iter.name));
428 }
429 }
430 });
431 return uv_names;
432}
433
434/* Create uv map attributes. */
435static void attr_create_uv_map(Scene *scene,
436 Mesh *mesh,
437 const ::Mesh &b_mesh,
438 const set<ustring> &blender_uv_names)
439{
440 const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
441 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
442 const ustring render_name(CustomData_get_render_layer_name(&b_mesh.corner_data, CD_PROP_FLOAT2));
443 if (!blender_uv_names.empty()) {
444 for (const ustring &uv_name : blender_uv_names) {
445 const bool active_render = uv_name == render_name;
446 AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
447 AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
448 ustring tangent_name = ustring((string(uv_name) + ".tangent").c_str());
449
450 /* Denotes whether UV map was requested directly. */
451 const bool need_uv = mesh->need_attribute(scene, uv_name) ||
452 mesh->need_attribute(scene, uv_std);
453 /* Denotes whether tangent was requested directly. */
454 const bool need_tangent = mesh->need_attribute(scene, tangent_name) ||
455 (active_render && mesh->need_attribute(scene, tangent_std));
456
457 /* UV map */
458 /* NOTE: We create temporary UV layer if its needed for tangent but
459 * wasn't requested by other nodes in shaders.
460 */
461 Attribute *uv_attr = NULL;
462 if (need_uv || need_tangent) {
463 if (active_render) {
464 uv_attr = mesh->attributes.add(uv_std, uv_name);
465 }
466 else {
467 uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
468 }
469
470 const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
471 uv_name.c_str(), blender::bke::AttrDomain::Corner);
472 float2 *fdata = uv_attr->data_float2();
473 for (const int i : corner_tris.index_range()) {
474 const blender::int3 &tri = corner_tris[i];
475 fdata[i * 3 + 0] = make_float2(b_uv_map[tri[0]][0], b_uv_map[tri[0]][1]);
476 fdata[i * 3 + 1] = make_float2(b_uv_map[tri[1]][0], b_uv_map[tri[1]][1]);
477 fdata[i * 3 + 2] = make_float2(b_uv_map[tri[2]][0], b_uv_map[tri[2]][1]);
478 }
479 }
480
481 /* UV tangent */
482 if (need_tangent) {
483 AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
484 ustring sign_name = ustring((string(uv_name) + ".tangent_sign").c_str());
485 bool need_sign = (mesh->need_attribute(scene, sign_name) ||
486 mesh->need_attribute(scene, sign_std));
487 mikk_compute_tangents(b_mesh, uv_name.c_str(), mesh, need_sign, active_render);
488 }
489 /* Remove temporarily created UV attribute. */
490 if (!need_uv && uv_attr != NULL) {
491 mesh->attributes.remove(uv_attr);
492 }
493 }
494 }
495 else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
496 bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
497 mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
498 if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
499 mesh->attributes.remove(ATTR_STD_GENERATED);
500 }
501 }
502}
503
505 Mesh *mesh,
506 const ::Mesh &b_mesh,
507 bool subdivide_uvs,
508 const set<ustring> &blender_uv_names)
509{
510 const blender::OffsetIndices faces = b_mesh.faces();
511 if (faces.is_empty()) {
512 return;
513 }
514
515 if (!blender_uv_names.empty()) {
516 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
517 const ustring render_name(
519 for (const ustring &uv_name : blender_uv_names) {
520 const bool active_render = uv_name == render_name;
521 AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
522 AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
523 ustring tangent_name = ustring((string(uv_name) + ".tangent").c_str());
524
525 /* Denotes whether UV map was requested directly. */
526 const bool need_uv = mesh->need_attribute(scene, uv_name) ||
527 mesh->need_attribute(scene, uv_std);
528 /* Denotes whether tangent was requested directly. */
529 const bool need_tangent = mesh->need_attribute(scene, tangent_name) ||
530 (active_render && mesh->need_attribute(scene, tangent_std));
531
532 Attribute *uv_attr = NULL;
533
534 /* UV map */
535 if (need_uv || need_tangent) {
536 if (active_render) {
537 uv_attr = mesh->subd_attributes.add(uv_std, uv_name);
538 }
539 else {
540 uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
541 }
542
543 if (subdivide_uvs) {
544 uv_attr->flags |= ATTR_SUBDIVIDED;
545 }
546
547 const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
548 uv_name.c_str(), blender::bke::AttrDomain::Corner);
549 float2 *fdata = uv_attr->data_float2();
550
551 for (const int i : faces.index_range()) {
552 const blender::IndexRange face = faces[i];
553 for (const int corner : face) {
554 *(fdata++) = make_float2(b_uv_map[corner][0], b_uv_map[corner][1]);
555 }
556 }
557 }
558
559 /* UV tangent */
560 if (need_tangent) {
561 AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
562 ustring sign_name = ustring((string(uv_name) + ".tangent_sign").c_str());
563 bool need_sign = (mesh->need_attribute(scene, sign_name) ||
564 mesh->need_attribute(scene, sign_std));
565 mikk_compute_tangents(b_mesh, uv_name.c_str(), mesh, need_sign, active_render);
566 }
567 /* Remove temporarily created UV attribute. */
568 if (!need_uv && uv_attr != NULL) {
569 mesh->subd_attributes.remove(uv_attr);
570 }
571 }
572 }
573 else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
574 bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
575 mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
576 if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
577 mesh->subd_attributes.remove(ATTR_STD_GENERATED);
578 }
579 }
580}
581
582/* Create vertex pointiness attributes. */
583
584/* Compare vertices by sum of their coordinates. */
586 public:
588
589 bool operator()(const int &vert_idx_a, const int &vert_idx_b)
590 {
591 const float3 &vert_a = verts_[vert_idx_a];
592 const float3 &vert_b = verts_[vert_idx_b];
593 if (vert_a == vert_b) {
594 /* Special case for doubles, so we ensure ordering. */
595 return vert_idx_a > vert_idx_b;
596 }
597 const float x1 = vert_a.x + vert_a.y + vert_a.z;
598 const float x2 = vert_b.x + vert_b.y + vert_b.z;
599 return x1 < x2;
600 }
601
602 protected:
604};
605
606static void attr_create_pointiness(Mesh *mesh,
607 const blender::Span<blender::float3> positions,
608 const blender::Span<blender::float3> b_vert_normals,
610 bool subdivision)
611{
612 const int num_verts = positions.size();
613 if (positions.is_empty()) {
614 return;
615 }
616
617 /* STEP 1: Find out duplicated vertices and point duplicates to a single
618 * original vertex.
619 */
620 vector<int> sorted_vert_indeices(num_verts);
621 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
622 sorted_vert_indeices[vert_index] = vert_index;
623 }
624 VertexAverageComparator compare(mesh->get_verts());
625 sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare);
626 /* This array stores index of the original vertex for the given vertex
627 * index.
628 */
629 vector<int> vert_orig_index(num_verts);
630 for (int sorted_vert_index = 0; sorted_vert_index < num_verts; ++sorted_vert_index) {
631 const int vert_index = sorted_vert_indeices[sorted_vert_index];
632 const float3 &vert_co = mesh->get_verts()[vert_index];
633 bool found = false;
634 for (int other_sorted_vert_index = sorted_vert_index + 1; other_sorted_vert_index < num_verts;
635 ++other_sorted_vert_index)
636 {
637 const int other_vert_index = sorted_vert_indeices[other_sorted_vert_index];
638 const float3 &other_vert_co = mesh->get_verts()[other_vert_index];
639 /* We are too far away now, we wouldn't have duplicate. */
640 if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) -
641 (vert_co.x + vert_co.y + vert_co.z) >
642 3 * FLT_EPSILON)
643 {
644 break;
645 }
646 /* Found duplicate. */
647 if (len_squared(other_vert_co - vert_co) < FLT_EPSILON) {
648 found = true;
649 vert_orig_index[vert_index] = other_vert_index;
650 break;
651 }
652 }
653 if (!found) {
654 vert_orig_index[vert_index] = vert_index;
655 }
656 }
657 /* Make sure we always points to the very first orig vertex. */
658 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
659 int orig_index = vert_orig_index[vert_index];
660 while (orig_index != vert_orig_index[orig_index]) {
661 orig_index = vert_orig_index[orig_index];
662 }
663 vert_orig_index[vert_index] = orig_index;
664 }
665 sorted_vert_indeices.free_memory();
666 /* STEP 2: Calculate vertex normals taking into account their possible
667 * duplicates which gets "welded" together.
668 */
669 vector<float3> vert_normal(num_verts, zero_float3());
670 /* First we accumulate all vertex normals in the original index. */
671 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
672 const float *b_vert_normal = b_vert_normals[vert_index];
673 const int orig_index = vert_orig_index[vert_index];
674 vert_normal[orig_index] += make_float3(b_vert_normal[0], b_vert_normal[1], b_vert_normal[2]);
675 }
676 /* Then we normalize the accumulated result and flush it to all duplicates
677 * as well.
678 */
679 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
680 const int orig_index = vert_orig_index[vert_index];
681 vert_normal[vert_index] = normalize(vert_normal[orig_index]);
682 }
683 /* STEP 3: Calculate pointiness using single ring neighborhood. */
684 vector<int> counter(num_verts, 0);
685 vector<float> raw_data(num_verts, 0.0f);
686 vector<float3> edge_accum(num_verts, zero_float3());
687 EdgeMap visited_edges;
688 memset(&counter[0], 0, sizeof(int) * counter.size());
689
690 for (const int i : edges.index_range()) {
691 const blender::int2 b_edge = edges[i];
692 const int v0 = vert_orig_index[b_edge[0]];
693 const int v1 = vert_orig_index[b_edge[1]];
694 if (visited_edges.exists(v0, v1)) {
695 continue;
696 }
697 visited_edges.insert(v0, v1);
698 float3 co0 = make_float3(positions[v0][0], positions[v0][1], positions[v0][2]);
699 float3 co1 = make_float3(positions[v1][0], positions[v1][1], positions[v1][2]);
700 float3 edge = normalize(co1 - co0);
701 edge_accum[v0] += edge;
702 edge_accum[v1] += -edge;
703 ++counter[v0];
704 ++counter[v1];
705 }
706 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
707 const int orig_index = vert_orig_index[vert_index];
708 if (orig_index != vert_index) {
709 /* Skip duplicates, they'll be overwritten later on. */
710 continue;
711 }
712 if (counter[vert_index] > 0) {
713 const float3 normal = vert_normal[vert_index];
714 const float angle = safe_acosf(dot(normal, edge_accum[vert_index] / counter[vert_index]));
715 raw_data[vert_index] = angle * M_1_PI_F;
716 }
717 else {
718 raw_data[vert_index] = 0.0f;
719 }
720 }
721 /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */
722 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
723 Attribute *attr = attributes.add(ATTR_STD_POINTINESS);
724 float *data = attr->data_float();
725 memcpy(data, &raw_data[0], sizeof(float) * raw_data.size());
726 memset(&counter[0], 0, sizeof(int) * counter.size());
727 visited_edges.clear();
728 for (const int i : edges.index_range()) {
729 const blender::int2 b_edge = edges[i];
730 const int v0 = vert_orig_index[b_edge[0]];
731 const int v1 = vert_orig_index[b_edge[1]];
732 if (visited_edges.exists(v0, v1)) {
733 continue;
734 }
735 visited_edges.insert(v0, v1);
736 data[v0] += raw_data[v1];
737 data[v1] += raw_data[v0];
738 ++counter[v0];
739 ++counter[v1];
740 }
741 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
742 data[vert_index] /= counter[vert_index] + 1;
743 }
744 /* STEP 4: Copy attribute to the duplicated vertices. */
745 for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
746 const int orig_index = vert_orig_index[vert_index];
747 data[vert_index] = data[orig_index];
748 }
749}
750
751/* The Random Per Island attribute is a random float associated with each
752 * connected component (island) of the mesh. The attribute is computed by
753 * first classifying the vertices into different sets using a Disjoint Set
754 * data structure. Then the index of the root of each vertex (Which is the
755 * representative of the set the vertex belongs to) is hashed and stored.
756 *
757 * We are using a face attribute to avoid interpolation during rendering,
758 * allowing the user to safely hash the output further. Had we used vertex
759 * attribute, the interpolation will introduce very slight variations,
760 * making the output unsafe to hash. */
762 Mesh *mesh,
763 const ::Mesh &b_mesh,
764 bool subdivision)
765{
766 if (!mesh->need_attribute(scene, ATTR_STD_RANDOM_PER_ISLAND)) {
767 return;
768 }
769
770 if (b_mesh.verts_num == 0) {
771 return;
772 }
773
774 DisjointSet vertices_sets(b_mesh.verts_num);
775
776 const blender::Span<blender::int2> edges = b_mesh.edges();
777 const blender::Span<int> corner_verts = b_mesh.corner_verts();
778
779 for (const int i : edges.index_range()) {
780 vertices_sets.join(edges[i][0], edges[i][1]);
781 }
782
783 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
784 Attribute *attribute = attributes.add(ATTR_STD_RANDOM_PER_ISLAND);
785 float *data = attribute->data_float();
786
787 if (!subdivision) {
788 const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
789 if (!corner_tris.is_empty()) {
790 for (const int i : corner_tris.index_range()) {
791 const int vert = corner_verts[corner_tris[i][0]];
792 data[i] = hash_uint_to_float(vertices_sets.find(vert));
793 }
794 }
795 }
796 else {
797 const blender::OffsetIndices<int> faces = b_mesh.faces();
798 if (!faces.is_empty()) {
799 for (const int i : faces.index_range()) {
800 const int vert = corner_verts[faces[i].start()];
801 data[i] = hash_uint_to_float(vertices_sets.find(vert));
802 }
803 }
804 }
805}
806
807/* Create Mesh */
808
809static void create_mesh(Scene *scene,
810 Mesh *mesh,
811 const ::Mesh &b_mesh,
812 const array<Node *> &used_shaders,
813 const bool need_motion,
814 const float motion_scale,
815 const bool subdivision = false,
816 const bool subdivide_uvs = true)
817{
818 const blender::Span<blender::float3> positions = b_mesh.vert_positions();
819 const blender::OffsetIndices faces = b_mesh.faces();
820 const blender::Span<int> corner_verts = b_mesh.corner_verts();
821 const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
822 const blender::bke::MeshNormalDomain normals_domain = b_mesh.normals_domain(true);
823 int numfaces = (!subdivision) ? b_mesh.corner_tris().size() : faces.size();
824
825 bool use_corner_normals = normals_domain == blender::bke::MeshNormalDomain::Corner &&
826 (mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
827
828 /* If no faces, create empty mesh. */
829 if (faces.is_empty()) {
830 return;
831 }
832
833 const blender::VArraySpan material_indices = *b_attributes.lookup<int>(
834 "material_index", blender::bke::AttrDomain::Face);
835 const blender::VArraySpan sharp_faces = *b_attributes.lookup<bool>(
836 "sharp_face", blender::bke::AttrDomain::Face);
837 blender::Span<blender::float3> corner_normals;
838 if (use_corner_normals) {
839 corner_normals = b_mesh.corner_normals();
840 }
841
842 int numngons = 0;
843 int numtris = 0;
844 if (!subdivision) {
845 numtris = numfaces;
846 }
847 else {
848 const blender::OffsetIndices faces = b_mesh.faces();
849 for (const int i : faces.index_range()) {
850 numngons += (faces[i].size() == 4) ? 0 : 1;
851 }
852 }
853
854 /* allocate memory */
855 if (subdivision) {
856 mesh->resize_subd_faces(numfaces, numngons, corner_verts.size());
857 }
858 mesh->resize_mesh(positions.size(), numtris);
859
860 float3 *verts = mesh->get_verts().data();
861 for (const int i : positions.index_range()) {
862 verts[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
863 }
864
865 AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
866 Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
867 float3 *N = attr_N->data_float3();
868
869 if (subdivision || !(use_corner_normals && !corner_normals.is_empty())) {
870 const blender::Span<blender::float3> vert_normals = b_mesh.vert_normals();
871 for (const int i : vert_normals.index_range()) {
872 N[i] = make_float3(vert_normals[i][0], vert_normals[i][1], vert_normals[i][2]);
873 }
874 }
875
876 const set<ustring> blender_uv_names = get_blender_uv_names(b_mesh);
877
878 /* create generated coordinates from undeformed coordinates */
879 const bool need_default_tangent = (subdivision == false) && (blender_uv_names.empty()) &&
880 (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
881 if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) {
882 const float(*orco)[3] = static_cast<const float(*)[3]>(
883 CustomData_get_layer(&b_mesh.vert_data, CD_ORCO));
884 Attribute *attr = attributes.add(ATTR_STD_GENERATED);
885 attr->flags |= ATTR_SUBDIVIDED;
886
887 float3 loc, size;
888 mesh_texture_space(b_mesh, loc, size);
889
890 float texspace_location[3], texspace_size[3];
891 BKE_mesh_texspace_get(const_cast<::Mesh *>(b_mesh.texcomesh ? b_mesh.texcomesh : &b_mesh),
892 texspace_location,
893 texspace_size);
894
895 float3 *generated = attr->data_float3();
896
897 for (const int i : positions.index_range()) {
898 blender::float3 value;
899 if (orco) {
900 madd_v3_v3v3v3(value, texspace_location, orco[i], texspace_size);
901 }
902 else {
903 value = positions[i];
904 }
905 generated[i] = make_float3(value[0], value[1], value[2]) * size - loc;
906 }
907 }
908
909 auto clamp_material_index = [&](const int material_index) -> int {
910 return clamp(material_index, 0, used_shaders.size() - 1);
911 };
912
913 /* create faces */
914 if (!subdivision) {
915 int *triangles = mesh->get_triangles().data();
916 bool *smooth = mesh->get_smooth().data();
917 int *shader = mesh->get_shader().data();
918
919 const blender::Span<blender::int3> corner_tris = b_mesh.corner_tris();
920 for (const int i : corner_tris.index_range()) {
921 const blender::int3 &tri = corner_tris[i];
922 triangles[i * 3 + 0] = corner_verts[tri[0]];
923 triangles[i * 3 + 1] = corner_verts[tri[1]];
924 triangles[i * 3 + 2] = corner_verts[tri[2]];
925 }
926
927 if (!material_indices.is_empty()) {
928 const blender::Span<int> tri_faces = b_mesh.corner_tri_faces();
929 for (const int i : corner_tris.index_range()) {
930 shader[i] = clamp_material_index(material_indices[tri_faces[i]]);
931 }
932 }
933 else {
934 std::fill(shader, shader + numtris, 0);
935 }
936
937 if (!sharp_faces.is_empty() && !(use_corner_normals && !corner_normals.is_empty())) {
938 const blender::Span<int> tri_faces = b_mesh.corner_tri_faces();
939 for (const int i : corner_tris.index_range()) {
940 smooth[i] = !sharp_faces[tri_faces[i]];
941 }
942 }
943 else {
944 /* If only face normals are needed, all faces are sharp. */
945 std::fill(smooth, smooth + numtris, normals_domain != blender::bke::MeshNormalDomain::Face);
946 }
947
948 if (use_corner_normals && !corner_normals.is_empty()) {
949 for (const int i : corner_tris.index_range()) {
950 const blender::int3 &tri = corner_tris[i];
951 for (int i = 0; i < 3; i++) {
952 const int corner = tri[i];
953 const int vert = corner_verts[corner];
954 const float *normal = corner_normals[corner];
955 N[vert] = make_float3(normal[0], normal[1], normal[2]);
956 }
957 }
958 }
959
960 mesh->tag_triangles_modified();
961 mesh->tag_shader_modified();
962 mesh->tag_smooth_modified();
963 }
964 else {
965 int *subd_start_corner = mesh->get_subd_start_corner().data();
966 int *subd_num_corners = mesh->get_subd_num_corners().data();
967 int *subd_shader = mesh->get_subd_shader().data();
968 bool *subd_smooth = mesh->get_subd_smooth().data();
969 int *subd_ptex_offset = mesh->get_subd_ptex_offset().data();
970 int *subd_face_corners = mesh->get_subd_face_corners().data();
971
972 if (!sharp_faces.is_empty() && !use_corner_normals) {
973 for (int i = 0; i < numfaces; i++) {
974 subd_smooth[i] = !sharp_faces[i];
975 }
976 }
977 else {
978 std::fill(subd_smooth, subd_smooth + numfaces, true);
979 }
980
981 if (!material_indices.is_empty()) {
982 for (int i = 0; i < numfaces; i++) {
983 subd_shader[i] = clamp_material_index(material_indices[i]);
984 }
985 }
986 else {
987 std::fill(subd_shader, subd_shader + numfaces, 0);
988 }
989
990 std::copy(corner_verts.data(), corner_verts.data() + corner_verts.size(), subd_face_corners);
991
992 const blender::OffsetIndices faces = b_mesh.faces();
993 int ptex_offset = 0;
994 for (const int i : faces.index_range()) {
995 const blender::IndexRange face = faces[i];
996
997 subd_start_corner[i] = face.start();
998 subd_num_corners[i] = face.size();
999 subd_ptex_offset[i] = ptex_offset;
1000 const int num_ptex = (face.size() == 4) ? 1 : face.size();
1001 ptex_offset += num_ptex;
1002 }
1003
1004 mesh->tag_subd_face_corners_modified();
1005 mesh->tag_subd_start_corner_modified();
1006 mesh->tag_subd_num_corners_modified();
1007 mesh->tag_subd_shader_modified();
1008 mesh->tag_subd_smooth_modified();
1009 mesh->tag_subd_ptex_offset_modified();
1010 }
1011
1012 /* Create all needed attributes.
1013 * The calculate functions will check whether they're needed or not.
1014 */
1015 if (mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
1016 attr_create_pointiness(mesh, positions, b_mesh.vert_normals(), b_mesh.edges(), subdivision);
1017 }
1018 attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
1019 attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
1020
1021 if (subdivision) {
1022 attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs, blender_uv_names);
1023 }
1024 else {
1025 attr_create_uv_map(scene, mesh, b_mesh, blender_uv_names);
1026 }
1027
1028 /* For volume objects, create a matrix to transform from object space to
1029 * mesh texture space. this does not work with deformations but that can
1030 * probably only be done well with a volume grid mapping of coordinates. */
1031 if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
1032 Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
1033 Transform *tfm = attr->data_transform();
1034
1035 float3 loc, size;
1036 mesh_texture_space(b_mesh, loc, size);
1037
1038 *tfm = transform_translate(-loc) * transform_scale(size);
1039 }
1040}
1041
1042static void create_subd_mesh(Scene *scene,
1043 Mesh *mesh,
1044 BObjectInfo &b_ob_info,
1045 const ::Mesh &b_mesh,
1046 const array<Node *> &used_shaders,
1047 const bool need_motion,
1048 const float motion_scale,
1049 float dicing_rate,
1050 int max_subdivisions)
1051{
1052 BL::Object b_ob = b_ob_info.real_object;
1053
1054 BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]);
1055 bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE;
1056
1057 create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs);
1058
1059 const blender::VArraySpan creases = *b_mesh.attributes().lookup<float>(
1060 "crease_edge", blender::bke::AttrDomain::Edge);
1061 if (!creases.is_empty()) {
1062 size_t num_creases = 0;
1063 for (const int i : creases.index_range()) {
1064 if (creases[i] != 0.0f) {
1065 num_creases++;
1066 }
1067 }
1068
1069 mesh->reserve_subd_creases(num_creases);
1070
1071 const blender::Span<blender::int2> edges = b_mesh.edges();
1072 for (const int i : edges.index_range()) {
1073 const float crease = creases[i];
1074 if (crease != 0.0f) {
1075 const blender::int2 &b_edge = edges[i];
1076 mesh->add_edge_crease(b_edge[0], b_edge[1], crease);
1077 }
1078 }
1079 }
1080
1081 const blender::VArraySpan vert_creases = *b_mesh.attributes().lookup<float>(
1082 "crease_vert", blender::bke::AttrDomain::Point);
1083 if (!vert_creases.is_empty()) {
1084 for (const int i : vert_creases.index_range()) {
1085 if (vert_creases[i] != 0.0f) {
1086 mesh->add_vertex_crease(i, vert_creases[i]);
1087 }
1088 }
1089 }
1090
1091 /* set subd params */
1092 PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
1093 float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
1094
1095 mesh->set_subd_dicing_rate(subd_dicing_rate);
1096 mesh->set_subd_max_level(max_subdivisions);
1097 mesh->set_subd_objecttoworld(get_transform(b_ob.matrix_world()));
1098}
1099
1100/* Sync */
1101
1102void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
1103{
1104 /* make a copy of the shaders as the caller in the main thread still need them for syncing the
1105 * attributes */
1106 array<Node *> used_shaders = mesh->get_used_shaders();
1107
1108 Mesh new_mesh;
1109 new_mesh.set_used_shaders(used_shaders);
1110
1111 if (view_layer.use_surfaces) {
1112 /* Adaptive subdivision setup. Not for baking since that requires
1113 * exact mapping to the Blender mesh. */
1114 if (!scene->bake_manager->get_baking()) {
1115 new_mesh.set_subdivision_type(
1116 object_subdivision_type(b_ob_info.real_object, preview, experimental));
1117 }
1118
1119 /* For some reason, meshes do not need this... */
1120 bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED);
1121 BL::Mesh b_mesh = object_to_mesh(
1122 b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
1123
1124 if (b_mesh) {
1125 /* Motion blur attribute is relative to seconds, we need it relative to frames. */
1126 const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
1127 const float motion_scale = (need_motion) ?
1128 scene->motion_shutter_time() /
1129 (b_scene.render().fps() / b_scene.render().fps_base()) :
1130 0.0f;
1131
1132 /* Sync mesh itself. */
1133 if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
1134 create_subd_mesh(scene,
1135 &new_mesh,
1136 b_ob_info,
1137 *static_cast<const ::Mesh *>(b_mesh.ptr.data),
1138 new_mesh.get_used_shaders(),
1139 need_motion,
1140 motion_scale,
1141 dicing_rate,
1142 max_subdivisions);
1143 }
1144 else {
1145 create_mesh(scene,
1146 &new_mesh,
1147 *static_cast<const ::Mesh *>(b_mesh.ptr.data),
1148 new_mesh.get_used_shaders(),
1149 need_motion,
1150 motion_scale,
1151 false);
1152 }
1153
1154 free_object_to_mesh(b_data, b_ob_info, b_mesh);
1155 }
1156 }
1157
1158 /* update original sockets */
1159
1160 mesh->clear_non_sockets();
1161
1162 for (const SocketType &socket : new_mesh.type->inputs) {
1163 /* Those sockets are updated in sync_object, so do not modify them. */
1164 if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
1165 socket.name == "used_shaders")
1166 {
1167 continue;
1168 }
1169 mesh->set_value(socket, new_mesh, socket);
1170 }
1171
1172 mesh->attributes.update(std::move(new_mesh.attributes));
1173 mesh->subd_attributes.update(std::move(new_mesh.subd_attributes));
1174
1175 mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
1176
1177 /* tag update */
1178 bool rebuild = (mesh->triangles_is_modified()) || (mesh->subd_num_corners_is_modified()) ||
1179 (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
1180 (mesh->subd_ptex_offset_is_modified()) ||
1181 (mesh->subd_start_corner_is_modified()) ||
1182 (mesh->subd_face_corners_is_modified());
1183
1184 mesh->tag_update(scene, rebuild);
1185}
1186
1187void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
1188 BObjectInfo &b_ob_info,
1189 Mesh *mesh,
1190 int motion_step)
1191{
1192 /* Skip if no vertices were exported. */
1193 size_t numverts = mesh->get_verts().size();
1194 if (numverts == 0) {
1195 return;
1196 }
1197
1198 /* Skip objects without deforming modifiers. this is not totally reliable,
1199 * would need a more extensive check to see which objects are animated. */
1200 BL::Mesh b_mesh_rna(PointerRNA_NULL);
1201 if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
1202 /* get derived mesh */
1203 b_mesh_rna = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
1204 }
1205
1206 const std::string ob_name = b_ob_info.real_object.name();
1207
1208 /* TODO(sergey): Perform preliminary check for number of vertices. */
1209 if (b_mesh_rna) {
1210 const ::Mesh &b_mesh = *static_cast<const ::Mesh *>(b_mesh_rna.ptr.data);
1211 const int b_verts_num = b_mesh.verts_num;
1212 const blender::Span<blender::float3> positions = b_mesh.vert_positions();
1213 if (positions.is_empty()) {
1214 free_object_to_mesh(b_data, b_ob_info, b_mesh_rna);
1215 return;
1216 }
1217
1218 /* Export deformed coordinates. */
1219 /* Find attributes. */
1220 Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
1221 Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
1222 Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
1223 bool new_attribute = false;
1224 /* Add new attributes if they don't exist already. */
1225 if (!attr_mP) {
1226 attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
1227 if (attr_N) {
1228 attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
1229 }
1230
1231 new_attribute = true;
1232 }
1233 /* Load vertex data from mesh. */
1234 float3 *mP = attr_mP->data_float3() + motion_step * numverts;
1235 float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : NULL;
1236
1237 /* NOTE: We don't copy more that existing amount of vertices to prevent
1238 * possible memory corruption.
1239 */
1240 for (int i = 0; i < std::min<size_t>(b_verts_num, numverts); i++) {
1241 mP[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
1242 }
1243 if (mN) {
1244 const blender::Span<blender::float3> b_vert_normals = b_mesh.vert_normals();
1245 for (int i = 0; i < std::min<size_t>(b_verts_num, numverts); i++) {
1246 mN[i] = make_float3(b_vert_normals[i][0], b_vert_normals[i][1], b_vert_normals[i][2]);
1247 }
1248 }
1249 if (new_attribute) {
1250 /* In case of new attribute, we verify if there really was any motion. */
1251 if (b_verts_num != numverts ||
1252 memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0)
1253 {
1254 /* no motion, remove attributes again */
1255 if (b_verts_num != numverts) {
1256 VLOG_WARNING << "Topology differs, disabling motion blur for object " << ob_name;
1257 }
1258 else {
1259 VLOG_DEBUG << "No actual deformation motion for object " << ob_name;
1260 }
1261 mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
1262 if (attr_mN) {
1263 mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
1264 }
1265 }
1266 else if (motion_step > 0) {
1267 VLOG_DEBUG << "Filling deformation motion for object " << ob_name;
1268 /* motion, fill up previous steps that we might have skipped because
1269 * they had no motion, but we need them anyway now */
1270 float3 *P = &mesh->get_verts()[0];
1271 float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
1272 for (int step = 0; step < motion_step; step++) {
1273 memcpy(attr_mP->data_float3() + step * numverts, P, sizeof(float3) * numverts);
1274 if (attr_mN) {
1275 memcpy(attr_mN->data_float3() + step * numverts, N, sizeof(float3) * numverts);
1276 }
1277 }
1278 }
1279 }
1280 else {
1281 if (b_verts_num != numverts) {
1282 VLOG_WARNING << "Topology differs, discarding motion blur for object " << ob_name
1283 << " at time " << motion_step;
1284 memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
1285 if (mN != NULL) {
1286 memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
1287 }
1288 }
1289 }
1290
1291 free_object_to_mesh(b_data, b_ob_info, b_mesh_rna);
1292 return;
1293 }
1294
1295 /* No deformation on this frame, copy coordinates if other frames did have it. */
1296 mesh->copy_center_to_motion_step(motion_step);
1297}
1298
const char * 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)
bool map_to_sphere(float *r_u, float *r_v, float x, float y, float z)
MINLINE void madd_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT2
constexpr PointerRNA PointerRNA_NULL
Definition RNA_types.hh:45
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 mikk_compute_tangents(const ::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render)
static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, const ::Mesh &b_mesh, bool subdivide_uvs, const set< ustring > &blender_uv_names)
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, float dicing_rate, int max_subdivisions)
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, const bool subdivide_uvs=true)
static void attr_create_motion_from_velocity(Mesh *mesh, const blender::Span< blender::float3 > b_attr, const float motion_scale)
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 DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
Definition btDbvt.cpp:418
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
list< Attribute > attributes
uchar4 * data_uchar4()
float * data_float()
AttributeStandard std
float3 * data_float3()
Transform * data_transform()
void add(const float &f)
float2 * data_float2()
void join(size_t x, size_t y)
size_t find(size_t x)
void insert(int v0, int v1)
bool exists(int v0, int v1)
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 start() const
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader get() const
void free_memory()
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
static void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
static void free_object_to_mesh(BL::BlendData &, BObjectInfo &b_ob_info, BL::Mesh &mesh)
static BL::Mesh object_to_mesh(BL::BlendData &, BObjectInfo &b_ob_info, BL::Depsgraph &, bool, Mesh::SubdivisionType subdivision_type)
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
static Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, bool preview, bool experimental)
static Transform get_transform(const BL::Array< float, 16 > &array)
#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)
#define NULL
ccl_device_forceinline float2 make_float2(const float x, const float y)
draw_view in_light_buf[] float
static float verts[][3]
ccl_device_inline float hash_uint_to_float(uint kx)
Definition hash.h:136
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_UV_TANGENT_SIGN
@ ATTR_STD_POINTINESS
@ ATTR_STD_GENERATED
@ ATTR_STD_RANDOM_PER_ISLAND
@ ATTR_SUBDIVIDED
AttributeElement
@ ATTR_ELEMENT_NONE
@ ATTR_ELEMENT_CORNER_BYTE
@ ATTR_ELEMENT_CORNER
@ ATTR_ELEMENT_VERTEX
@ ATTR_ELEMENT_FACE
#define VLOG_WARNING
Definition log.h:70
#define VLOG_DEBUG
Definition log.h:81
ccl_device_inline float len_squared(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
#define N
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
T step(const T &edge, const T &value)
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
CCL_NAMESPACE_BEGIN static OIIO_NAMESPACE_USING constexpr TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
BL::Object real_object
float3 compute_normal(const float3 *verts) const
size_t get_num_subd_faces() const
Definition scene/mesh.h:233
AttributeSet subd_attributes
Definition scene/mesh.h:159
@ SUBDIVISION_NONE
Definition scene/mesh.h:121
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:123
int verts_num
mikk::float3 GetPosition(const int face_num, const int vert_num)
int GetNumVerticesOfFace(const int face_num)
void SetTangentSpace(const int face_num, const int vert_num, mikk::float3 T, bool orientation)
MikkMeshWrapper(const ::Mesh &b_mesh, const char *layer_name, const Mesh *mesh, float3 *tangent, float *tangent_sign)
mikk::float3 GetNormal(const int face_num, const int vert_num)
mikk::float3 GetTexCoord(const int face_num, const int vert_num)
int CornerIndex(const int face_num, const int vert_num)
int VertexIndex(const int face_num, const int vert_num)
const Mesh * mesh
float x
float y
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
ccl_device_inline Transform transform_translate(float3 t)
Definition transform.h:244
ccl_device_inline Transform transform_scale(float3 s)
Definition transform.h:254
float max
static Mesh * create_mesh(SnapObjectContext *sctx, const Object *ob_eval, eSnapEditType)
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379