Skip to content

Commit 880658c

Browse files
authored
Merge pull request #7 from tbttfox/xxhashCheck
Store the processed connectivity rather than re-compute each time
2 parents c7892be + f69524c commit 880658c

File tree

4 files changed

+1459
-92
lines changed

4 files changed

+1459
-92
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/Maya${MAYA_VERSIO
99

1010
set(SOURCE_FILES
1111
"blurRelax.cpp"
12+
"external/xxhash.h"
13+
"external/xxhash.c"
1214
)
1315

1416
include_directories(${MAYA_INCLUDE_DIR})

blurRelax.cpp

Lines changed: 100 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ SOFTWARE.
5959
#include <numeric>
6060
#include <math.h>
6161

62+
#include "external/xxhash.h"
63+
6264
#define CHECKSTAT(m) if (!status) {status.perror(m); return status;};
6365

6466
#define BB_NONE 0
@@ -246,6 +248,25 @@ class BlurRelax : public MPxDeformerNode {
246248
static MObject aTaubinBias;
247249
static MTypeId id;
248250
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+
249270

250271
MStatus getTrueWeights(
251272
MObject &mesh,
@@ -262,36 +283,19 @@ class BlurRelax : public MPxDeformerNode {
262283
short hardEdgeBehavior,
263284
short groupEdgeBehavior,
264285
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
275287
);
276288

277289
void quickRelax(
278-
const MObject &mesh,
290+
MObject &mesh,
279291
const short borderBehavior,
280292
const short hardEdgeBehavior,
281293
const short groupEdgeBehavior,
282294
const bool reproject,
283295
const float taubinBias,
284296
const float_t iterations,
285297
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,
295299
float_t(*verts)[4] // already resized
296300
);
297301
};
@@ -492,44 +496,78 @@ MStatus BlurRelax::deform(MDataBlock& dataBlock, MItGeometry& vertIter, const MM
492496
MDataHandle hInput = dataBlock.inputValue(inPlug);
493497
MObject mesh = hInput.asMesh();
494498

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-
506499
// Get the point values
507500
MFnMesh meshFn(mesh);
508-
pointArray_t mpa;
509-
meshFn.getPoints(mpa);
510501
UINT numVerts = meshFn.numVertices();
511502

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+
}
521550

522551
// This can happen if the user is pinning all the points
523552
// or all the edges are hard (like when you import an obj)
524553
if (neighbors.empty()) {
525-
delete [] verts;
526554
return status;
527555
}
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+
}
528568

529569
// 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);
533571

534572
// Get the painted weight values
535573
std::vector<float> weightVals;
@@ -538,11 +576,11 @@ MStatus BlurRelax::deform(MDataBlock& dataBlock, MItGeometry& vertIter, const MM
538576
// Finally set the output
539577
for (; !vertIter.isDone(); vertIter.next()) {
540578
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());
542580
}
543581

544582
// Make sure to clean up after myself
545-
delete [] verts;
583+
delete [] reoVerts;
546584
}
547585
return status;
548586
}
@@ -569,52 +607,30 @@ void BlurRelax::buildQuickData(
569607
short hardEdgeBehavior,
570608
short groupEdgeBehavior,
571609
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
582611
) {
583612
// This takes the mesh, Gets all the required data, reorders so
584613
// the verts are in descending order of valence, and gets the subgroup
585614
// I'm trying to pre-process everything I can right here so I don't have to
586615
// branch in quickLaplacianSmooth() so auto-vectorization works
587-
588616
MFnMesh meshFn(mesh);
589617
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));
592618

593-
std::vector<bool> rawPinPoints;
619+
std::vector<char> rawPinPoints;
594620
std::vector<UINT> rawCreaseCount;
595621
rawCreaseCount.resize(numVertices);
596622
rawPinPoints.resize(numVertices);
597623

598624
std::vector<UINT> groupBorders;
599-
std::vector<bool> isGroupBorder;
625+
std::vector<char> isGroupBorder;
600626
isGroupBorder.resize(numVertices);
601627

602628
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;
605631
rawHardEdges.resize(numVertices);
606632
rawNeighbors.resize(numVertices);
607633

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-
618634
// Get the connectivity data
619635
// The big trick is that all pinning happens once, right here
620636
// If a vertex has no neighbors, then it is never smoothed
@@ -700,7 +716,7 @@ void BlurRelax::buildQuickData(
700716
rawPinPoints[i] = true;
701717

702718
std::vector<UINT> newNeigh;
703-
std::vector<bool> newHard;
719+
std::vector<char> newHard;
704720
if (!rawPinPoints[i]) {
705721
for (size_t j = 0; j < rawNeighbors[i].size(); ++j) {
706722
if (rawHardEdges[i][j]) {
@@ -724,7 +740,9 @@ void BlurRelax::buildQuickData(
724740

725741
// Build the "transposed" neighbor and hard edge values
726742
size_t maxValence = rawNeighbors[order[0]].size();
743+
neighbors.clear();
727744
neighbors.resize(maxValence);
745+
hardEdges.clear();
728746
hardEdges.resize(maxValence);
729747
creaseCount.resize(numVertices);
730748
pinPoints.resize(numVertices);
@@ -733,20 +751,19 @@ void BlurRelax::buildQuickData(
733751
shiftVal.resize(numVertices*4);
734752

735753
invOrder.resize(order.size());
754+
736755
for (size_t i = 0; i < order.size(); ++i) {
737756
invOrder[order[i]] = i;
738757
}
739758

740759
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]];
743762
size_t vale = neigh.size();
744763
for (size_t n = 0; n < vale; ++n) {
745764
neighbors[n].push_back(invOrder[neigh[n]]);
746765
hardEdges[n].push_back(invOrder[hards[n]]);
747766
}
748-
for (size_t x = 0; x < 3; ++x)
749-
verts[i][x] = rawVerts[order[i]][x];
750767
creaseCount[i] = rawCreaseCount[order[i]];
751768
pinPoints[i] = rawPinPoints[order[i]];
752769

@@ -757,27 +774,18 @@ void BlurRelax::buildQuickData(
757774
shiftVal[4 * i + xx] = rawShiftVal[order[i]];
758775
}
759776
}
760-
delete [] rawVerts;
761777
}
762778

763779
void BlurRelax::quickRelax(
764-
const MObject &mesh,
780+
MObject &mesh,
765781
const short borderBehavior,
766782
const short hardEdgeBehavior,
767783
const short groupEdgeBehavior,
768784
const bool reproject,
769785
const float taubinBias,
770786
const float_t iterations,
771787
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,
781789
float_t(*verts)[4]
782790
) {
783791
bool rpEdges = (borderBehavior == BB_SLIDE) || (hardEdgeBehavior == HB_SLIDE) || (groupEdgeBehavior == GB_SLIDE);
@@ -806,9 +814,9 @@ void BlurRelax::quickRelax(
806814
size_t nonzeroValence = neighbors[0].size();
807815

808816
MStatus status;
809-
MFnMesh meshFn(mesh);
810817
MMeshIntersector octree;
811818
MObject smoothMeshPar, smoothMesh;
819+
MFnMesh meshFn(mesh);
812820
if (reproject) {
813821
MFnMeshData smoothMeshParFn;
814822
MMeshSmoothOptions smoothOpt;

0 commit comments

Comments
 (0)