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