Blender V5.0
BlenderFileLoader.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BlenderFileLoader.h"
10
11#include "DNA_meshdata_types.h"
12
13#include "BLI_math_geom.h"
14#include "BLI_math_matrix.h"
15#include "BLI_math_vector.h"
16#include "BLI_utildefines.h"
17
18#include "BKE_attribute.hh"
19#include "BKE_customdata.hh"
20#include "BKE_global.hh"
21#include "BKE_mesh.hh"
22#include "BKE_object.hh"
23
24#include <sstream>
25
26using blender::float3;
27using blender::Span;
28
29namespace Freestyle {
30
32{
33 _re = re;
35 _Scene = nullptr;
36 _numFacesRead = 0;
37#if 0
38 _minEdgeSize = DBL_MAX;
39#endif
41 _pRenderMonitor = nullptr;
42}
43
48
50{
51 if (G.debug & G_DEBUG_FREESTYLE) {
52 cout << "\n=== Importing triangular meshes into Blender ===" << endl;
53 }
54
55 // creation of the scene root node
56 _Scene = new NodeGroup;
57
58 if (_re->clip_start < 0.0f) {
59 // Adjust clipping start/end and set up a Z offset when the viewport preview
60 // is used with the orthographic view. In this case, _re->clip_start is negative,
61 // while Freestyle assumes that imported mesh data are in the camera coordinate
62 // system with the view point located at origin [bug #36009].
63 _z_near = -0.001f;
64 _z_offset = _re->clip_start + _z_near;
65 _z_far = -_re->clip_end + _z_offset;
66 }
67 else {
68 _z_near = -_re->clip_start;
69 _z_far = -_re->clip_end;
70 _z_offset = 0.0f;
71 }
72
73 int id = 0;
74 const eEvaluationMode eval_mode = DEG_get_mode(_depsgraph);
75
76 DEGObjectIterSettings deg_iter_settings{};
77 deg_iter_settings.depsgraph = _depsgraph;
81 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
82 if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
83 break;
84 }
85
86 if ((ob->base_flag & (BASE_HOLDOUT | BASE_INDIRECT_ONLY)) ||
87 (ob->visibility_flag & OB_HOLDOUT))
88 {
89 continue;
90 }
91
92 if (!(BKE_object_visibility(ob, eval_mode) & OB_VISIBLE_SELF)) {
93 continue;
94 }
95
96 /* Evaluated meta-balls will appear as mesh objects in the iterator. */
97 if (ob->type == OB_MBALL) {
98 continue;
99 }
100
101 Mesh *mesh = BKE_object_to_mesh(nullptr, ob, false);
102
103 if (mesh) {
104 insertShapeNode(ob, mesh, ++id);
106 }
107 }
109
110 // Return the built scene.
111 return _Scene;
112}
113
114#define CLIPPED_BY_NEAR -1
115#define NOT_CLIPPED 0
116#define CLIPPED_BY_FAR 1
117
118// check if each vertex of a triangle (V1, V2, V3) is clipped by the near/far plane
119// and calculate the number of triangles to be generated by clipping
120int BlenderFileLoader::countClippedFaces(float v1[3], float v2[3], float v3[3], int clip[3])
121{
122 float *v[3];
123 int numClipped, sum, numTris = 0;
124
125 v[0] = v1;
126 v[1] = v2;
127 v[2] = v3;
128 numClipped = sum = 0;
129 for (int i = 0; i < 3; i++) {
130 if (v[i][2] > _z_near) {
131 clip[i] = CLIPPED_BY_NEAR;
132 numClipped++;
133 }
134 else if (v[i][2] < _z_far) {
135 clip[i] = CLIPPED_BY_FAR;
136 numClipped++;
137 }
138 else {
139 clip[i] = NOT_CLIPPED;
140 }
141#if 0
142 if (G.debug & G_DEBUG_FREESTYLE) {
143 printf("%d %s\n",
144 i,
145 (clip[i] == NOT_CLIPPED) ? "not" :
146 (clip[i] == CLIPPED_BY_NEAR) ? "near" :
147 "far");
148 }
149#endif
150 sum += clip[i];
151 }
152 switch (numClipped) {
153 case 0:
154 numTris = 1; // triangle
155 break;
156 case 1:
157 numTris = 2; // tetragon
158 break;
159 case 2:
160 if (sum == 0) {
161 numTris = 3; // pentagon
162 }
163 else {
164 numTris = 1; // triangle
165 }
166 break;
167 case 3:
168 if (ELEM(sum, 3, -3)) {
169 numTris = 0;
170 }
171 else {
172 numTris = 2; // tetragon
173 }
174 break;
175 }
176 return numTris;
177}
178
179// find the intersection point C between the line segment from V1 to V2 and
180// a clipping plane at depth Z (i.e., the Z component of C is known, while
181// the X and Y components are unknown).
182void BlenderFileLoader::clipLine(float v1[3], float v2[3], float c[3], float z)
183{
184 // Order v1 and v2 by Z values to make sure that clipLine(P, Q, c, z)
185 // and clipLine(Q, P, c, z) gives exactly the same numerical result.
186 float *p, *q;
187 if (v1[2] < v2[2]) {
188 p = v1;
189 q = v2;
190 }
191 else {
192 p = v2;
193 q = v1;
194 }
195 double d[3];
196 for (int i = 0; i < 3; i++) {
197 d[i] = q[i] - p[i];
198 }
199 double t = (z - p[2]) / d[2];
200 c[0] = p[0] + t * d[0];
201 c[1] = p[1] + t * d[1];
202 c[2] = z;
203}
204
205// clip the triangle (V1, V2, V3) by the near and far clipping plane and
206// obtain a set of vertices after the clipping. The number of vertices
207// is at most 5.
209 float triCoords[][3],
210 float v1[3],
211 float v2[3],
212 float v3[3],
213 float triNormals[][3],
214 float n1[3],
215 float n2[3],
216 float n3[3],
217 bool edgeMarks[5],
218 bool em1,
219 bool em2,
220 bool em3,
221 const int clip[3])
222{
223 float *v[3], *n[3];
224 bool em[3];
225 int i, j, k;
226
227 v[0] = v1;
228 n[0] = n1;
229 v[1] = v2;
230 n[1] = n2;
231 v[2] = v3;
232 n[2] = n3;
233 em[0] = em1; /* edge mark of the edge between v1 and v2 */
234 em[1] = em2; /* edge mark of the edge between v2 and v3 */
235 em[2] = em3; /* edge mark of the edge between v3 and v1 */
236 k = 0;
237 for (i = 0; i < 3; i++) {
238 j = (i + 1) % 3;
239 if (clip[i] == NOT_CLIPPED) {
240 copy_v3_v3(triCoords[k], v[i]);
241 copy_v3_v3(triNormals[k], n[i]);
242 edgeMarks[k] = em[i];
243 k++;
244 if (clip[j] != NOT_CLIPPED) {
245 clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
246 copy_v3_v3(triNormals[k], n[j]);
247 edgeMarks[k] = false;
248 k++;
249 }
250 }
251 else if (clip[i] != clip[j]) {
252 if (clip[j] == NOT_CLIPPED) {
253 clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
254 copy_v3_v3(triNormals[k], n[i]);
255 edgeMarks[k] = em[i];
256 k++;
257 }
258 else {
259 clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
260 copy_v3_v3(triNormals[k], n[i]);
261 edgeMarks[k] = em[i];
262 k++;
263 clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
264 copy_v3_v3(triNormals[k], n[j]);
265 edgeMarks[k] = false;
266 k++;
267 }
268 }
269 }
270 BLI_assert(k == 2 + numTris);
271 (void)numTris; /* Ignored in release builds. */
272}
273
275 float v1[3],
276 float v2[3],
277 float v3[3],
278 float n1[3],
279 float n2[3],
280 float n3[3],
281 bool fm,
282 bool em1,
283 bool em2,
284 bool em3)
285{
286 float *fv[3], *fn[3];
287#if 0
288 float len;
289#endif
290 uint i, j;
292
293 // initialize the bounding box by the first vertex
294 if (ls->currentIndex == 0) {
295 copy_v3_v3(ls->minBBox, v1);
296 copy_v3_v3(ls->maxBBox, v1);
297 }
298
299 fv[0] = v1;
300 fn[0] = n1;
301 fv[1] = v2;
302 fn[1] = n2;
303 fv[2] = v3;
304 fn[2] = n3;
305 for (i = 0; i < 3; i++) {
306
307 copy_v3_v3(ls->pv, fv[i]);
308 copy_v3_v3(ls->pn, fn[i]);
309
310 // update the bounding box
311 for (j = 0; j < 3; j++) {
312 if (ls->minBBox[j] > ls->pv[j]) {
313 ls->minBBox[j] = ls->pv[j];
314 }
315
316 if (ls->maxBBox[j] < ls->pv[j]) {
317 ls->maxBBox[j] = ls->pv[j];
318 }
319 }
320
321#if 0
322 len = len_v3v3(fv[i], fv[(i + 1) % 3]);
323 if (_minEdgeSize > len) {
324 _minEdgeSize = len;
325 }
326#endif
327
328 *ls->pvi = ls->currentIndex;
329 *ls->pni = ls->currentIndex;
330 *ls->pmi = ls->currentMIndex;
331
332 ls->currentIndex += 3;
333 ls->pv += 3;
334 ls->pn += 3;
335
336 ls->pvi++;
337 ls->pni++;
338 ls->pmi++;
339 }
340
341 if (fm) {
343 }
344 if (em1) {
346 }
347 if (em2) {
349 }
350 if (em3) {
352 }
353 *(ls->pm++) = marks;
354}
355
356// With A, B and P indicating the three vertices of a given triangle, returns:
357// 1 if points A and B are in the same position in the 3D space;
358// 2 if the distance between point P and line segment AB is zero; and
359// zero otherwise.
360int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3[3])
361{
362 const float eps = 1.0e-6;
363 const float eps_sq = eps * eps;
364
365#if 0
366 float area = area_tri_v3(v1, v2, v3);
367 bool verbose = (area < 1.0e-6);
368#endif
369
370 if (equals_v3v3(v1, v2) || equals_v3v3(v2, v3) || equals_v3v3(v1, v3)) {
371#if 0
372 if (verbose && G.debug & G_DEBUG_FREESTYLE) {
373 printf("BlenderFileLoader::testDegenerateTriangle = 1\n");
374 }
375#endif
376 return 1;
377 }
378 if (dist_squared_to_line_segment_v3(v1, v2, v3) < eps_sq ||
379 dist_squared_to_line_segment_v3(v2, v1, v3) < eps_sq ||
380 dist_squared_to_line_segment_v3(v3, v1, v2) < eps_sq)
381 {
382#if 0
383 if (verbose && G.debug & G_DEBUG_FREESTYLE) {
384 printf("BlenderFileLoader::testDegenerateTriangle = 2\n");
385 }
386#endif
387 return 2;
388 }
389#if 0
390 if (verbose && G.debug & G_DEBUG_FREESTYLE) {
391 printf("BlenderFileLoader::testDegenerateTriangle = 0\n");
392 }
393#endif
394 return 0;
395}
396
397static bool testEdgeMark(Mesh *mesh,
398 const blender::VArray<bool> &fed,
399 const blender::int3 &tri,
400 int i)
401{
402 const Span<blender::int2> edges = mesh->edges();
403 const Span<int> corner_verts = mesh->corner_verts();
404 const Span<int> corner_edges = mesh->corner_edges();
405
406 const int corner = tri[i];
407 const int corner_next = tri[(i + 1) % 3];
408 const blender::int2 &edge = edges[corner_edges[corner]];
409
410 if (!ELEM(corner_verts[corner_next], edge[0], edge[1])) {
411 /* Not an edge in the original mesh before triangulation. */
412 return false;
413 }
414
415 return fed[corner_edges[corner]];
416}
417
419{
420 using namespace blender;
421 char *name = ob->id.name + 2;
422
423 const Span<float3> vert_positions = mesh->vert_positions();
424 const OffsetIndices mesh_polys = mesh->faces();
425 const Span<int> corner_verts = mesh->corner_verts();
426
427 // Compute loop triangles
428 int tottri = poly_to_tri_count(mesh->faces_num, mesh->corners_num);
429 blender::int3 *corner_tris = MEM_malloc_arrayN<blender::int3>(size_t(tottri), __func__);
431 vert_positions, mesh_polys, corner_verts, {corner_tris, tottri});
432 const blender::Span<int> tri_faces = mesh->corner_tri_faces();
433 const blender::Span<blender::float3> corner_normals = mesh->corner_normals();
434 const bke::AttributeAccessor attributes = mesh->attributes();
435
436 // Get other mesh data
437 const VArray<bool> fed = *attributes.lookup_or_default<bool>(
438 "freestyle_edge", bke::AttrDomain::Edge, false);
439 const VArray<bool> ffa = *attributes.lookup_or_default<bool>(
440 "freestyle_face", bke::AttrDomain::Face, false);
441
442 // Compute view matrix
444 float viewinv[4][4], viewmat[4][4];
445 RE_GetCameraModelMatrix(_re, ob_camera_eval, viewinv);
446 invert_m4_m4(viewmat, viewinv);
447
448 // Compute matrix including camera transform
449 float obmat[4][4], nmat[4][4];
450 mul_m4_m4m4(obmat, viewmat, ob->object_to_world().ptr());
451 invert_m4_m4(nmat, obmat);
452 transpose_m4(nmat);
453
454 // We count the number of triangles after the clipping by the near and far view
455 // planes is applied (NOTE: mesh vertices are in the camera coordinate system).
456 uint numFaces = 0;
457 float v1[3], v2[3], v3[3];
458 float n1[3], n2[3], n3[3], facenormal[3];
459 int clip[3];
460 for (int a = 0; a < tottri; a++) {
461 const int3 &tri = corner_tris[a];
462
463 copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
464 copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
465 copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
466
467 mul_m4_v3(obmat, v1);
468 mul_m4_v3(obmat, v2);
469 mul_m4_v3(obmat, v3);
470
471 v1[2] += _z_offset;
472 v2[2] += _z_offset;
473 v3[2] += _z_offset;
474
475 numFaces += countClippedFaces(v1, v2, v3, clip);
476 }
477#if 0
478 if (G.debug & G_DEBUG_FREESTYLE) {
479 cout << "numFaces " << numFaces << endl;
480 }
481#endif
482 if (numFaces == 0) {
483 MEM_freeN(corner_tris);
484 return;
485 }
486
487 // We allocate memory for the meshes to be imported
488 NodeGroup *currentMesh = new NodeGroup;
489 NodeShape *shape = new NodeShape;
490
491 uint vSize = 3 * 3 * numFaces;
492 float *vertices = new float[vSize];
493 uint nSize = vSize;
494 float *normals = new float[nSize];
495 uint *numVertexPerFaces = new uint[numFaces];
496 vector<Material *> meshMaterials;
497 vector<FrsMaterial> meshFrsMaterials;
498
500 uint i;
501 for (i = 0; i < numFaces; i++) {
502 faceStyle[i] = IndexedFaceSet::TRIANGLES;
503 numVertexPerFaces[i] = 3;
504 }
505
506 IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = new IndexedFaceSet::FaceEdgeMark[numFaces];
507
508 uint viSize = 3 * numFaces;
509 uint *VIndices = new uint[viSize];
510 uint niSize = viSize;
511 uint *NIndices = new uint[niSize];
512 uint *MIndices = new uint[viSize]; // Material Indices
513
514 LoaderState ls;
515 ls.pv = vertices;
516 ls.pn = normals;
517 ls.pm = faceEdgeMarks;
518 ls.pvi = VIndices;
519 ls.pni = NIndices;
520 ls.pmi = MIndices;
521 ls.currentIndex = 0;
522 ls.currentMIndex = 0;
523
524 FrsMaterial tmpMat;
525
526 const VArray<int> material_indices = *attributes.lookup_or_default<int>(
527 "material_index", bke::AttrDomain::Face, 0);
528 const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
529 "sharp_face", bke::AttrDomain::Face, false);
530
531 // We parse the vlak nodes again and import meshes while applying the clipping
532 // by the near and far view planes.
533 for (int a = 0; a < tottri; a++) {
534 const int3 &tri = corner_tris[a];
535 const int poly_i = tri_faces[a];
536 Material *mat = BKE_object_material_get(ob, material_indices[poly_i] + 1);
537
538 copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
539 copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
540 copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
541
542 mul_m4_v3(obmat, v1);
543 mul_m4_v3(obmat, v2);
544 mul_m4_v3(obmat, v3);
545
546 v1[2] += _z_offset;
547 v2[2] += _z_offset;
548 v3[2] += _z_offset;
549
550 if (_smooth && (!sharp_faces[poly_i])) {
551 copy_v3_v3(n1, corner_normals[tri[0]]);
552 copy_v3_v3(n2, corner_normals[tri[1]]);
553 copy_v3_v3(n3, corner_normals[tri[2]]);
554
555 mul_mat3_m4_v3(nmat, n1);
556 mul_mat3_m4_v3(nmat, n2);
557 mul_mat3_m4_v3(nmat, n3);
558
559 normalize_v3(n1);
560 normalize_v3(n2);
561 normalize_v3(n3);
562 }
563 else {
564 normal_tri_v3(facenormal, v3, v2, v1);
565
566 copy_v3_v3(n1, facenormal);
567 copy_v3_v3(n2, facenormal);
568 copy_v3_v3(n3, facenormal);
569 }
570
571 uint numTris = countClippedFaces(v1, v2, v3, clip);
572 if (numTris == 0) {
573 continue;
574 }
575
576 bool fm = ffa[poly_i];
577 bool em1 = false, em2 = false, em3 = false;
578
579 if (fed) {
580 em1 = testEdgeMark(mesh, fed, tri, 0);
581 em2 = testEdgeMark(mesh, fed, tri, 1);
582 em3 = testEdgeMark(mesh, fed, tri, 2);
583 }
584
585 if (mat) {
586 tmpMat.setLine(mat->line_col[0], mat->line_col[1], mat->line_col[2], mat->line_col[3]);
587 tmpMat.setDiffuse(mat->r, mat->g, mat->b, 1.0f);
588 tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, 1.0f);
589 tmpMat.setShininess(128.0f);
590 tmpMat.setPriority(mat->line_priority);
591 }
592
593 if (meshMaterials.empty()) {
594 meshMaterials.push_back(mat);
595 meshFrsMaterials.push_back(tmpMat);
596 shape->setFrsMaterial(tmpMat);
597 }
598 else {
599 // find if the Blender material is already in the list
600 uint i = 0;
601 bool found = false;
602
603 for (vector<Material *>::iterator it = meshMaterials.begin(), itend = meshMaterials.end();
604 it != itend;
605 it++, i++)
606 {
607 if (*it == mat) {
608 ls.currentMIndex = i;
609 found = true;
610 break;
611 }
612 }
613
614 if (!found) {
615 meshMaterials.push_back(mat);
616 meshFrsMaterials.push_back(tmpMat);
617 ls.currentMIndex = meshFrsMaterials.size() - 1;
618 }
619 }
620
621 float triCoords[5][3], triNormals[5][3];
622 bool edgeMarks[5]; // edgeMarks[i] is for the edge between i-th and (i+1)-th vertices
623
625 numTris, triCoords, v1, v2, v3, triNormals, n1, n2, n3, edgeMarks, em1, em2, em3, clip);
626 for (i = 0; i < numTris; i++) {
627 addTriangle(&ls,
628 triCoords[0],
629 triCoords[i + 1],
630 triCoords[i + 2],
631 triNormals[0],
632 triNormals[i + 1],
633 triNormals[i + 2],
634 fm,
635 (i == 0) ? edgeMarks[0] : false,
636 edgeMarks[i + 1],
637 (i == numTris - 1) ? edgeMarks[i + 2] : false);
639 }
640 }
641
642 MEM_freeN(corner_tris);
643
644 // We might have several times the same vertex. We want a clean
645 // shape with no real-vertex. Here, we are making a cleaning pass.
646 float *cleanVertices = nullptr;
647 uint cvSize;
648 uint *cleanVIndices = nullptr;
649
651 vertices, vSize, VIndices, viSize, &cleanVertices, &cvSize, &cleanVIndices);
652
653 float *cleanNormals = nullptr;
654 uint cnSize;
655 uint *cleanNIndices = nullptr;
656
658 normals, nSize, NIndices, niSize, &cleanNormals, &cnSize, &cleanNIndices);
659
660 // format materials array
661 FrsMaterial **marray = new FrsMaterial *[meshFrsMaterials.size()];
662 uint mindex = 0;
663 for (vector<FrsMaterial>::iterator m = meshFrsMaterials.begin(), mend = meshFrsMaterials.end();
664 m != mend;
665 ++m)
666 {
667 marray[mindex] = new FrsMaterial(*m);
668 ++mindex;
669 }
670
671 // deallocates memory:
672 delete[] vertices;
673 delete[] normals;
674 delete[] VIndices;
675 delete[] NIndices;
676
677 // Fix for degenerated triangles
678 // A degenerate triangle is a triangle such that
679 // 1) A and B are in the same position in the 3D space; or
680 // 2) the distance between point P and line segment AB is zero.
681 // Only those degenerate triangles in the second form are resolved here
682 // by adding a small offset to P, whereas those in the first form are
683 // addressed later in WShape::MakeFace().
684 vector<detri_t> detriList;
685 Vec3r zero(0.0, 0.0, 0.0);
686 uint vi0, vi1, vi2;
687 for (i = 0; i < viSize; i += 3) {
688 detri_t detri;
689 vi0 = cleanVIndices[i];
690 vi1 = cleanVIndices[i + 1];
691 vi2 = cleanVIndices[i + 2];
692 Vec3r v0(cleanVertices[vi0], cleanVertices[vi0 + 1], cleanVertices[vi0 + 2]);
693 Vec3r v1(cleanVertices[vi1], cleanVertices[vi1 + 1], cleanVertices[vi1 + 2]);
694 Vec3r v2(cleanVertices[vi2], cleanVertices[vi2 + 1], cleanVertices[vi2 + 2]);
695 if (v0 == v1 || v0 == v2 || v1 == v2) {
696 continue; // do nothing for now
697 }
698 if (GeomUtils::distPointSegment<Vec3r>(v0, v1, v2) < 1.0e-6) {
699 detri.viP = vi0;
700 detri.viA = vi1;
701 detri.viB = vi2;
702 }
703 else if (GeomUtils::distPointSegment<Vec3r>(v1, v0, v2) < 1.0e-6) {
704 detri.viP = vi1;
705 detri.viA = vi0;
706 detri.viB = vi2;
707 }
708 else if (GeomUtils::distPointSegment<Vec3r>(v2, v0, v1) < 1.0e-6) {
709 detri.viP = vi2;
710 detri.viA = vi0;
711 detri.viB = vi1;
712 }
713 else {
714 continue;
715 }
716
717 detri.v = zero;
718 detri.n = 0;
719 for (uint j = 0; j < viSize; j += 3) {
720 if (i == j) {
721 continue;
722 }
723 vi0 = cleanVIndices[j];
724 vi1 = cleanVIndices[j + 1];
725 vi2 = cleanVIndices[j + 2];
726 Vec3r v0(cleanVertices[vi0], cleanVertices[vi0 + 1], cleanVertices[vi0 + 2]);
727 Vec3r v1(cleanVertices[vi1], cleanVertices[vi1 + 1], cleanVertices[vi1 + 2]);
728 Vec3r v2(cleanVertices[vi2], cleanVertices[vi2 + 1], cleanVertices[vi2 + 2]);
729 if (detri.viP == vi0 && (detri.viA == vi1 || detri.viB == vi1)) {
730 detri.v += (v2 - v0);
731 detri.n++;
732 }
733 else if (detri.viP == vi0 && (detri.viA == vi2 || detri.viB == vi2)) {
734 detri.v += (v1 - v0);
735 detri.n++;
736 }
737 else if (detri.viP == vi1 && (detri.viA == vi0 || detri.viB == vi0)) {
738 detri.v += (v2 - v1);
739 detri.n++;
740 }
741 else if (detri.viP == vi1 && (detri.viA == vi2 || detri.viB == vi2)) {
742 detri.v += (v0 - v1);
743 detri.n++;
744 }
745 else if (detri.viP == vi2 && (detri.viA == vi0 || detri.viB == vi0)) {
746 detri.v += (v1 - v2);
747 detri.n++;
748 }
749 else if (detri.viP == vi2 && (detri.viA == vi1 || detri.viB == vi1)) {
750 detri.v += (v0 - v2);
751 detri.n++;
752 }
753 }
754 if (detri.n > 0) {
755 detri.v.normalizeSafe();
756 }
757 detriList.push_back(detri);
758 }
759
760 if (!detriList.empty()) {
761 vector<detri_t>::iterator v;
762 for (v = detriList.begin(); v != detriList.end(); v++) {
763 detri_t detri = (*v);
764 if (detri.n == 0) {
765 cleanVertices[detri.viP] = cleanVertices[detri.viA];
766 cleanVertices[detri.viP + 1] = cleanVertices[detri.viA + 1];
767 cleanVertices[detri.viP + 2] = cleanVertices[detri.viA + 2];
768 }
769 else if (detri.v.norm() > 0.0) {
770 cleanVertices[detri.viP] += 1.0e-5 * detri.v.x();
771 cleanVertices[detri.viP + 1] += 1.0e-5 * detri.v.y();
772 cleanVertices[detri.viP + 2] += 1.0e-5 * detri.v.z();
773 }
774 }
775 if (G.debug & G_DEBUG_FREESTYLE) {
776 printf("Warning: Object %s contains %lu degenerated triangle%s (strokes may be incorrect)\n",
777 name,
778 ulong(detriList.size()),
779 (detriList.size() > 1) ? "s" : "");
780 }
781 }
782
783 // Create the IndexedFaceSet with the retrieved attributes
784 IndexedFaceSet *rep;
785 rep = new IndexedFaceSet(cleanVertices,
786 cvSize,
787 cleanNormals,
788 cnSize,
789 marray,
790 meshFrsMaterials.size(),
791 nullptr,
792 0,
793 numFaces,
794 numVertexPerFaces,
795 faceStyle,
796 faceEdgeMarks,
797 cleanVIndices,
798 viSize,
799 cleanNIndices,
800 niSize,
801 MIndices,
802 viSize,
803 nullptr,
804 0,
805 0);
806 // sets the id of the rep
807 rep->setId(Id(id, 0));
808 rep->setName(ob->id.name + 2);
809 rep->setLibraryPath(ob->id.lib ? ob->id.lib->filepath : "");
810
811 const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(ls.minBBox[0], ls.minBBox[1], ls.minBBox[2]),
812 Vec3r(ls.maxBBox[0], ls.maxBBox[1], ls.maxBBox[2]));
813 rep->setBBox(bbox);
814 shape->AddRep(rep);
815
816 currentMesh->AddChild(shape);
817 _Scene->AddChild(currentMesh);
818}
819
820} /* namespace Freestyle */
CustomData interface, see also DNA_customdata_types.h.
@ G_DEBUG_FREESTYLE
Material * BKE_object_material_get(Object *ob, short act)
General operations, lookup, etc. for blender objects.
void BKE_object_to_mesh_clear(Object *object)
@ OB_VISIBLE_SELF
Mesh * BKE_object_to_mesh(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers)
int BKE_object_visibility(const Object *ob, int dag_eval_mode)
#define BLI_assert(a)
Definition BLI_assert.h:46
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:519
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:100
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:41
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void transpose_m4(float R[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
unsigned long ulong
unsigned int uint
#define ELEM(...)
#define NOT_CLIPPED
#define CLIPPED_BY_FAR
#define CLIPPED_BY_NEAR
eEvaluationMode
#define DEG_OBJECT_ITER_BEGIN(settings_, instance_)
#define DEG_OBJECT_ITER_END
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_VISIBLE
@ DEG_ITER_OBJECT_FLAG_DUPLI
@ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET
@ FREESTYLE_FACE_SMOOTHNESS_FLAG
@ BASE_INDIRECT_ONLY
@ BASE_HOLDOUT
@ OB_HOLDOUT
@ OB_MBALL
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
static T sum(const btAlignedObjectArray< T > &items)
static int verbose
Definition cineonlib.cc:30
BlenderFileLoader(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph)
void clipLine(float v1[3], float v2[3], float c[3], float z)
void addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3], float n1[3], float n2[3], float n3[3], bool fm, bool em1, bool em2, bool em3)
int testDegenerateTriangle(float v1[3], float v2[3], float v3[3])
void insertShapeNode(Object *ob, Mesh *mesh, int id)
void clipTriangle(int numTris, float triCoords[][3], float v1[3], float v2[3], float v3[3], float triNormals[][3], float n1[3], float n2[3], float n3[3], bool edgeMarks[5], bool em1, bool em2, bool em3, const int clip[3])
int countClippedFaces(float v1[3], float v2[3], float v3[3], int clip[3])
void setShininess(float s)
void setPriority(int priority)
void setDiffuse(float r, float g, float b, float a)
void setLine(float r, float g, float b, float a)
void setSpecular(float r, float g, float b, float a)
static void CleanIndexedVertexArray(const float *iVertices, uint iVSize, const uint *iIndices, uint iISize, float **oVertices, uint *oVSize, uint **oIndices)
static const FaceEdgeMark EDGE_MARK_V2V3
static const FaceEdgeMark EDGE_MARK_V1V2
static const FaceEdgeMark FACE_MARK
static const FaceEdgeMark EDGE_MARK_V3V1
virtual void AddChild(Node *iChild)
Definition NodeGroup.cpp:16
virtual void AddRep(Rep *iRep)
Definition NodeShape.h:39
void setFrsMaterial(const FrsMaterial &iMaterial)
Definition NodeShape.h:55
void setLibraryPath(const string &path)
Definition Rep.h:152
void setId(const Id &id)
Definition Rep.h:142
virtual void setBBox(const BBox< Vec3f > &iBox)
Definition Rep.h:137
void setName(const string &name)
Definition Rep.h:147
value_type x() const
Definition VecMat.h:489
value_type z() const
Definition VecMat.h:509
value_type y() const
Definition VecMat.h:499
Vec< T, N > & normalizeSafe()
Definition VecMat.h:111
value_type norm() const
Definition VecMat.h:92
AttributeSet attributes
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
static float normals[][3]
#define printf(...)
void RE_GetCameraModelMatrix(const Render *re, const Object *camera, float r_modelmat[4][4])
Object * RE_GetCamera(Render *re)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
real distPointSegment(const T &P, const T &A, const T &B)
Definition GeomUtils.h:32
VecMat::Vec3< real > Vec3r
Definition Geom.h:30
inherits from class Rep
Definition AppCanvas.cpp:20
static uint c
Definition RandGen.cpp:87
static bool testEdgeMark(Mesh *mesh, const blender::VArray< bool > &fed, const blender::int3 &tri, int i)
static uint a[3]
Definition RandGen.cpp:82
void corner_tris_calc(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< int3 > corner_tris)
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
const btScalar eps
Definition poly34.cpp:11
const char * name
IndexedFaceSet::FaceEdgeMark * pm
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
char filepath[1024]
Definition DNA_ID.h:552
float line_col[4]
int corners_num
int faces_num
struct FreestyleConfig freestyle_config
i
Definition text_draw.cc:230
uint len