Blender V4.3
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
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;
66 }
67 else {
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;
78 deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
81 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
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 metaballs 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, const FreestyleEdge *fed, const blender::int3 &tri, int i)
398{
399 const Span<blender::int2> edges = mesh->edges();
400 const Span<int> corner_verts = mesh->corner_verts();
401 const Span<int> corner_edges = mesh->corner_edges();
402
403 const int corner = tri[i];
404 const int corner_next = tri[(i + 1) % 3];
405 const blender::int2 &edge = edges[corner_edges[corner]];
406
407 if (!ELEM(corner_verts[corner_next], edge[0], edge[1])) {
408 /* Not an edge in the original mesh before triangulation. */
409 return false;
410 }
411
412 return (fed[corner_edges[corner]].flag & FREESTYLE_EDGE_MARK) != 0;
413}
414
416{
417 using namespace blender;
418 char *name = ob->id.name + 2;
419
420 const Span<float3> vert_positions = mesh->vert_positions();
421 const OffsetIndices mesh_polys = mesh->faces();
422 const Span<int> corner_verts = mesh->corner_verts();
423
424 // Compute loop triangles
425 int tottri = poly_to_tri_count(mesh->faces_num, mesh->corners_num);
427 tottri, sizeof(*corner_tris), __func__);
429 vert_positions, mesh_polys, corner_verts, {corner_tris, tottri});
430 const blender::Span<int> tri_faces = mesh->corner_tri_faces();
431 const blender::Span<blender::float3> corner_normals = mesh->corner_normals();
432
433 // Get other mesh data
434 const FreestyleEdge *fed = (const FreestyleEdge *)CustomData_get_layer(&mesh->edge_data,
436 const FreestyleFace *ffa = (const FreestyleFace *)CustomData_get_layer(&mesh->face_data,
438
439 // Compute view matrix
441 float viewinv[4][4], viewmat[4][4];
442 RE_GetCameraModelMatrix(_re, ob_camera_eval, viewinv);
443 invert_m4_m4(viewmat, viewinv);
444
445 // Compute matrix including camera transform
446 float obmat[4][4], nmat[4][4];
447 mul_m4_m4m4(obmat, viewmat, ob->object_to_world().ptr());
448 invert_m4_m4(nmat, obmat);
449 transpose_m4(nmat);
450
451 // We count the number of triangles after the clipping by the near and far view
452 // planes is applied (NOTE: mesh vertices are in the camera coordinate system).
453 uint numFaces = 0;
454 float v1[3], v2[3], v3[3];
455 float n1[3], n2[3], n3[3], facenormal[3];
456 int clip[3];
457 for (int a = 0; a < tottri; a++) {
458 const int3 &tri = corner_tris[a];
459
460 copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
461 copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
462 copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
463
464 mul_m4_v3(obmat, v1);
465 mul_m4_v3(obmat, v2);
466 mul_m4_v3(obmat, v3);
467
468 v1[2] += _z_offset;
469 v2[2] += _z_offset;
470 v3[2] += _z_offset;
471
472 numFaces += countClippedFaces(v1, v2, v3, clip);
473 }
474#if 0
475 if (G.debug & G_DEBUG_FREESTYLE) {
476 cout << "numFaces " << numFaces << endl;
477 }
478#endif
479 if (numFaces == 0) {
480 MEM_freeN(corner_tris);
481 return;
482 }
483
484 // We allocate memory for the meshes to be imported
485 NodeGroup *currentMesh = new NodeGroup;
486 NodeShape *shape = new NodeShape;
487
488 uint vSize = 3 * 3 * numFaces;
489 float *vertices = new float[vSize];
490 uint nSize = vSize;
491 float *normals = new float[nSize];
492 uint *numVertexPerFaces = new uint[numFaces];
493 vector<Material *> meshMaterials;
494 vector<FrsMaterial> meshFrsMaterials;
495
497 uint i;
498 for (i = 0; i < numFaces; i++) {
499 faceStyle[i] = IndexedFaceSet::TRIANGLES;
500 numVertexPerFaces[i] = 3;
501 }
502
503 IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = new IndexedFaceSet::FaceEdgeMark[numFaces];
504
505 uint viSize = 3 * numFaces;
506 uint *VIndices = new uint[viSize];
507 uint niSize = viSize;
508 uint *NIndices = new uint[niSize];
509 uint *MIndices = new uint[viSize]; // Material Indices
510
511 LoaderState ls;
512 ls.pv = vertices;
513 ls.pn = normals;
514 ls.pm = faceEdgeMarks;
515 ls.pvi = VIndices;
516 ls.pni = NIndices;
517 ls.pmi = MIndices;
518 ls.currentIndex = 0;
519 ls.currentMIndex = 0;
520
521 FrsMaterial tmpMat;
522
523 const bke::AttributeAccessor attributes = mesh->attributes();
524 const VArray<int> material_indices = *attributes.lookup_or_default<int>(
525 "material_index", bke::AttrDomain::Face, 0);
526 const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
527 "sharp_face", bke::AttrDomain::Face, false);
528
529 // We parse the vlak nodes again and import meshes while applying the clipping
530 // by the near and far view planes.
531 for (int a = 0; a < tottri; a++) {
532 const int3 &tri = corner_tris[a];
533 const int poly_i = tri_faces[a];
534 Material *mat = BKE_object_material_get(ob, material_indices[poly_i] + 1);
535
536 copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
537 copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
538 copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
539
540 mul_m4_v3(obmat, v1);
541 mul_m4_v3(obmat, v2);
542 mul_m4_v3(obmat, v3);
543
544 v1[2] += _z_offset;
545 v2[2] += _z_offset;
546 v3[2] += _z_offset;
547
548 if (_smooth && (!sharp_faces[poly_i])) {
549 copy_v3_v3(n1, corner_normals[tri[0]]);
550 copy_v3_v3(n2, corner_normals[tri[1]]);
551 copy_v3_v3(n3, corner_normals[tri[2]]);
552
553 mul_mat3_m4_v3(nmat, n1);
554 mul_mat3_m4_v3(nmat, n2);
555 mul_mat3_m4_v3(nmat, n3);
556
557 normalize_v3(n1);
558 normalize_v3(n2);
559 normalize_v3(n3);
560 }
561 else {
562 normal_tri_v3(facenormal, v3, v2, v1);
563
564 copy_v3_v3(n1, facenormal);
565 copy_v3_v3(n2, facenormal);
566 copy_v3_v3(n3, facenormal);
567 }
568
569 uint numTris = countClippedFaces(v1, v2, v3, clip);
570 if (numTris == 0) {
571 continue;
572 }
573
574 bool fm = (ffa) ? (ffa[poly_i].flag & FREESTYLE_FACE_MARK) != 0 : false;
575 bool em1 = false, em2 = false, em3 = false;
576
577 if (fed) {
578 em1 = testEdgeMark(mesh, fed, tri, 0);
579 em2 = testEdgeMark(mesh, fed, tri, 1);
580 em3 = testEdgeMark(mesh, fed, tri, 2);
581 }
582
583 if (mat) {
584 tmpMat.setLine(mat->line_col[0], mat->line_col[1], mat->line_col[2], mat->line_col[3]);
585 tmpMat.setDiffuse(mat->r, mat->g, mat->b, 1.0f);
586 tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, 1.0f);
587 tmpMat.setShininess(128.0f);
588 tmpMat.setPriority(mat->line_priority);
589 }
590
591 if (meshMaterials.empty()) {
592 meshMaterials.push_back(mat);
593 meshFrsMaterials.push_back(tmpMat);
594 shape->setFrsMaterial(tmpMat);
595 }
596 else {
597 // find if the Blender material is already in the list
598 uint i = 0;
599 bool found = false;
600
601 for (vector<Material *>::iterator it = meshMaterials.begin(), itend = meshMaterials.end();
602 it != itend;
603 it++, i++)
604 {
605 if (*it == mat) {
606 ls.currentMIndex = i;
607 found = true;
608 break;
609 }
610 }
611
612 if (!found) {
613 meshMaterials.push_back(mat);
614 meshFrsMaterials.push_back(tmpMat);
615 ls.currentMIndex = meshFrsMaterials.size() - 1;
616 }
617 }
618
619 float triCoords[5][3], triNormals[5][3];
620 bool edgeMarks[5]; // edgeMarks[i] is for the edge between i-th and (i+1)-th vertices
621
623 numTris, triCoords, v1, v2, v3, triNormals, n1, n2, n3, edgeMarks, em1, em2, em3, clip);
624 for (i = 0; i < numTris; i++) {
625 addTriangle(&ls,
626 triCoords[0],
627 triCoords[i + 1],
628 triCoords[i + 2],
629 triNormals[0],
630 triNormals[i + 1],
631 triNormals[i + 2],
632 fm,
633 (i == 0) ? edgeMarks[0] : false,
634 edgeMarks[i + 1],
635 (i == numTris - 1) ? edgeMarks[i + 2] : false);
637 }
638 }
639
640 MEM_freeN(corner_tris);
641
642 // We might have several times the same vertex. We want a clean
643 // shape with no real-vertex. Here, we are making a cleaning pass.
644 float *cleanVertices = nullptr;
645 uint cvSize;
646 uint *cleanVIndices = nullptr;
647
649 vertices, vSize, VIndices, viSize, &cleanVertices, &cvSize, &cleanVIndices);
650
651 float *cleanNormals = nullptr;
652 uint cnSize;
653 uint *cleanNIndices = nullptr;
654
656 normals, nSize, NIndices, niSize, &cleanNormals, &cnSize, &cleanNIndices);
657
658 // format materials array
659 FrsMaterial **marray = new FrsMaterial *[meshFrsMaterials.size()];
660 uint mindex = 0;
661 for (vector<FrsMaterial>::iterator m = meshFrsMaterials.begin(), mend = meshFrsMaterials.end();
662 m != mend;
663 ++m)
664 {
665 marray[mindex] = new FrsMaterial(*m);
666 ++mindex;
667 }
668
669 // deallocates memory:
670 delete[] vertices;
671 delete[] normals;
672 delete[] VIndices;
673 delete[] NIndices;
674
675 // Fix for degenerated triangles
676 // A degenerate triangle is a triangle such that
677 // 1) A and B are in the same position in the 3D space; or
678 // 2) the distance between point P and line segment AB is zero.
679 // Only those degenerate triangles in the second form are resolved here
680 // by adding a small offset to P, whereas those in the first form are
681 // addressed later in WShape::MakeFace().
682 vector<detri_t> detriList;
683 Vec3r zero(0.0, 0.0, 0.0);
684 uint vi0, vi1, vi2;
685 for (i = 0; i < viSize; i += 3) {
686 detri_t detri;
687 vi0 = cleanVIndices[i];
688 vi1 = cleanVIndices[i + 1];
689 vi2 = cleanVIndices[i + 2];
690 Vec3r v0(cleanVertices[vi0], cleanVertices[vi0 + 1], cleanVertices[vi0 + 2]);
691 Vec3r v1(cleanVertices[vi1], cleanVertices[vi1 + 1], cleanVertices[vi1 + 2]);
692 Vec3r v2(cleanVertices[vi2], cleanVertices[vi2 + 1], cleanVertices[vi2 + 2]);
693 if (v0 == v1 || v0 == v2 || v1 == v2) {
694 continue; // do nothing for now
695 }
696 if (GeomUtils::distPointSegment<Vec3r>(v0, v1, v2) < 1.0e-6) {
697 detri.viP = vi0;
698 detri.viA = vi1;
699 detri.viB = vi2;
700 }
701 else if (GeomUtils::distPointSegment<Vec3r>(v1, v0, v2) < 1.0e-6) {
702 detri.viP = vi1;
703 detri.viA = vi0;
704 detri.viB = vi2;
705 }
706 else if (GeomUtils::distPointSegment<Vec3r>(v2, v0, v1) < 1.0e-6) {
707 detri.viP = vi2;
708 detri.viA = vi0;
709 detri.viB = vi1;
710 }
711 else {
712 continue;
713 }
714
715 detri.v = zero;
716 detri.n = 0;
717 for (uint j = 0; j < viSize; j += 3) {
718 if (i == j) {
719 continue;
720 }
721 vi0 = cleanVIndices[j];
722 vi1 = cleanVIndices[j + 1];
723 vi2 = cleanVIndices[j + 2];
724 Vec3r v0(cleanVertices[vi0], cleanVertices[vi0 + 1], cleanVertices[vi0 + 2]);
725 Vec3r v1(cleanVertices[vi1], cleanVertices[vi1 + 1], cleanVertices[vi1 + 2]);
726 Vec3r v2(cleanVertices[vi2], cleanVertices[vi2 + 1], cleanVertices[vi2 + 2]);
727 if (detri.viP == vi0 && (detri.viA == vi1 || detri.viB == vi1)) {
728 detri.v += (v2 - v0);
729 detri.n++;
730 }
731 else if (detri.viP == vi0 && (detri.viA == vi2 || detri.viB == vi2)) {
732 detri.v += (v1 - v0);
733 detri.n++;
734 }
735 else if (detri.viP == vi1 && (detri.viA == vi0 || detri.viB == vi0)) {
736 detri.v += (v2 - v1);
737 detri.n++;
738 }
739 else if (detri.viP == vi1 && (detri.viA == vi2 || detri.viB == vi2)) {
740 detri.v += (v0 - v1);
741 detri.n++;
742 }
743 else if (detri.viP == vi2 && (detri.viA == vi0 || detri.viB == vi0)) {
744 detri.v += (v1 - v2);
745 detri.n++;
746 }
747 else if (detri.viP == vi2 && (detri.viA == vi1 || detri.viB == vi1)) {
748 detri.v += (v0 - v2);
749 detri.n++;
750 }
751 }
752 if (detri.n > 0) {
753 detri.v.normalizeSafe();
754 }
755 detriList.push_back(detri);
756 }
757
758 if (!detriList.empty()) {
759 vector<detri_t>::iterator v;
760 for (v = detriList.begin(); v != detriList.end(); v++) {
761 detri_t detri = (*v);
762 if (detri.n == 0) {
763 cleanVertices[detri.viP] = cleanVertices[detri.viA];
764 cleanVertices[detri.viP + 1] = cleanVertices[detri.viA + 1];
765 cleanVertices[detri.viP + 2] = cleanVertices[detri.viA + 2];
766 }
767 else if (detri.v.norm() > 0.0) {
768 cleanVertices[detri.viP] += 1.0e-5 * detri.v.x();
769 cleanVertices[detri.viP + 1] += 1.0e-5 * detri.v.y();
770 cleanVertices[detri.viP + 2] += 1.0e-5 * detri.v.z();
771 }
772 }
773 if (G.debug & G_DEBUG_FREESTYLE) {
774 printf("Warning: Object %s contains %lu degenerated triangle%s (strokes may be incorrect)\n",
775 name,
776 ulong(detriList.size()),
777 (detriList.size() > 1) ? "s" : "");
778 }
779 }
780
781 // Create the IndexedFaceSet with the retrieved attributes
782 IndexedFaceSet *rep;
783 rep = new IndexedFaceSet(cleanVertices,
784 cvSize,
785 cleanNormals,
786 cnSize,
787 marray,
788 meshFrsMaterials.size(),
789 nullptr,
790 0,
791 numFaces,
792 numVertexPerFaces,
793 faceStyle,
794 faceEdgeMarks,
795 cleanVIndices,
796 viSize,
797 cleanNIndices,
798 niSize,
799 MIndices,
800 viSize,
801 nullptr,
802 0,
803 0);
804 // sets the id of the rep
805 rep->setId(Id(id, 0));
806 rep->setName(ob->id.name + 2);
807 rep->setLibraryPath(ob->id.lib ? ob->id.lib->filepath : "");
808
809 const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(ls.minBBox[0], ls.minBBox[1], ls.minBBox[2]),
810 Vec3r(ls.maxBBox[0], ls.maxBBox[1], ls.maxBBox[2]));
811 rep->setBBox(bbox);
812 shape->AddRep(rep);
813
814 currentMesh->AddChild(shape);
815 _Scene->AddChild(currentMesh);
816}
817
818} /* namespace Freestyle */
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
@ G_DEBUG_FREESTYLE
struct Material * BKE_object_material_get(struct 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:50
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:517
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:98
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:39
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)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_VISIBLE
@ DEG_ITER_OBJECT_FLAG_DUPLI
@ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET
@ CD_FREESTYLE_EDGE
@ CD_FREESTYLE_FACE
@ FREESTYLE_FACE_SMOOTHNESS_FLAG
@ BASE_INDIRECT_ONLY
@ BASE_HOLDOUT
@ FREESTYLE_FACE_MARK
@ FREESTYLE_EDGE_MARK
@ OB_HOLDOUT
@ OB_MBALL
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
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:31
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
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:493
value_type z() const
Definition VecMat.h:513
value_type y() const
Definition VecMat.h:503
Vec< T, N > & normalizeSafe()
Definition VecMat.h:113
value_type norm() const
Definition VecMat.h:94
#define printf
const Depsgraph * depsgraph
int len
static float normals[][3]
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:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#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 FreestyleEdge *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)
const btScalar eps
Definition poly34.cpp:11
IndexedFaceSet::FaceEdgeMark * pm
struct Library * lib
Definition DNA_ID.h:419
char name[66]
Definition DNA_ID.h:425
char filepath[1024]
Definition DNA_ID.h:531
float line_col[4]
float clip_start
float clip_end
struct FreestyleConfig freestyle_config
uint8_t flag
Definition wm_window.cc:138