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