stripifier.java
来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 1,365 行 · 第 1/3 页
JAVA
1,365 行
// Does the stripification, puts output strips into vector allStrips
//
// Works by setting runnning a number of experiments in different areas of
// the mesh, and
// accepting the one which results in the longest strips. It then accepts
// this, and moves
// on to a different area of the mesh. We try to jump around the mesh some,
// to ensure that
// large open spans of strips get generated.
//
void findAllStrips(StripInfoVec allStrips, FaceInfoVec allFaceInfos,
EdgeInfoVec allEdgeInfos, int numSamples) {
// the experiments
int experimentId = 0;
int stripId = 0;
boolean done = false;
int loopCtr = 0;
while (!done) {
loopCtr++;
//
// PHASE 1: Set up numSamples * numEdges experiments
//
StripInfoVec[] experiments = new StripInfoVec[numSamples * 6];
for (int i = 0; i < experiments.length; i++)
experiments[i] = new StripInfoVec();
int experimentIndex = 0;
HashSet<FaceInfo> resetPoints = new HashSet<FaceInfo>(); /* NvFaceInfo */
for (int i = 0; i < numSamples; i++) {
// Try to find another good reset point.
// If there are none to be found, we are done
FaceInfo nextFace = findGoodResetPoint(allFaceInfos,
allEdgeInfos);
if (nextFace == null) {
done = true;
break;
}
// If we have already evaluated starting at this face in this
// slew of experiments, then skip going any further
else if (resetPoints.contains(nextFace)) {
continue;
}
// trying it now...
resetPoints.add(nextFace);
// otherwise, we shall now try experiments for starting on the
// 01,12, and 20 edges
// build the strip off of this face's 0-1 edge
EdgeInfo edge01 = findEdgeInfo(allEdgeInfos, nextFace.m_v0,
nextFace.m_v1);
StripInfo strip01 = new StripInfo(new StripStartInfo(nextFace,
edge01, true), stripId++, experimentId++);
experiments[experimentIndex++].add(strip01);
// build the strip off of this face's 1-0 edge
EdgeInfo edge10 = findEdgeInfo(allEdgeInfos, nextFace.m_v0,
nextFace.m_v1);
StripInfo strip10 = new StripInfo(new StripStartInfo(nextFace,
edge10, false), stripId++, experimentId++);
experiments[experimentIndex++].add(strip10);
// build the strip off of this face's 1-2 edge
EdgeInfo edge12 = findEdgeInfo(allEdgeInfos, nextFace.m_v1,
nextFace.m_v2);
StripInfo strip12 = new StripInfo(new StripStartInfo(nextFace,
edge12, true), stripId++, experimentId++);
experiments[experimentIndex++].add(strip12);
// build the strip off of this face's 2-1 edge
EdgeInfo edge21 = findEdgeInfo(allEdgeInfos, nextFace.m_v1,
nextFace.m_v2);
StripInfo strip21 = new StripInfo(new StripStartInfo(nextFace,
edge21, false), stripId++, experimentId++);
experiments[experimentIndex++].add(strip21);
// build the strip off of this face's 2-0 edge
EdgeInfo edge20 = findEdgeInfo(allEdgeInfos, nextFace.m_v2,
nextFace.m_v0);
StripInfo strip20 = new StripInfo(new StripStartInfo(nextFace,
edge20, true), stripId++, experimentId++);
experiments[experimentIndex++].add(strip20);
// build the strip off of this face's 0-2 edge
EdgeInfo edge02 = findEdgeInfo(allEdgeInfos, nextFace.m_v2,
nextFace.m_v0);
StripInfo strip02 = new StripInfo(new StripStartInfo(nextFace,
edge02, false), stripId++, experimentId++);
experiments[experimentIndex++].add(strip02);
}
//
// PHASE 2: Iterate through that we setup in the last phase
// and really build each of the strips and strips that follow to
// see how
// far we get
//
int numExperiments = experimentIndex;
for (int i = 0; i < numExperiments; i++) {
// get the strip set
// build the first strip of the list
experiments[i].at(0).build(allEdgeInfos, allFaceInfos);
int experimentId2 = experiments[i].at(0).m_experimentId;
StripInfo stripIter = experiments[i].at(0);
StripStartInfo startInfo = new StripStartInfo(null, null, false);
while (findTraversal(allFaceInfos, allEdgeInfos, stripIter,
startInfo)) {
// create the new strip info
//TODO startInfo clone ?
stripIter = new StripInfo(startInfo, stripId++,
experimentId2);
// build the next strip
stripIter.build(allEdgeInfos, allFaceInfos);
// add it to the list
experiments[i].add(stripIter);
}
}
//
// Phase 3: Find the experiment that has the most promise
//
int bestIndex = 0;
double bestValue = 0;
for (int i = 0; i < numExperiments; i++) {
float avgStripSizeWeight = 1.0f;
//float numTrisWeight = 0.0f;
float numStripsWeight = 0.0f;
float avgStripSize = avgStripSize(experiments[i]);
float numStrips = experiments[i].size();
float value = avgStripSize * avgStripSizeWeight
+ (numStrips * numStripsWeight);
//float value = 1.f / numStrips;
//float value = numStrips * avgStripSize;
if (value > bestValue) {
bestValue = value;
bestIndex = i;
}
}
//
// Phase 4: commit the best experiment of the bunch
//
commitStrips(allStrips, experiments[bestIndex]);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// SplitUpStripsAndOptimize()
//
// Splits the input vector of strips (allBigStrips) into smaller, cache
// friendly pieces, then
// reorders these pieces to maximize cache hits
// The final strips are output through outStrips
//
void splitUpStripsAndOptimize(StripInfoVec allStrips,
StripInfoVec outStrips, EdgeInfoVec edgeInfos,
FaceInfoVec outFaceList) {
int threshold = cacheSize;
StripInfoVec tempStrips = new StripInfoVec();
int j;
//split up strips into threshold-sized pieces
for (int i = 0; i < allStrips.size(); i++) {
StripInfo currentStrip;
StripStartInfo startInfo = new StripStartInfo(null, null, false);
int actualStripSize = 0;
for (j = 0; j < allStrips.at(i).m_faces.size(); ++j) {
if (!isDegenerate(allStrips.at(i).m_faces.at(j)))
actualStripSize++;
}
if (actualStripSize /* allStrips.at(i).m_faces.size() */
> threshold) {
int numTimes = actualStripSize /* allStrips.at(i).m_faces.size() */
/ threshold;
int numLeftover = actualStripSize /* allStrips.at(i).m_faces.size() */
% threshold;
int degenerateCount = 0;
for (j = 0; j < numTimes; j++) {
currentStrip = new StripInfo(startInfo, 0, -1);
int faceCtr = j * threshold + degenerateCount;
boolean bFirstTime = true;
while (faceCtr < threshold + (j * threshold)
+ degenerateCount) {
if (isDegenerate(allStrips.at(i).m_faces.at(faceCtr))) {
degenerateCount++;
//last time or first time through, no need for a
// degenerate
if ((((faceCtr + 1) != threshold + (j * threshold)
+ degenerateCount) || ((j == numTimes - 1)
&& (numLeftover < 4) && (numLeftover > 0)))
&& !bFirstTime) {
currentStrip.m_faces
.add(allStrips.at(i).m_faces
.at(faceCtr++));
} else
++faceCtr;
} else {
currentStrip.m_faces.add(allStrips.at(i).m_faces
.at(faceCtr++));
bFirstTime = false;
}
}
/*
* threshold; faceCtr < threshold+(j*threshold); faceCtr++) {
* currentStrip.m_faces.add(allStrips.at(i).m_faces.at(faceCtr]); }
*/
///*
if (j == numTimes - 1) //last time through
{
if ((numLeftover < 4) && (numLeftover > 0)) //way too
// small
{
//just add to last strip
int ctr = 0;
while (ctr < numLeftover) {
if (!isDegenerate(allStrips.at(i).m_faces
.at(faceCtr))) {
currentStrip.m_faces
.add(allStrips.at(i).m_faces
.at(faceCtr++));
++ctr;
} else {
currentStrip.m_faces
.add(allStrips.at(i).m_faces
.at(faceCtr++));
++degenerateCount;
}
}
numLeftover = 0;
}
}
//*/
tempStrips.add(currentStrip);
}
int leftOff = j * threshold + degenerateCount;
if (numLeftover != 0) {
currentStrip = new StripInfo(startInfo, 0, -1);
int ctr = 0;
boolean bFirstTime = true;
while (ctr < numLeftover) {
if (!isDegenerate(allStrips.at(i).m_faces.at(leftOff))) {
ctr++;
bFirstTime = false;
currentStrip.m_faces.add(allStrips.at(i).m_faces
.at(leftOff++));
} else if (!bFirstTime)
currentStrip.m_faces.add(allStrips.at(i).m_faces
.at(leftOff++));
else
leftOff++;
}
/*
* for(int k = 0; k < numLeftover; k++) {
* currentStrip.m_faces.add(allStrips.at(i).m_faces[leftOff++]); }
*/
tempStrips.add(currentStrip);
}
} else {
//we're not just doing a tempStrips.add(allBigStrips[i])
// because
// this way we can delete allBigStrips later to free the memory
currentStrip = new StripInfo(startInfo, 0, -1);
for (j = 0; j < allStrips.at(i).m_faces.size(); j++)
currentStrip.m_faces.add(allStrips.at(i).m_faces.at(j));
tempStrips.add(currentStrip);
}
}
//add small strips to face list
StripInfoVec tempStrips2 = new StripInfoVec();
removeSmallStrips(tempStrips, tempStrips2, outFaceList);
outStrips.clear();
//screw optimization for now
// for(i = 0; i < tempStrips.size(); ++i)
// outStrips.add(tempStrips[i]);
if (tempStrips2.size() != 0) {
//Optimize for the vertex cache
VertexCache vcache = new VertexCache(cacheSize);
float bestNumHits = -1.0f;
float numHits;
int bestIndex = -99999;
int firstIndex = 0;
float minCost = 10000.0f;
for (int i = 0; i < tempStrips2.size(); i++) {
int numNeighbors = 0;
//find strip with least number of neighbors per face
for (j = 0; j < tempStrips2.at(i).m_faces.size(); j++) {
numNeighbors += numNeighbors(tempStrips2.at(i).m_faces
.at(j), edgeInfos);
}
float currCost = (float) numNeighbors
/ (float) tempStrips2.at(i).m_faces.size();
if (currCost < minCost) {
minCost = currCost;
firstIndex = i;
}
}
updateCacheStrip(vcache, tempStrips2.at(firstIndex));
outStrips.add(tempStrips2.at(firstIndex));
tempStrips2.at(firstIndex).visited = true;
boolean bWantsCW = (tempStrips2.at(firstIndex).m_faces.size() % 2) == 0;
//this n^2 algo is what slows down stripification so much....
// needs to be improved
while (true) {
bestNumHits = -1.0f;
//find best strip to add next, given the current cache
for (int i = 0; i < tempStrips2.size(); i++) {
if (tempStrips2.at(i).visited)
continue;
numHits = calcNumHitsStrip(vcache, tempStrips2.at(i));
if (numHits > bestNumHits) {
bestNumHits = numHits;
bestIndex = i;
} else if (numHits >= bestNumHits) {
//check previous strip to see if this one requires it
// to switch polarity
StripInfo strip = tempStrips2.at(i);
int nStripFaceCount = strip.m_faces.size();
FaceInfo tFirstFace = new FaceInfo(
strip.m_faces.at(0).m_v0,
strip.m_faces.at(0).m_v1,
strip.m_faces.at(0).m_v2);
// If there is a second face, reorder vertices such
// that the
// unique vertex is first
if (nStripFaceCount > 1) {
int nUnique = getUniqueVertexInB(strip.m_faces
.at(1), tFirstFace);
if (nUnique == tFirstFace.m_v1) {
int tmp = tFirstFace.m_v0;
tFirstFace.m_v0 = tFirstFace.m_v1;
tFirstFace.m_v1 = tmp;
} else if (nUnique == tFirstFace.m_v2) {
int tmp = tFirstFace.m_v0;
tFirstFace.m_v0 = tFirstFace.m_v2;
tFirstFace.m_v2 = tmp;
}
// If there is a third face, reorder vertices such
// that the
// shared vertex is last
if (nStripFaceCount > 2) {
int[] nShared = new int[2];
getSharedVertices(strip.m_faces.at(2),
tFirstFace, nShared);
if ((nShared[0] == tFirstFace.m_v1)
&& (nShared[1] == -1)) {
int tmp = tFirstFace.m_v2;
tFirstFace.m_v2 = tFirstFace.m_v1;
tFirstFace.m_v1 = tmp;
}
}
}
// Check CW/CCW ordering
if (bWantsCW == isCW(strip.m_faces.at(0),
tFirstFace.m_v0, tFirstFace.m_v1)) {
//I like this one!
bestIndex = i;
}
}
}
if (bestNumHits == -1.0f)
break;
tempStrips2.at(bestIndex).visited = true;
updateCacheStrip(vcache, tempStrips2.at(bestIndex));
outStrips.add(tempStrips2.at(bestIndex));
bWantsCW = (tempStrips2.at(bestIndex).m_faces.size() % 2 == 0) ? bWantsCW
: !bWantsCW;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Stripify()
//
//
// in_indices are the input indices of the mesh to stripify
// in_cacheSize is the target cache size
//
void stripify(IntVec in_indices, int in_cacheSize, int in_minStripLength,
int maxIndex, StripInfoVec outStrips, FaceInfoVec outFaceList) {
meshJump = 0.0f;
bFirstTimeResetPoint = true; //used in FindGoodResetPoint()
//the number of times to run the experiments
int numSamples = 10;
//the cache size, clamped to one
cacheSize = Math.max(1, in_cacheSize - CACHE_INEFFICIENCY);
minStripLength = in_minStripLength;
//this is the strip size threshold below which we dump the strip into
// a list
indices = in_indices;
// build the stripification info
FaceInfoVec allFaceInfos = new FaceInfoVec();
EdgeInfoVec allEdgeInfos = new EdgeInfoVec();
buildStripifyInfo(allFaceInfos, allEdgeInfos, maxIndex);
StripInfoVec allStrips = new StripInfoVec();
// stripify
findAllStrips(allStrips, allFaceInfos, allEdgeInfos, numSamples);
//split up the strips into cache friendly pieces, optimize them, then
// dump these into outStrips
splitUpStripsAndOptimize(allStrips, outStrips, allEdgeInfos,
outFaceList);
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?