use of com.jme3.math.Triangle in project jmonkeyengine by jMonkeyEngine.
the class MikktspaceTangentGenerator method generateTSpaces.
static boolean generateTSpaces(TSpace[] psTspace, final TriInfo[] pTriInfos, final Group[] pGroups, final int iNrActiveGroups, final int[] piTriListIn, final float fThresCos, final MikkTSpaceContext mikkTSpace) {
TSpace[] pSubGroupTspace;
SubGroup[] pUniSubGroups;
int[] pTmpMembers;
int iMaxNrFaces = 0, iUniqueTspaces = 0, g = 0, i = 0;
for (g = 0; g < iNrActiveGroups; g++) {
if (iMaxNrFaces < pGroups[g].nrFaces) {
iMaxNrFaces = pGroups[g].nrFaces;
}
}
if (iMaxNrFaces == 0) {
return true;
}
// make initial allocations
pSubGroupTspace = new TSpace[iMaxNrFaces];
pUniSubGroups = new SubGroup[iMaxNrFaces];
pTmpMembers = new int[iMaxNrFaces];
iUniqueTspaces = 0;
for (g = 0; g < iNrActiveGroups; g++) {
final Group pGroup = pGroups[g];
int iUniqueSubGroups = 0, s = 0;
for (// triangles
i = 0; // triangles
i < pGroup.nrFaces; // triangles
i++) {
// triangle number
final int f = pGroup.faceIndices.get(i);
int index = -1, iVertIndex = -1, iOF_1 = -1, iMembers = 0, j = 0, l = 0;
SubGroup tmp_group = new SubGroup();
boolean bFound;
Vector3f n, vOs, vOt;
if (pTriInfos[f].assignedGroup[0] == pGroup) {
index = 0;
} else if (pTriInfos[f].assignedGroup[1] == pGroup) {
index = 1;
} else if (pTriInfos[f].assignedGroup[2] == pGroup) {
index = 2;
}
assert (index >= 0 && index < 3);
iVertIndex = piTriListIn[f * 3 + index];
assert (iVertIndex == pGroup.vertexRepresentitive);
// is normalized already
n = getNormal(mikkTSpace, iVertIndex);
// project
vOs = pTriInfos[f].os.subtract(n.mult(n.dot(pTriInfos[f].os)));
vOt = pTriInfos[f].ot.subtract(n.mult(n.dot(pTriInfos[f].ot)));
vOs.normalizeLocal();
vOt.normalizeLocal();
// original face number
iOF_1 = pTriInfos[f].orgFaceNumber;
iMembers = 0;
for (j = 0; j < pGroup.nrFaces; j++) {
// triangle number
final int t = pGroup.faceIndices.get(j);
final int iOF_2 = pTriInfos[t].orgFaceNumber;
// project
Vector3f vOs2 = pTriInfos[t].os.subtract(n.mult(n.dot(pTriInfos[t].os)));
Vector3f vOt2 = pTriInfos[t].ot.subtract(n.mult(n.dot(pTriInfos[t].ot)));
vOs2.normalizeLocal();
vOt2.normalizeLocal();
{
final boolean bAny = ((pTriInfos[f].flag | pTriInfos[t].flag) & GROUP_WITH_ANY) != 0;
// make sure triangles which belong to the same quad are joined.
final boolean bSameOrgFace = iOF_1 == iOF_2;
final float fCosS = vOs.dot(vOs2);
final float fCosT = vOt.dot(vOt2);
// sanity check
assert (f != t || bSameOrgFace);
if (bAny || bSameOrgFace || (fCosS > fThresCos && fCosT > fThresCos)) {
pTmpMembers[iMembers++] = t;
}
}
}
// sort pTmpMembers
tmp_group.nrFaces = iMembers;
tmp_group.triMembers = pTmpMembers;
if (iMembers > 1) {
quickSort(pTmpMembers, 0, iMembers - 1, INTERNAL_RND_SORT_SEED);
}
// look for an existing match
bFound = false;
l = 0;
while (l < iUniqueSubGroups && !bFound) {
bFound = compareSubGroups(tmp_group, pUniSubGroups[l]);
if (!bFound) {
++l;
}
}
// assign tangent space index
assert (bFound || l == iUniqueSubGroups);
// if no match was found we allocate a new subgroup
if (!bFound) {
// insert new subgroup
int[] pIndices = new int[iMembers];
pUniSubGroups[iUniqueSubGroups] = new SubGroup();
pUniSubGroups[iUniqueSubGroups].nrFaces = iMembers;
pUniSubGroups[iUniqueSubGroups].triMembers = pIndices;
System.arraycopy(tmp_group.triMembers, 0, pIndices, 0, iMembers);
//memcpy(pIndices, tmp_group.pTriMembers, iMembers*sizeof(int));
pSubGroupTspace[iUniqueSubGroups] = evalTspace(tmp_group.triMembers, iMembers, piTriListIn, pTriInfos, mikkTSpace, pGroup.vertexRepresentitive);
++iUniqueSubGroups;
}
// output tspace
{
final int iOffs = pTriInfos[f].tSpacesOffs;
final int iVert = pTriInfos[f].vertNum[index];
TSpace pTS_out = psTspace[iOffs + iVert];
assert (pTS_out.counter < 2);
assert (((pTriInfos[f].flag & ORIENT_PRESERVING) != 0) == pGroup.orientPreservering);
if (pTS_out.counter == 1) {
pTS_out.set(avgTSpace(pTS_out, pSubGroupTspace[l]));
// update counter
pTS_out.counter = 2;
pTS_out.orient = pGroup.orientPreservering;
} else {
assert (pTS_out.counter == 0);
pTS_out.set(pSubGroupTspace[l]);
// update counter
pTS_out.counter = 1;
pTS_out.orient = pGroup.orientPreservering;
}
}
}
iUniqueTspaces += iUniqueSubGroups;
}
return true;
}
use of com.jme3.math.Triangle in project jmonkeyengine by jMonkeyEngine.
the class MikktspaceTangentGenerator method initTriInfo.
static void initTriInfo(TriInfo[] pTriInfos, final int[] piTriListIn, final MikkTSpaceContext mikkTSpace, final int iNrTrianglesIn) {
// generate neighbor info list
for (int f = 0; f < iNrTrianglesIn; f++) {
for (int i = 0; i < 3; i++) {
pTriInfos[f].faceNeighbors[i] = -1;
pTriInfos[f].assignedGroup[i] = null;
pTriInfos[f].os.x = 0.0f;
pTriInfos[f].os.y = 0.0f;
pTriInfos[f].os.z = 0.0f;
pTriInfos[f].ot.x = 0.0f;
pTriInfos[f].ot.y = 0.0f;
pTriInfos[f].ot.z = 0.0f;
pTriInfos[f].magS = 0;
pTriInfos[f].magT = 0;
// assumed bad
pTriInfos[f].flag |= GROUP_WITH_ANY;
}
}
// evaluate first order derivatives
for (int f = 0; f < iNrTrianglesIn; f++) {
// initial values
final Vector3f v1 = getPosition(mikkTSpace, piTriListIn[f * 3 + 0]);
final Vector3f v2 = getPosition(mikkTSpace, piTriListIn[f * 3 + 1]);
final Vector3f v3 = getPosition(mikkTSpace, piTriListIn[f * 3 + 2]);
final Vector3f t1 = getTexCoord(mikkTSpace, piTriListIn[f * 3 + 0]);
final Vector3f t2 = getTexCoord(mikkTSpace, piTriListIn[f * 3 + 1]);
final Vector3f t3 = getTexCoord(mikkTSpace, piTriListIn[f * 3 + 2]);
final float t21x = t2.x - t1.x;
final float t21y = t2.y - t1.y;
final float t31x = t3.x - t1.x;
final float t31y = t3.y - t1.y;
final Vector3f d1 = v2.subtract(v1);
final Vector3f d2 = v3.subtract(v1);
final float fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
//assert(fSignedAreaSTx2!=0);
// eq 18
Vector3f vOs = d1.mult(t31y).subtract(d2.mult(t21y));
// eq 19
Vector3f vOt = d1.mult(-t31x).add(d2.mult(t21x));
pTriInfos[f].flag |= (fSignedAreaSTx2 > 0 ? ORIENT_PRESERVING : 0);
if (isNotZero(fSignedAreaSTx2)) {
final float fAbsArea = Math.abs(fSignedAreaSTx2);
final float fLenOs = vOs.length();
final float fLenOt = vOt.length();
final float fS = (pTriInfos[f].flag & ORIENT_PRESERVING) == 0 ? (-1.0f) : 1.0f;
if (isNotZero(fLenOs)) {
pTriInfos[f].os = vOs.multLocal(fS / fLenOs);
}
if (isNotZero(fLenOt)) {
pTriInfos[f].ot = vOt.multLocal(fS / fLenOt);
}
// evaluate magnitudes prior to normalization of vOs and vOt
pTriInfos[f].magS = fLenOs / fAbsArea;
pTriInfos[f].magT = fLenOt / fAbsArea;
// if this is a good triangle
if (isNotZero(pTriInfos[f].magS) && isNotZero(pTriInfos[f].magT)) {
pTriInfos[f].flag &= (~GROUP_WITH_ANY);
}
}
}
// force otherwise healthy quads to a fixed orientation
int t = 0;
while (t < (iNrTrianglesIn - 1)) {
final int iFO_a = pTriInfos[t].orgFaceNumber;
final int iFO_b = pTriInfos[t + 1].orgFaceNumber;
if (iFO_a == iFO_b) {
// this is a quad
final boolean bIsDeg_a = (pTriInfos[t].flag & MARK_DEGENERATE) != 0;
final boolean bIsDeg_b = (pTriInfos[t + 1].flag & MARK_DEGENERATE) != 0;
// DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false
if ((bIsDeg_a || bIsDeg_b) == false) {
final boolean bOrientA = (pTriInfos[t].flag & ORIENT_PRESERVING) != 0;
final boolean bOrientB = (pTriInfos[t + 1].flag & ORIENT_PRESERVING) != 0;
// if this happens the quad has extremely bad mapping!!
if (bOrientA != bOrientB) {
//printf("found quad with bad mapping\n");
boolean bChooseOrientFirstTri = false;
if ((pTriInfos[t + 1].flag & GROUP_WITH_ANY) != 0) {
bChooseOrientFirstTri = true;
} else if (calcTexArea(mikkTSpace, Arrays.copyOfRange(piTriListIn, t * 3 + 0, t * 3 + 3)) >= calcTexArea(mikkTSpace, Arrays.copyOfRange(piTriListIn, (t + 1) * 3 + 0, (t + 1) * 3 + 3))) {
bChooseOrientFirstTri = true;
}
// force match
{
final int t0 = bChooseOrientFirstTri ? t : (t + 1);
final int t1 = bChooseOrientFirstTri ? (t + 1) : t;
// clear first
pTriInfos[t1].flag &= (~ORIENT_PRESERVING);
// copy bit
pTriInfos[t1].flag |= (pTriInfos[t0].flag & ORIENT_PRESERVING);
}
}
}
t += 2;
} else {
++t;
}
}
// match up edge pairs
{
//Edge * pEdges = (Edge *) malloc(sizeof(Edge)*iNrTrianglesIn*3);
Edge[] pEdges = new Edge[iNrTrianglesIn * 3];
//TODO nehon weird... original algorithm check if pEdges is null but it's just been allocated... weirder, it does soemthing different if the edges are null...
// if (pEdges==null)
// BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn);
// else
// {
buildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn);
// }
}
}
use of com.jme3.math.Triangle in project jmonkeyengine by jMonkeyEngine.
the class MikktspaceTangentGenerator method DegenEpilogue.
static void DegenEpilogue(TSpace[] psTspace, TriInfo[] pTriInfos, int[] piTriListIn, final MikkTSpaceContext mikkTSpace, final int iNrTrianglesIn, final int iTotTris) {
// punishment for degenerate triangles is O(N^2)
for (int t = iNrTrianglesIn; t < iTotTris; t++) {
// degenerate triangles on a quad with one good triangle are skipped
// here but processed in the next loop
final boolean bSkip = (pTriInfos[t].flag & QUAD_ONE_DEGEN_TRI) != 0;
if (!bSkip) {
for (int i = 0; i < 3; i++) {
final int index1 = piTriListIn[t * 3 + i];
// search through the good triangles
boolean bNotFound = true;
int j = 0;
while (bNotFound && j < (3 * iNrTrianglesIn)) {
final int index2 = piTriListIn[j];
if (index1 == index2) {
bNotFound = false;
} else {
++j;
}
}
if (!bNotFound) {
final int iTri = j / 3;
final int iVert = j % 3;
final int iSrcVert = pTriInfos[iTri].vertNum[iVert];
final int iSrcOffs = pTriInfos[iTri].tSpacesOffs;
final int iDstVert = pTriInfos[t].vertNum[i];
final int iDstOffs = pTriInfos[t].tSpacesOffs;
// copy tspace
psTspace[iDstOffs + iDstVert] = psTspace[iSrcOffs + iSrcVert];
}
}
}
}
// deal with degenerate quads with one good triangle
for (int t = 0; t < iNrTrianglesIn; t++) {
// other triangle is degenerate
if ((pTriInfos[t].flag & QUAD_ONE_DEGEN_TRI) != 0) {
byte[] pV = pTriInfos[t].vertNum;
int iFlag = (1 << pV[0]) | (1 << pV[1]) | (1 << pV[2]);
int iMissingIndex = 0;
if ((iFlag & 2) == 0) {
iMissingIndex = 1;
} else if ((iFlag & 4) == 0) {
iMissingIndex = 2;
} else if ((iFlag & 8) == 0) {
iMissingIndex = 3;
}
int iOrgF = pTriInfos[t].orgFaceNumber;
Vector3f vDstP = getPosition(mikkTSpace, makeIndex(iOrgF, iMissingIndex));
boolean bNotFound = true;
int i = 0;
while (bNotFound && i < 3) {
final int iVert = pV[i];
final Vector3f vSrcP = getPosition(mikkTSpace, makeIndex(iOrgF, iVert));
if (vSrcP.equals(vDstP)) {
final int iOffs = pTriInfos[t].tSpacesOffs;
psTspace[iOffs + iMissingIndex] = psTspace[iOffs + iVert];
bNotFound = false;
} else {
++i;
}
}
assert (!bNotFound);
}
}
}
use of com.jme3.math.Triangle in project jmonkeyengine by jMonkeyEngine.
the class TangentBinormalGenerator method processTriangleData.
private static void processTriangleData(Mesh mesh, List<VertexData> vertices, boolean approxTangent, boolean splitMirrored) {
ArrayList<VertexInfo> vertexMap = linkVertices(mesh, splitMirrored);
FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.size() * 4);
ColorRGBA[] cols = null;
if (debug) {
cols = new ColorRGBA[vertices.size()];
}
Vector3f tangent = new Vector3f();
Vector3f binormal = new Vector3f();
//Vector3f normal = new Vector3f();
Vector3f givenNormal = new Vector3f();
Vector3f tangentUnit = new Vector3f();
Vector3f binormalUnit = new Vector3f();
for (int k = 0; k < vertexMap.size(); k++) {
float wCoord = -1;
VertexInfo vertexInfo = vertexMap.get(k);
givenNormal.set(vertexInfo.normal);
givenNormal.normalizeLocal();
TriangleData firstTriangle = vertices.get(vertexInfo.indices.get(0)).triangles.get(0);
// check tangent and binormal consistency
tangent.set(firstTriangle.tangent);
tangent.normalizeLocal();
binormal.set(firstTriangle.binormal);
binormal.normalizeLocal();
for (int i : vertexInfo.indices) {
ArrayList<TriangleData> triangles = vertices.get(i).triangles;
for (int j = 0; j < triangles.size(); j++) {
TriangleData triangleData = triangles.get(j);
tangentUnit.set(triangleData.tangent);
tangentUnit.normalizeLocal();
if (tangent.dot(tangentUnit) < toleranceDot) {
log.log(Level.WARNING, "Angle between tangents exceeds tolerance " + "for vertex {0}.", i);
break;
}
if (!approxTangent) {
binormalUnit.set(triangleData.binormal);
binormalUnit.normalizeLocal();
if (binormal.dot(binormalUnit) < toleranceDot) {
log.log(Level.WARNING, "Angle between binormals exceeds tolerance " + "for vertex {0}.", i);
break;
}
}
}
}
// find average tangent
tangent.set(0, 0, 0);
binormal.set(0, 0, 0);
int triangleCount = 0;
for (int i : vertexInfo.indices) {
ArrayList<TriangleData> triangles = vertices.get(i).triangles;
triangleCount += triangles.size();
if (debug) {
cols[i] = ColorRGBA.White;
}
for (int j = 0; j < triangles.size(); j++) {
TriangleData triangleData = triangles.get(j);
tangent.addLocal(triangleData.tangent);
binormal.addLocal(triangleData.binormal);
}
}
int blameVertex = vertexInfo.indices.get(0);
if (tangent.length() < ZERO_TOLERANCE) {
log.log(Level.WARNING, "Shared tangent is zero for vertex {0}.", blameVertex);
// attempt to fix from binormal
if (binormal.length() >= ZERO_TOLERANCE) {
binormal.cross(givenNormal, tangent);
tangent.normalizeLocal();
} else // if all fails use the tangent from the first triangle
{
tangent.set(firstTriangle.tangent);
}
} else {
tangent.divideLocal(triangleCount);
}
tangentUnit.set(tangent);
tangentUnit.normalizeLocal();
if (Math.abs(Math.abs(tangentUnit.dot(givenNormal)) - 1) < ZERO_TOLERANCE) {
log.log(Level.WARNING, "Normal and tangent are parallel for vertex {0}.", blameVertex);
}
if (!approxTangent) {
if (binormal.length() < ZERO_TOLERANCE) {
log.log(Level.WARNING, "Shared binormal is zero for vertex {0}.", blameVertex);
// attempt to fix from tangent
if (tangent.length() >= ZERO_TOLERANCE) {
givenNormal.cross(tangent, binormal);
binormal.normalizeLocal();
} else // if all fails use the binormal from the first triangle
{
binormal.set(firstTriangle.binormal);
}
} else {
binormal.divideLocal(triangleCount);
}
binormalUnit.set(binormal);
binormalUnit.normalizeLocal();
if (Math.abs(Math.abs(binormalUnit.dot(givenNormal)) - 1) < ZERO_TOLERANCE) {
log.log(Level.WARNING, "Normal and binormal are parallel for vertex {0}.", blameVertex);
}
if (Math.abs(Math.abs(binormalUnit.dot(tangentUnit)) - 1) < ZERO_TOLERANCE) {
log.log(Level.WARNING, "Tangent and binormal are parallel for vertex {0}.", blameVertex);
}
}
Vector3f finalTangent = new Vector3f();
Vector3f tmp = new Vector3f();
for (int i : vertexInfo.indices) {
if (approxTangent) {
// Gram-Schmidt orthogonalize
finalTangent.set(tangent).subtractLocal(tmp.set(givenNormal).multLocal(givenNormal.dot(tangent)));
finalTangent.normalizeLocal();
wCoord = tmp.set(givenNormal).crossLocal(tangent).dot(binormal) < 0f ? -1f : 1f;
tangents.put((i * 4), finalTangent.x);
tangents.put((i * 4) + 1, finalTangent.y);
tangents.put((i * 4) + 2, finalTangent.z);
tangents.put((i * 4) + 3, wCoord);
} else {
tangents.put((i * 4), tangent.x);
tangents.put((i * 4) + 1, tangent.y);
tangents.put((i * 4) + 2, tangent.z);
tangents.put((i * 4) + 3, wCoord);
//setInBuffer(binormal, binormals, i);
}
}
}
tangents.limit(tangents.capacity());
// If the model already had a tangent buffer, replace it with the regenerated one
mesh.clearBuffer(Type.Tangent);
mesh.setBuffer(Type.Tangent, 4, tangents);
if (mesh.isAnimated()) {
mesh.clearBuffer(Type.BindPoseNormal);
mesh.clearBuffer(Type.BindPosePosition);
mesh.clearBuffer(Type.BindPoseTangent);
mesh.generateBindPose(true);
}
if (debug) {
writeColorBuffer(vertices, cols, mesh);
}
mesh.updateBound();
mesh.updateCounts();
}
use of com.jme3.math.Triangle in project jmonkeyengine by jMonkeyEngine.
the class TangentBinormalGenerator method splitVertices.
//Don't remove splitmirorred boolean,It's not used right now, but i intend to
//make this method also split vertice with rotated tangent space and I'll
//add another splitRotated boolean
private static List<VertexData> splitVertices(Mesh mesh, List<VertexData> vertexData, boolean splitMirorred) {
int nbVertices = mesh.getBuffer(Type.Position).getNumElements();
List<VertexData> newVertices = new ArrayList<VertexData>();
Map<Integer, Integer> indiceMap = new HashMap<Integer, Integer>();
FloatBuffer normalBuffer = mesh.getFloatBuffer(Type.Normal);
for (int i = 0; i < vertexData.size(); i++) {
ArrayList<TriangleData> triangles = vertexData.get(i).triangles;
Vector3f givenNormal = new Vector3f();
populateFromBuffer(givenNormal, normalBuffer, i);
ArrayList<TriangleData> trianglesUp = new ArrayList<TriangleData>();
ArrayList<TriangleData> trianglesDown = new ArrayList<TriangleData>();
for (int j = 0; j < triangles.size(); j++) {
TriangleData triangleData = triangles.get(j);
if (parity(givenNormal, triangleData.normal) > 0) {
trianglesUp.add(triangleData);
} else {
trianglesDown.add(triangleData);
}
}
//if the vertex has triangles with opposite parity it has to be split
if (!trianglesUp.isEmpty() && !trianglesDown.isEmpty()) {
log.log(Level.FINE, "Splitting vertex {0}", i);
//assigning triangle with the same parity to the original vertex
vertexData.get(i).triangles.clear();
vertexData.get(i).triangles.addAll(trianglesUp);
//creating a new vertex
VertexData newVert = new VertexData();
//assigning triangles with opposite parity to it
newVert.triangles.addAll(trianglesDown);
newVertices.add(newVert);
//keep vertex index to fix the index buffers later
indiceMap.put(nbVertices, i);
for (TriangleData tri : newVert.triangles) {
for (int j = 0; j < tri.index.length; j++) {
if (tri.index[j] == i) {
tri.index[j] = nbVertices;
}
}
}
nbVertices++;
}
}
if (!newVertices.isEmpty()) {
//we have new vertices, we need to update the mesh's buffers.
for (Type type : VertexBuffer.Type.values()) {
//skip tangent buffer as we're gonna overwrite it later
if (type == Type.Tangent || type == Type.BindPoseTangent)
continue;
VertexBuffer vb = mesh.getBuffer(type);
//They'll be initialized when Hardware Skinning is engaged
if (vb == null || vb.getNumComponents() == 0)
continue;
Buffer buffer = vb.getData();
//IndexBuffer has special treatement, only swapping the vertex indices is needed
if (type == Type.Index) {
boolean isShortBuffer = vb.getFormat() == VertexBuffer.Format.UnsignedShort;
for (VertexData vertex : newVertices) {
for (TriangleData tri : vertex.triangles) {
for (int i = 0; i < tri.index.length; i++) {
if (isShortBuffer) {
((ShortBuffer) buffer).put(tri.triangleOffset + i, (short) tri.index[i]);
} else {
((IntBuffer) buffer).put(tri.triangleOffset + i, tri.index[i]);
}
}
}
}
vb.setUpdateNeeded();
} else {
//copy the buffer in a bigger one and append nex vertices to the end
Buffer newVerts = VertexBuffer.createBuffer(vb.getFormat(), vb.getNumComponents(), nbVertices);
if (buffer != null) {
buffer.rewind();
bulkPut(vb.getFormat(), newVerts, buffer);
int index = vertexData.size();
newVerts.position(vertexData.size() * vb.getNumComponents());
for (int j = 0; j < newVertices.size(); j++) {
int oldInd = indiceMap.get(index);
for (int i = 0; i < vb.getNumComponents(); i++) {
putValue(vb.getFormat(), newVerts, buffer, oldInd * vb.getNumComponents() + i);
}
index++;
}
vb.updateData(newVerts);
//destroy previous buffer as it's no longer needed
destroyDirectBuffer(buffer);
}
}
}
vertexData.addAll(newVertices);
mesh.updateCounts();
}
return vertexData;
}
Aggregations