@@ -59,6 +59,8 @@ SOFTWARE.
59
59
#include < numeric>
60
60
#include < math.h>
61
61
62
+ #include " external/xxhash.h"
63
+
62
64
#define CHECKSTAT (m ) if (!status) {status.perror (m); return status;};
63
65
64
66
#define BB_NONE 0
@@ -246,6 +248,25 @@ class BlurRelax : public MPxDeformerNode {
246
248
static MObject aTaubinBias;
247
249
static MTypeId id;
248
250
private:
251
+ // Hash checking variables
252
+ unsigned long long faceHash = 0 ;
253
+ unsigned long long edgeHash = 0 ;
254
+ unsigned long long groupHash = 0 ;
255
+ unsigned long long smoothHash = 0 ;
256
+ short bbCheck = 255 ;
257
+ short hbCheck = 255 ;
258
+ short gbCheck = 255 ;
259
+
260
+ // storage for this data doesn't change unless the hashes do
261
+ std::vector<size_t > order;
262
+ std::vector<size_t > invOrder;
263
+ std::vector<std::vector<size_t >> neighbors;
264
+ std::vector<std::vector<bool >> hardEdges;
265
+ std::vector<float_t > shiftVal; // normally 0.5; but it's 0.25 if on a hard edge
266
+ std::vector<float_t > valence; // as float for vectorizing
267
+ std::vector<bool > pinPoints;
268
+ std::vector<UINT> creaseCount;
269
+
249
270
250
271
MStatus getTrueWeights (
251
272
MObject &mesh,
@@ -262,36 +283,19 @@ class BlurRelax : public MPxDeformerNode {
262
283
short hardEdgeBehavior,
263
284
short groupEdgeBehavior,
264
285
bool reproject,
265
- std::vector<bool > &group,
266
- std::vector<size_t > &invOrder,
267
- std::vector<size_t > &order,
268
- std::vector<std::vector<size_t >> &neighbors,
269
- std::vector<std::vector<bool >> &hardEdges,
270
- std::vector<float_t > &shiftVal, // normally 0.5, but it's 0.25 if on a hard edge
271
- std::vector<float_t > &valence, // as float for vectorizing
272
- std::vector<bool > &pinPoints,
273
- std::vector<UINT> &creaseCount,
274
- float_t (*verts)[4]
286
+ std::vector<char > &group
275
287
);
276
288
277
289
void quickRelax (
278
- const MObject &mesh,
290
+ MObject &mesh,
279
291
const short borderBehavior,
280
292
const short hardEdgeBehavior,
281
293
const short groupEdgeBehavior,
282
294
const bool reproject,
283
295
const float taubinBias,
284
296
const float_t iterations,
285
297
const UINT numVerts,
286
- const std::vector<bool > &group,
287
- const std::vector<size_t > &order,
288
- const std::vector<size_t > &invOrder,
289
- const std::vector<std::vector<size_t >> &neighbors,
290
- const std::vector<std::vector<bool >> &hardEdges,
291
- const std::vector<float_t > &shiftVal, // normally 0.5, but it's 0.25 if on a hard edge
292
- const std::vector<float_t > &valence, // as float for vectorizing
293
- const std::vector<bool > &pinPoints,
294
- const std::vector<UINT> &creaseCount,
298
+ const std::vector<char > &group,
295
299
float_t (*verts)[4] // already resized
296
300
);
297
301
};
@@ -492,44 +496,78 @@ MStatus BlurRelax::deform(MDataBlock& dataBlock, MItGeometry& vertIter, const MM
492
496
MDataHandle hInput = dataBlock.inputValue (inPlug);
493
497
MObject mesh = hInput.asMesh ();
494
498
495
- // Initialize the variables
496
- std::vector<bool > group;
497
- std::vector<size_t > order;
498
- std::vector<size_t > invOrder;
499
- std::vector<std::vector<size_t >> neighbors;
500
- std::vector<std::vector<bool >> hardEdges;
501
- std::vector<float_t > shiftVal; // normally 0.5; but it's 0.25 if on a hard edge
502
- std::vector<float_t > valence; // as float for vectorizing
503
- std::vector<bool > pinPoints;
504
- std::vector<UINT> creaseCount;
505
-
506
499
// Get the point values
507
500
MFnMesh meshFn (mesh);
508
- pointArray_t mpa;
509
- meshFn.getPoints (mpa);
510
501
UINT numVerts = meshFn.numVertices ();
511
502
512
- // Build and fill the raw float data buffers
513
- float_t (*verts)[4 ] = new float_t [numVerts][4 ];
514
- mpa.get (verts);
515
-
516
- // Populate the variables with *SPECIALLY ORDERED* data
517
- // all vertex data is now shuffled by the order vector
518
- buildQuickData (mesh, vertIter, bb, hb, gb, reproject,
519
- group, order, invOrder, neighbors, hardEdges, shiftVal, valence,
520
- pinPoints, creaseCount, verts);
503
+ // Get the group data
504
+ std::vector<char > group;
505
+ group.resize (numVerts);
506
+ for (; !vertIter.isDone (); vertIter.next ()) {
507
+ group[vertIter.index ()] = true ;
508
+ }
509
+ vertIter.reset ();
510
+
511
+ // Get the true smooth-edge data
512
+ std::vector<char > trueSmoothEdges;
513
+ trueSmoothEdges.resize (meshFn.numEdges ());
514
+ MItMeshEdge edgeIter (mesh);
515
+ for (; !edgeIter.isDone (); edgeIter.next ()) {
516
+ if (edgeIter.isSmooth ()) {
517
+ trueSmoothEdges[edgeIter.index ()] = true ;
518
+ }
519
+ }
520
+ edgeIter.reset ();
521
+
522
+ // Hash the topology to see if we need to re-build the data
523
+ // I could be smarter about this and only recompute things when needed
524
+ // however, those re-computations wouldn't save frames when it mattered
525
+ MIntArray mfaceCounts, mvertIdxs;
526
+ int *faceCounts, *vertIdxs;
527
+ meshFn.getVertices (mfaceCounts, mvertIdxs);
528
+ faceCounts = new int [mfaceCounts.length ()];
529
+ vertIdxs = new int [mvertIdxs.length ()];
530
+ unsigned long long tFaceHash = XXH64 (faceCounts, mfaceCounts.length ()*sizeof (int ), 0 );
531
+ unsigned long long tEdgeHash = XXH64 (vertIdxs, mvertIdxs.length ()*sizeof (int ), 0 );
532
+ unsigned long long tGroupHash = XXH64 (group.data (), group.size ()*sizeof (char ), 0 );
533
+ unsigned long long tSmoothHash = XXH64 (trueSmoothEdges.data (), trueSmoothEdges.size ()*sizeof (char ), 0 );
534
+ delete[] faceCounts;
535
+ delete[] vertIdxs;
536
+
537
+ if (
538
+ (bbCheck != bb) || (hbCheck != hb) || (gbCheck != gb) ||
539
+ (tFaceHash != faceHash) || (tEdgeHash != edgeHash) ||
540
+ (tGroupHash != groupHash) || (tSmoothHash != smoothHash)
541
+ ) {
542
+ bbCheck = bb; hbCheck = hb; gbCheck = gb;
543
+ faceHash = tFaceHash; edgeHash = tEdgeHash;
544
+ groupHash = tGroupHash; smoothHash = tSmoothHash;
545
+
546
+ // Populate the variables with *SPECIALLY ORDERED* data
547
+ // all vertex data is now shuffled by the order vector
548
+ buildQuickData (mesh, vertIter, bb, hb, gb, reproject, group);
549
+ }
521
550
522
551
// This can happen if the user is pinning all the points
523
552
// or all the edges are hard (like when you import an obj)
524
553
if (neighbors.empty ()) {
525
- delete [] verts;
526
554
return status;
527
555
}
556
+
557
+ // Build the raw float data buffers
558
+ pointArray_t mpa;
559
+ float_t (*reoVerts)[4 ] = new float_t [numVerts][4 ];
560
+ meshFn.getPoints (mpa);
561
+
562
+ for (size_t i = 0 ; i < numVerts; ++i) {
563
+ reoVerts[i][0 ] = mpa[order[i]].x ;
564
+ reoVerts[i][1 ] = mpa[order[i]].y ;
565
+ reoVerts[i][2 ] = mpa[order[i]].z ;
566
+ reoVerts[i][3 ] = mpa[order[i]].w ;
567
+ }
528
568
529
569
// Calculate the relax, and store in verts
530
- quickRelax (mesh, bb, hb, gb, reproject, tBias,
531
- iterations, numVerts, group, order, invOrder, neighbors, hardEdges, shiftVal,
532
- valence, pinPoints, creaseCount, verts);
570
+ quickRelax (mesh, bb, hb, gb, reproject, tBias, iterations, numVerts, group, reoVerts);
533
571
534
572
// Get the painted weight values
535
573
std::vector<float > weightVals;
@@ -538,11 +576,11 @@ MStatus BlurRelax::deform(MDataBlock& dataBlock, MItGeometry& vertIter, const MM
538
576
// Finally set the output
539
577
for (; !vertIter.isDone (); vertIter.next ()) {
540
578
const UINT idx = vertIter.index ();
541
- vertIter.setPosition ((weightVals[idx]) * point_t (verts [invOrder[idx]]) + (1.0 - weightVals[idx]) * vertIter.position ());
579
+ vertIter.setPosition ((weightVals[idx]) * point_t (reoVerts [invOrder[idx]]) + (1.0 - weightVals[idx]) * vertIter.position ());
542
580
}
543
581
544
582
// Make sure to clean up after myself
545
- delete [] verts ;
583
+ delete [] reoVerts ;
546
584
}
547
585
return status;
548
586
}
@@ -569,52 +607,30 @@ void BlurRelax::buildQuickData(
569
607
short hardEdgeBehavior,
570
608
short groupEdgeBehavior,
571
609
bool reproject,
572
- std::vector<bool > &group,
573
- std::vector<size_t > &order,
574
- std::vector<size_t > &invOrder,
575
- std::vector<std::vector<size_t >> &neighbors,
576
- std::vector<std::vector<bool >> &hardEdges,
577
- std::vector<float_t > &shiftVal, // normally 0.5, but it's 0.25 if on a hard edge
578
- std::vector<float_t > &valence, // as float for vectorizing
579
- std::vector<bool > &pinPoints,
580
- std::vector<UINT> &creaseCount,
581
- float_t (*verts)[4] // already resized
610
+ std::vector<char > &group
582
611
) {
583
612
// This takes the mesh, Gets all the required data, reorders so
584
613
// the verts are in descending order of valence, and gets the subgroup
585
614
// I'm trying to pre-process everything I can right here so I don't have to
586
615
// branch in quickLaplacianSmooth() so auto-vectorization works
587
-
588
616
MFnMesh meshFn (mesh);
589
617
UINT numVertices = meshFn.numVertices ();
590
- float_t (*rawVerts)[4 ] = new float_t [numVertices][4 ];
591
- memcpy (&(rawVerts[0 ][0 ]), &(verts[0 ][0 ]), 4 * numVertices * sizeof (float_t ));
592
618
593
- std::vector<bool > rawPinPoints;
619
+ std::vector<char > rawPinPoints;
594
620
std::vector<UINT> rawCreaseCount;
595
621
rawCreaseCount.resize (numVertices);
596
622
rawPinPoints.resize (numVertices);
597
623
598
624
std::vector<UINT> groupBorders;
599
- std::vector<bool > isGroupBorder;
625
+ std::vector<char > isGroupBorder;
600
626
isGroupBorder.resize (numVertices);
601
627
602
628
std::vector<std::vector<UINT>> rawNeighbors;
603
- std::vector<std::vector<bool >> rawHardEdges;
604
- std::vector<std::vector<bool >> rawPinBorders;
629
+ std::vector<std::vector<char >> rawHardEdges;
630
+ std::vector<std::vector<char >> rawPinBorders;
605
631
rawHardEdges.resize (numVertices);
606
632
rawNeighbors.resize (numVertices);
607
633
608
- // for (auto &rh : rawHardEdges) { rh.reserve(4); }
609
- // for (auto &rn : rawNeighbors) { rn.reserve(4); }
610
-
611
- // Get the group data
612
- group.resize (numVertices);
613
- for (; !vertIter.isDone (); vertIter.next ()) {
614
- group[vertIter.index ()] = true ;
615
- }
616
- vertIter.reset ();
617
-
618
634
// Get the connectivity data
619
635
// The big trick is that all pinning happens once, right here
620
636
// If a vertex has no neighbors, then it is never smoothed
@@ -700,7 +716,7 @@ void BlurRelax::buildQuickData(
700
716
rawPinPoints[i] = true ;
701
717
702
718
std::vector<UINT> newNeigh;
703
- std::vector<bool > newHard;
719
+ std::vector<char > newHard;
704
720
if (!rawPinPoints[i]) {
705
721
for (size_t j = 0 ; j < rawNeighbors[i].size (); ++j) {
706
722
if (rawHardEdges[i][j]) {
@@ -724,7 +740,9 @@ void BlurRelax::buildQuickData(
724
740
725
741
// Build the "transposed" neighbor and hard edge values
726
742
size_t maxValence = rawNeighbors[order[0 ]].size ();
743
+ neighbors.clear ();
727
744
neighbors.resize (maxValence);
745
+ hardEdges.clear ();
728
746
hardEdges.resize (maxValence);
729
747
creaseCount.resize (numVertices);
730
748
pinPoints.resize (numVertices);
@@ -733,20 +751,19 @@ void BlurRelax::buildQuickData(
733
751
shiftVal.resize (numVertices*4 );
734
752
735
753
invOrder.resize (order.size ());
754
+
736
755
for (size_t i = 0 ; i < order.size (); ++i) {
737
756
invOrder[order[i]] = i;
738
757
}
739
758
740
759
for (size_t i = 0 ; i < numVertices; ++i) {
741
- const std::vector<UINT> &neigh = rawNeighbors[order[i]];
742
- const std::vector< bool > &hards = rawHardEdges[order[i]];
760
+ const auto &neigh = rawNeighbors[order[i]];
761
+ const auto &hards = rawHardEdges[order[i]];
743
762
size_t vale = neigh.size ();
744
763
for (size_t n = 0 ; n < vale; ++n) {
745
764
neighbors[n].push_back (invOrder[neigh[n]]);
746
765
hardEdges[n].push_back (invOrder[hards[n]]);
747
766
}
748
- for (size_t x = 0 ; x < 3 ; ++x)
749
- verts[i][x] = rawVerts[order[i]][x];
750
767
creaseCount[i] = rawCreaseCount[order[i]];
751
768
pinPoints[i] = rawPinPoints[order[i]];
752
769
@@ -757,27 +774,18 @@ void BlurRelax::buildQuickData(
757
774
shiftVal[4 * i + xx] = rawShiftVal[order[i]];
758
775
}
759
776
}
760
- delete [] rawVerts;
761
777
}
762
778
763
779
void BlurRelax::quickRelax (
764
- const MObject &mesh,
780
+ MObject &mesh,
765
781
const short borderBehavior,
766
782
const short hardEdgeBehavior,
767
783
const short groupEdgeBehavior,
768
784
const bool reproject,
769
785
const float taubinBias,
770
786
const float_t iterations,
771
787
const UINT numVerts,
772
- const std::vector<bool > &group,
773
- const std::vector<size_t > &order,
774
- const std::vector<size_t > &invOrder,
775
- const std::vector<std::vector<size_t >> &neighbors,
776
- const std::vector<std::vector<bool >> &hardEdges,
777
- const std::vector<float_t > &shiftVal, // normally 0.5, but it's 0.25 if on a hard edge
778
- const std::vector<float_t > &valence, // as float for vectorizing
779
- const std::vector<bool > &pinPoints,
780
- const std::vector<UINT> &creaseCount,
788
+ const std::vector<char > &group,
781
789
float_t (*verts)[4]
782
790
) {
783
791
bool rpEdges = (borderBehavior == BB_SLIDE) || (hardEdgeBehavior == HB_SLIDE) || (groupEdgeBehavior == GB_SLIDE);
@@ -806,9 +814,9 @@ void BlurRelax::quickRelax(
806
814
size_t nonzeroValence = neighbors[0 ].size ();
807
815
808
816
MStatus status;
809
- MFnMesh meshFn (mesh);
810
817
MMeshIntersector octree;
811
818
MObject smoothMeshPar, smoothMesh;
819
+ MFnMesh meshFn (mesh);
812
820
if (reproject) {
813
821
MFnMeshData smoothMeshParFn;
814
822
MMeshSmoothOptions smoothOpt;
0 commit comments