use of com.jme3.scene.plugins.blender.meshes.Edge 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.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class MikktspaceTangentGenerator method evalTspace.
static TSpace evalTspace(int[] face_indices, final int iFaces, final int[] piTriListIn, final TriInfo[] pTriInfos, final MikkTSpaceContext mikkTSpace, final int iVertexRepresentitive) {
TSpace res = new TSpace();
float fAngleSum = 0;
for (int face = 0; face < iFaces; face++) {
final int f = face_indices[face];
// only valid triangles get to add their contribution
if ((pTriInfos[f].flag & GROUP_WITH_ANY) == 0) {
int i = -1;
if (piTriListIn[3 * f + 0] == iVertexRepresentitive) {
i = 0;
} else if (piTriListIn[3 * f + 1] == iVertexRepresentitive) {
i = 1;
} else if (piTriListIn[3 * f + 2] == iVertexRepresentitive) {
i = 2;
}
assert (i >= 0 && i < 3);
// project
int index = piTriListIn[3 * f + i];
Vector3f n = getNormal(mikkTSpace, index);
Vector3f vOs = pTriInfos[f].os.subtract(n.mult(n.dot(pTriInfos[f].os)));
Vector3f vOt = pTriInfos[f].ot.subtract(n.mult(n.dot(pTriInfos[f].ot)));
vOs.normalizeLocal();
vOt.normalizeLocal();
int i2 = piTriListIn[3 * f + (i < 2 ? (i + 1) : 0)];
int i1 = piTriListIn[3 * f + i];
int i0 = piTriListIn[3 * f + (i > 0 ? (i - 1) : 2)];
Vector3f p0 = getPosition(mikkTSpace, i0);
Vector3f p1 = getPosition(mikkTSpace, i1);
Vector3f p2 = getPosition(mikkTSpace, i2);
Vector3f v1 = p0.subtract(p1);
Vector3f v2 = p2.subtract(p1);
// project
v1.subtractLocal(n.mult(n.dot(v1))).normalizeLocal();
v2.subtractLocal(n.mult(n.dot(v2))).normalizeLocal();
// weight contribution by the angle
// between the two edge vectors
float fCos = v1.dot(v2);
fCos = fCos > 1 ? 1 : (fCos < (-1) ? (-1) : fCos);
float fAngle = (float) Math.acos(fCos);
float fMagS = pTriInfos[f].magS;
float fMagT = pTriInfos[f].magT;
res.os.addLocal(vOs.multLocal(fAngle));
res.ot.addLocal(vOt.multLocal(fAngle));
res.magS += (fAngle * fMagS);
res.magT += (fAngle * fMagT);
fAngleSum += fAngle;
}
}
// normalize
res.os.normalizeLocal();
res.ot.normalizeLocal();
if (fAngleSum > 0) {
res.magS /= fAngleSum;
res.magT /= fAngleSum;
}
return res;
}
use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class CurvesTemporalMesh method applyBevelAndTaper.
/**
* This method applies bevel and taper objects to the curve.
* @param curve
* the curve we apply the objects to
* @param bevelObject
* the bevel object
* @param taperObject
* the taper object
* @param blenderContext
* the blender context
* @return a list of geometries representing the beveled and/or tapered curve
* @throws BlenderFileException
* an exception is thrown when problems with reading occur
*/
private CurvesTemporalMesh applyBevelAndTaper(CurvesTemporalMesh curve, CurvesTemporalMesh bevelObject, CurvesTemporalMesh taperObject, BlenderContext blenderContext) throws BlenderFileException {
List<BezierLine> bevelBezierLines = bevelObject.getScaledBeziers();
List<BezierLine> curveLines = curve.beziers;
if (bevelBezierLines.size() == 0 || curveLines.size() == 0) {
return null;
}
CurvesTemporalMesh result = new CurvesTemporalMesh(blenderContext);
for (BezierLine curveLine : curveLines) {
Vector3f[] curveLineVertices = curveLine.getVertices(bevelStart, bevelEnd);
for (BezierLine bevelBezierLine : bevelBezierLines) {
CurvesTemporalMesh partResult = new CurvesTemporalMesh(blenderContext);
Vector3f[] bevelLineVertices = bevelBezierLine.getVertices();
List<Vector3f[]> bevels = new ArrayList<Vector3f[]>();
Vector3f[] bevelPoints = curvesHelper.transformToFirstLineOfBevelPoints(bevelLineVertices, curveLineVertices[0], curveLineVertices[1]);
bevels.add(bevelPoints);
for (int i = 1; i < curveLineVertices.length - 1; ++i) {
bevelPoints = curvesHelper.transformBevel(bevelPoints, curveLineVertices[i - 1], curveLineVertices[i], curveLineVertices[i + 1]);
bevels.add(bevelPoints);
}
bevelPoints = curvesHelper.transformBevel(bevelPoints, curveLineVertices[curveLineVertices.length - 2], curveLineVertices[curveLineVertices.length - 1], null);
bevels.add(bevelPoints);
Vector3f subtractResult = new Vector3f();
if (bevels.size() > 2) {
// changing the first and last bevel so that they are parallel to their neighbours (blender works this way)
// notice this implicates that the distances of every corresponding point in the two bevels must be identical and
// equal to the distance between the points on curve that define the bevel position
// so instead doing complicated rotations on each point we will simply properly translate each of them
int[][] pointIndexes = new int[][] { { 0, 1 }, { curveLineVertices.length - 1, curveLineVertices.length - 2 } };
for (int[] indexes : pointIndexes) {
float distance = curveLineVertices[indexes[1]].subtract(curveLineVertices[indexes[0]], subtractResult).length();
Vector3f[] bevel = bevels.get(indexes[0]);
Vector3f[] nextBevel = bevels.get(indexes[1]);
for (int i = 0; i < bevel.length; ++i) {
float d = bevel[i].subtract(nextBevel[i], subtractResult).length();
subtractResult.normalizeLocal().multLocal(distance - d);
bevel[i].addLocal(subtractResult);
}
}
}
if (taperObject != null) {
float curveLength = curveLine.getLength(), lengthAlongCurve = bevelStart;
for (int i = 0; i < curveLineVertices.length; ++i) {
if (i > 0) {
lengthAlongCurve += curveLineVertices[i].subtract(curveLineVertices[i - 1], subtractResult).length();
}
float taperScale = -taperObject.getValueAlongCurve(lengthAlongCurve / curveLength).z * taperObject.scale.z;
if (taperScale != 1) {
this.applyScale(bevels.get(i), curveLineVertices[i], taperScale);
}
}
}
// adding vertices to the part result
for (Vector3f[] bevel : bevels) {
for (Vector3f d : bevel) {
partResult.getVertices().add(d);
}
}
// preparing faces for the part result (each face is a quad)
int bevelVertCount = bevelPoints.length;
for (int i = 0; i < bevels.size() - 1; ++i) {
for (int j = 0; j < bevelVertCount - 1; ++j) {
Integer[] indexes = new Integer[] { i * bevelVertCount + j + 1, (i + 1) * bevelVertCount + j + 1, (i + 1) * bevelVertCount + j, i * bevelVertCount + j };
partResult.getFaces().add(new Face(indexes, curveLine.isSmooth(), curveLine.getMaterialNumber(), null, null, partResult));
partResult.getEdges().add(new Edge(indexes[0], indexes[1], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[1], indexes[2], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[2], indexes[3], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[3], indexes[0], 0, true, partResult));
}
if (bevelBezierLine.isCyclic()) {
int j = bevelVertCount - 1;
Integer[] indexes = new Integer[] { i * bevelVertCount, (i + 1) * bevelVertCount, (i + 1) * bevelVertCount + j, i * bevelVertCount + j };
partResult.getFaces().add(new Face(indexes, curveLine.isSmooth(), curveLine.getMaterialNumber(), null, null, partResult));
partResult.getEdges().add(new Edge(indexes[0], indexes[1], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[1], indexes[2], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[2], indexes[3], 0, true, partResult));
partResult.getEdges().add(new Edge(indexes[3], indexes[0], 0, true, partResult));
}
}
partResult.generateNormals();
if (fillCaps) {
// caps in blender behave as if they weren't affected by the smooth factor
// START CAP
Vector3f[] cap = bevels.get(0);
List<Integer> capIndexes = new ArrayList<Integer>(cap.length);
Vector3f capNormal = curveLineVertices[0].subtract(curveLineVertices[1]).normalizeLocal();
for (int i = 0; i < cap.length; ++i) {
capIndexes.add(partResult.getVertices().size());
partResult.getVertices().add(cap[i]);
partResult.getNormals().add(capNormal);
}
// the indexes ned to be reversed for the face to have fron face outside the beveled line
Collections.reverse(capIndexes);
partResult.getFaces().add(new Face(capIndexes.toArray(new Integer[capIndexes.size()]), false, curveLine.getMaterialNumber(), null, null, partResult));
for (int i = 1; i < capIndexes.size(); ++i) {
partResult.getEdges().add(new Edge(capIndexes.get(i - 1), capIndexes.get(i), 0, true, partResult));
}
// END CAP
cap = bevels.get(bevels.size() - 1);
capIndexes.clear();
capNormal = curveLineVertices[curveLineVertices.length - 1].subtract(curveLineVertices[curveLineVertices.length - 2]).normalizeLocal();
for (int i = 0; i < cap.length; ++i) {
capIndexes.add(partResult.getVertices().size());
partResult.getVertices().add(cap[i]);
partResult.getNormals().add(capNormal);
}
partResult.getFaces().add(new Face(capIndexes.toArray(new Integer[capIndexes.size()]), false, curveLine.getMaterialNumber(), null, null, partResult));
for (int i = 1; i < capIndexes.size(); ++i) {
partResult.getEdges().add(new Edge(capIndexes.get(i - 1), capIndexes.get(i), 0, true, partResult));
}
}
result.append(partResult);
}
}
return result;
}
use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class Point method loadAll.
/**
* Loads all points of the mesh that do not belong to any edge.
* @param meshStructure
* the mesh structure
* @return a list of points
* @throws BlenderFileException
* an exception is thrown when problems with file reading occur
*/
public static List<Point> loadAll(Structure meshStructure) throws BlenderFileException {
LOGGER.log(Level.FINE, "Loading all points that do not belong to any edge from mesh: {0}", meshStructure.getName());
List<Point> result = new ArrayList<Point>();
Pointer pMEdge = (Pointer) meshStructure.getFieldValue("medge");
if (pMEdge.isNotNull()) {
int count = ((Number) meshStructure.getFieldValue("totvert")).intValue();
Set<Integer> unusedVertices = new HashSet<Integer>(count);
for (int i = 0; i < count; ++i) {
unusedVertices.add(i);
}
List<Structure> edges = pMEdge.fetchData();
for (Structure edge : edges) {
unusedVertices.remove(((Number) edge.getFieldValue("v1")).intValue());
unusedVertices.remove(((Number) edge.getFieldValue("v2")).intValue());
}
for (Integer unusedIndex : unusedVertices) {
result.add(new Point(unusedIndex));
}
}
LOGGER.log(Level.FINE, "Loaded {0} points.", result.size());
return result;
}
use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class TemporalMesh method prepareLinesGeometry.
/**
* The method creates geometries from lines.
* @param result
* the list where new geometries will be appended
* @param meshHelper
* the mesh helper
*/
protected void prepareLinesGeometry(List<Geometry> result, MeshHelper meshHelper) {
if (edges.size() > 0) {
LOGGER.fine("Preparing lines geometries.");
List<List<Integer>> separateEdges = new ArrayList<List<Integer>>();
List<Edge> edges = new ArrayList<Edge>(this.edges.size());
for (Edge edge : this.edges) {
if (!edge.isInFace()) {
edges.add(edge);
}
}
while (edges.size() > 0) {
boolean edgeAppended = false;
int edgeIndex = 0;
for (List<Integer> list : separateEdges) {
for (edgeIndex = 0; edgeIndex < edges.size() && !edgeAppended; ++edgeIndex) {
Edge edge = edges.get(edgeIndex);
if (list.get(0).equals(edge.getFirstIndex())) {
list.add(0, edge.getSecondIndex());
--edgeIndex;
edgeAppended = true;
} else if (list.get(0).equals(edge.getSecondIndex())) {
list.add(0, edge.getFirstIndex());
--edgeIndex;
edgeAppended = true;
} else if (list.get(list.size() - 1).equals(edge.getFirstIndex())) {
list.add(edge.getSecondIndex());
--edgeIndex;
edgeAppended = true;
} else if (list.get(list.size() - 1).equals(edge.getSecondIndex())) {
list.add(edge.getFirstIndex());
--edgeIndex;
edgeAppended = true;
}
}
if (edgeAppended) {
break;
}
}
Edge edge = edges.remove(edgeAppended ? edgeIndex : 0);
if (!edgeAppended) {
separateEdges.add(new ArrayList<Integer>(Arrays.asList(edge.getFirstIndex(), edge.getSecondIndex())));
}
}
for (List<Integer> list : separateEdges) {
MeshBuffers meshBuffers = new MeshBuffers(0);
for (int index : list) {
meshBuffers.append(vertices.get(index), normals.get(index));
}
Mesh mesh = new Mesh();
mesh.setLineWidth(blenderContext.getBlenderKey().getLinesWidth());
mesh.setMode(Mode.LineStrip);
if (meshBuffers.isShortIndexBuffer()) {
mesh.setBuffer(Type.Index, 1, (ShortBuffer) meshBuffers.getIndexBuffer());
} else {
mesh.setBuffer(Type.Index, 1, (IntBuffer) meshBuffers.getIndexBuffer());
}
mesh.setBuffer(meshBuffers.getPositionsBuffer());
mesh.setBuffer(meshBuffers.getNormalsBuffer());
Geometry geometry = new Geometry(meshStructure.getName() + (result.size() + 1), mesh);
geometry.setMaterial(meshHelper.getBlackUnshadedMaterial(blenderContext));
if (properties != null && properties.getValue() != null) {
meshHelper.applyProperties(geometry, properties);
}
result.add(geometry);
}
}
}
Aggregations