stripifier.java
来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 1,365 行 · 第 1/3 页
JAVA
1,365 行
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme.util.geom.nvtristrip;
import java.util.HashSet;
import java.util.logging.Logger;
/**
*
*/
class Stripifier {
private static final Logger logger = Logger.getLogger(Stripifier.class
.getName());
public static int CACHE_INEFFICIENCY = 6;
IntVec indices = new IntVec();
int cacheSize;
int minStripLength;
float meshJump;
boolean bFirstTimeResetPoint;
Stripifier() {
super();
}
///////////////////////////////////////////////////////////////////////////////////////////
// FindEdgeInfo()
//
// find the edge info for these two indices
//
static EdgeInfo findEdgeInfo(EdgeInfoVec edgeInfos, int v0, int v1) {
// we can get to it through either array
// because the edge infos have a v0 and v1
// and there is no order except how it was
// first created.
EdgeInfo infoIter = edgeInfos.at(v0);
while (infoIter != null) {
if (infoIter.m_v0 == v0) {
if (infoIter.m_v1 == v1)
return infoIter;
infoIter = infoIter.m_nextV0;
} else {
if (infoIter.m_v0 == v1)
return infoIter;
infoIter = infoIter.m_nextV1;
}
}
return null;
}
///////////////////////////////////////////////////////////////////////////////////////////
// FindOtherFace
//
// find the other face sharing these vertices
// exactly like the edge info above
//
static FaceInfo findOtherFace(EdgeInfoVec edgeInfos, int v0, int v1,
FaceInfo faceInfo) {
EdgeInfo edgeInfo = findEdgeInfo(edgeInfos, v0, v1);
if ((edgeInfo == null) || (v0 == v1)) {
//we've hit a degenerate
return null;
}
return (edgeInfo.m_face0 == faceInfo ? edgeInfo.m_face1
: edgeInfo.m_face0);
}
static boolean alreadyExists(FaceInfo faceInfo, FaceInfoVec faceInfos) {
for (int i = 0; i < faceInfos.size(); ++i) {
FaceInfo o = faceInfos.at(i);
if ((o.m_v0 == faceInfo.m_v0) && (o.m_v1 == faceInfo.m_v1)
&& (o.m_v2 == faceInfo.m_v2))
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////
// BuildStripifyInfo()
//
// Builds the list of all face and edge infos
//
void buildStripifyInfo(FaceInfoVec faceInfos, EdgeInfoVec edgeInfos,
int maxIndex) {
// reserve space for the face infos, but do not resize them.
int numIndices = indices.size();
faceInfos.reserve(numIndices / 3);
// we actually resize the edge infos, so we must initialize to null
for (int i = 0; i < maxIndex + 1; i++)
edgeInfos.add(null);
// iterate through the triangles of the triangle list
int numTriangles = numIndices / 3;
int index = 0;
boolean[] bFaceUpdated = new boolean[3];
for (int i = 0; i < numTriangles; i++) {
boolean bMightAlreadyExist = true;
bFaceUpdated[0] = false;
bFaceUpdated[1] = false;
bFaceUpdated[2] = false;
// grab the indices
int v0 = indices.get(index++);
int v1 = indices.get(index++);
int v2 = indices.get(index++);
//we disregard degenerates
if (isDegenerate(v0, v1, v2))
continue;
// create the face info and add it to the list of faces, but only
// if this exact face doesn't already
// exist in the list
FaceInfo faceInfo = new FaceInfo(v0, v1, v2);
// grab the edge infos, creating them if they do not already exist
EdgeInfo edgeInfo01 = findEdgeInfo(edgeInfos, v0, v1);
if (edgeInfo01 == null) {
//since one of it's edges isn't in the edge data structure, it
// can't already exist in the face structure
bMightAlreadyExist = false;
// create the info
edgeInfo01 = new EdgeInfo(v0, v1);
// update the linked list on both
edgeInfo01.m_nextV0 = edgeInfos.at(v0);
edgeInfo01.m_nextV1 = edgeInfos.at(v1);
edgeInfos.set(v0, edgeInfo01);
edgeInfos.set(v1, edgeInfo01);
// set face 0
edgeInfo01.m_face0 = faceInfo;
} else {
if (edgeInfo01.m_face1 != null) {
logger.info("BuildStripifyInfo: > 2 triangles on an edge"
+ v0 + "," + v1 + "... uncertain consequences\n");
} else {
edgeInfo01.m_face1 = faceInfo;
bFaceUpdated[0] = true;
}
}
// grab the edge infos, creating them if they do not already exist
EdgeInfo edgeInfo12 = findEdgeInfo(edgeInfos, v1, v2);
if (edgeInfo12 == null) {
bMightAlreadyExist = false;
// create the info
edgeInfo12 = new EdgeInfo(v1, v2);
// update the linked list on both
edgeInfo12.m_nextV0 = edgeInfos.at(v1);
edgeInfo12.m_nextV1 = edgeInfos.at(v2);
edgeInfos.set(v1, edgeInfo12);
edgeInfos.set(v2, edgeInfo12);
// set face 0
edgeInfo12.m_face0 = faceInfo;
} else {
if (edgeInfo12.m_face1 != null) {
logger.info("BuildStripifyInfo: > 2 triangles on an edge"
+ v1
+ ","
+ v2
+ "... uncertain consequences\n");
} else {
edgeInfo12.m_face1 = faceInfo;
bFaceUpdated[1] = true;
}
}
// grab the edge infos, creating them if they do not already exist
EdgeInfo edgeInfo20 = findEdgeInfo(edgeInfos, v2, v0);
if (edgeInfo20 == null) {
bMightAlreadyExist = false;
// create the info
edgeInfo20 = new EdgeInfo(v2, v0);
// update the linked list on both
edgeInfo20.m_nextV0 = edgeInfos.at(v2);
edgeInfo20.m_nextV1 = edgeInfos.at(v0);
edgeInfos.set(v2, edgeInfo20);
edgeInfos.set(v0, edgeInfo20);
// set face 0
edgeInfo20.m_face0 = faceInfo;
} else {
if (edgeInfo20.m_face1 != null) {
logger.info("BuildStripifyInfo: > 2 triangles on an edge"
+ v2
+ ","
+ v0
+ "... uncertain consequences\n");
} else {
edgeInfo20.m_face1 = faceInfo;
bFaceUpdated[2] = true;
}
}
if (bMightAlreadyExist) {
if (!alreadyExists(faceInfo, faceInfos))
faceInfos.add(faceInfo);
else {
//cleanup pointers that point to this deleted face
if (bFaceUpdated[0])
edgeInfo01.m_face1 = null;
if (bFaceUpdated[1])
edgeInfo12.m_face1 = null;
if (bFaceUpdated[2])
edgeInfo20.m_face1 = null;
}
} else {
faceInfos.add(faceInfo);
}
}
}
static boolean isDegenerate(FaceInfo face) {
if (face.m_v0 == face.m_v1)
return true;
else if (face.m_v0 == face.m_v2)
return true;
else if (face.m_v1 == face.m_v2)
return true;
else
return false;
}
static boolean isDegenerate(int v0, int v1, int v2) {
if (v0 == v1)
return true;
else if (v0 == v2)
return true;
else if (v1 == v2)
return true;
else
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////
// GetNextIndex()
//
// Returns vertex of the input face which is "next" in the input index list
//
static int getNextIndex(IntVec indices, FaceInfo face) {
int numIndices = indices.size();
int v0 = indices.get(numIndices - 2);
int v1 = indices.get(numIndices - 1);
int fv0 = face.m_v0;
int fv1 = face.m_v1;
int fv2 = face.m_v2;
if (fv0 != v0 && fv0 != v1) {
if ((fv1 != v0 && fv1 != v1) || (fv2 != v0 && fv2 != v1)) {
logger.info("GetNextIndex: Triangle doesn't have all of its vertices\n");
logger.info("GetNextIndex: Duplicate triangle probably got us derailed\n");
}
return fv0;
}
if (fv1 != v0 && fv1 != v1) {
if ((fv0 != v0 && fv0 != v1) || (fv2 != v0 && fv2 != v1)) {
logger.info("GetNextIndex: Triangle doesn't have all of its vertices\n");
logger.info("GetNextIndex: Duplicate triangle probably got us derailed\n");
}
return fv1;
}
if (fv2 != v0 && fv2 != v1) {
if ((fv0 != v0 && fv0 != v1) || (fv1 != v0 && fv1 != v1)) {
logger.info("GetNextIndex: Triangle doesn't have all of its vertices\n");
logger.info("GetNextIndex: Duplicate triangle probably got us derailed\n");
}
return fv2;
}
// shouldn't get here, but let's try and fail gracefully
if ((fv0 == fv1) || (fv0 == fv2))
return fv0;
else if ((fv1 == fv0) || (fv1 == fv2))
return fv1;
else if ((fv2 == fv0) || (fv2 == fv1))
return fv2;
else
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////
// FindStartPoint()
//
// Finds a good starting point, namely one which has only one neighbor
//
static int findStartPoint(FaceInfoVec faceInfos, EdgeInfoVec edgeInfos) {
int bestCtr = -1;
int bestIndex = -1;
for (int i = 0; i < faceInfos.size(); i++) {
int ctr = 0;
if (findOtherFace(edgeInfos, faceInfos.at(i).m_v0,
faceInfos.at(i).m_v1, faceInfos.at(i)) == null)
ctr++;
if (findOtherFace(edgeInfos, faceInfos.at(i).m_v1,
faceInfos.at(i).m_v2, faceInfos.at(i)) == null)
ctr++;
if (findOtherFace(edgeInfos, faceInfos.at(i).m_v2,
faceInfos.at(i).m_v0, faceInfos.at(i)) == null)
ctr++;
if (ctr > bestCtr) {
bestCtr = ctr;
bestIndex = i;
//return i;
}
}
//return -1;
if (bestCtr == 0)
return -1;
return bestIndex;
}
///////////////////////////////////////////////////////////////////////////////////////////
// FindGoodResetPoint()
//
// A good reset point is one near other commited areas so that
// we know that when we've made the longest strips its because
// we're stripifying in the same general orientation.
//
FaceInfo findGoodResetPoint(FaceInfoVec faceInfos, EdgeInfoVec edgeInfos) {
// we hop into different areas of the mesh to try to get
// other large open spans done. Areas of small strips can
// just be left to triangle lists added at the end.
FaceInfo result = null;
if (result == null) {
int numFaces = faceInfos.size();
int startPoint;
if (bFirstTimeResetPoint) {
//first time, find a face with few neighbors (look for an edge
// of the mesh)
startPoint = findStartPoint(faceInfos, edgeInfos);
bFirstTimeResetPoint = false;
} else
startPoint = (int) (((float) numFaces - 1) * meshJump);
if (startPoint == -1) {
startPoint = (int) (((float) numFaces - 1) * meshJump);
//meshJump += 0.1f;
//if (meshJump > 1.0f)
// meshJump = .05f;
}
int i = startPoint;
do {
// if this guy isn't visited, try him
if (faceInfos.at(i).m_stripId < 0) {
result = faceInfos.at(i);
break;
}
// update the index and clamp to 0-(numFaces-1)
if (++i >= numFaces)
i = 0;
} while (i != startPoint);
// update the meshJump
meshJump += 0.1f;
if (meshJump > 1.0f)
meshJump = .05f;
}
// return the best face we found
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////
// GetUniqueVertexInB()
//
// Returns the vertex unique to faceB
//
static int getUniqueVertexInB(FaceInfo faceA, FaceInfo faceB) {
int facev0 = faceB.m_v0;
if (facev0 != faceA.m_v0 && facev0 != faceA.m_v1
&& facev0 != faceA.m_v2)
return facev0;
int facev1 = faceB.m_v1;
if (facev1 != faceA.m_v0 && facev1 != faceA.m_v1
&& facev1 != faceA.m_v2)
return facev1;
int facev2 = faceB.m_v2;
if (facev2 != faceA.m_v0 && facev2 != faceA.m_v1
&& facev2 != faceA.m_v2)
return facev2;
// nothing is different
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////
// GetSharedVertices()
//
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?