use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class MirrorModifier method apply.
@Override
public void apply(Node node, BlenderContext blenderContext) {
if (invalid) {
LOGGER.log(Level.WARNING, "Mirror modifier is invalid! Cannot be applied to: {0}", node.getName());
} else {
TemporalMesh temporalMesh = this.getTemporalMesh(node);
if (temporalMesh != null) {
LOGGER.log(Level.FINE, "Applying mirror modifier to: {0}", temporalMesh);
Vector3f mirrorPlaneCenter = new Vector3f();
if (pMirrorObject.isNotNull()) {
Structure objectStructure;
try {
objectStructure = pMirrorObject.fetchData().get(0);
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
Node object = (Node) objectHelper.toObject(objectStructure, blenderContext);
if (object != null) {
// compute the mirror object coordinates in node's local space
mirrorPlaneCenter = this.getWorldMatrix(node).invertLocal().mult(object.getWorldTranslation());
}
} catch (BlenderFileException e) {
LOGGER.log(Level.SEVERE, "Cannot load mirror''s reference object. Cause: {0}", e.getLocalizedMessage());
LOGGER.log(Level.SEVERE, "Mirror modifier will not be applied to node named: {0}", node.getName());
return;
}
}
LOGGER.finest("Allocating temporal variables.");
float d;
Vector3f mirrorPlaneNormal = new Vector3f();
Vector3f shiftVector = new Vector3f();
LOGGER.fine("Mirroring mesh.");
for (int mirrorIndex = 0; mirrorIndex < 3; ++mirrorIndex) {
if (isMirrored[mirrorIndex]) {
boolean mirrorAtPoint0 = mirrorPlaneCenter.get(mirrorIndex) == 0;
if (!mirrorAtPoint0) {
// compute mirror's plane normal vector in node's space
mirrorPlaneNormal.set(0, 0, 0).set(mirrorIndex, Math.signum(mirrorPlaneCenter.get(mirrorIndex)));
}
TemporalMesh mirror = temporalMesh.clone();
for (int i = 0; i < mirror.getVertexCount(); ++i) {
Vector3f vertex = mirror.getVertices().get(i);
Vector3f normal = mirror.getNormals().get(i);
if (mirrorAtPoint0) {
d = Math.abs(vertex.get(mirrorIndex));
shiftVector.set(0, 0, 0).set(mirrorIndex, -vertex.get(mirrorIndex));
} else {
d = this.computeDistanceFromPlane(vertex, mirrorPlaneCenter, mirrorPlaneNormal);
mirrorPlaneNormal.mult(d, shiftVector);
}
if (merge && d <= tolerance) {
vertex.addLocal(shiftVector);
normal.set(mirrorIndex, 0);
temporalMesh.getVertices().get(i).addLocal(shiftVector);
temporalMesh.getNormals().get(i).set(mirrorIndex, 0);
} else {
vertex.addLocal(shiftVector.multLocal(2));
normal.set(mirrorIndex, -normal.get(mirrorIndex));
}
}
// flipping the indexes
for (Face face : mirror.getFaces()) {
face.flipIndexes();
}
for (Edge edge : mirror.getEdges()) {
edge.flipIndexes();
}
Collections.reverse(mirror.getPoints());
if (mirrorU || mirrorV) {
for (Face face : mirror.getFaces()) {
face.flipUV(mirrorU, mirrorV);
}
}
temporalMesh.append(mirror);
}
}
} else {
LOGGER.log(Level.WARNING, "Cannot find temporal mesh for node: {0}. The modifier will NOT be applied!", node);
}
}
}
use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class SubdivisionSurfaceModifier method subdivideCatmullClark.
/**
* Catmull-Clark subdivision. It assumes that the mesh was already simple-subdivided.
* @param temporalMesh
* the mesh whose vertices will be transformed to form Catmull-Clark subdivision
*/
private void subdivideCatmullClark(TemporalMesh temporalMesh) {
Set<Integer> boundaryVertices = new HashSet<Integer>();
for (Edge edge : temporalMesh.getEdges()) {
if (!edge.isInFace()) {
boundaryVertices.add(edge.getFirstIndex());
boundaryVertices.add(edge.getSecondIndex());
} else {
if (temporalMesh.isBoundary(edge.getFirstIndex())) {
boundaryVertices.add(edge.getFirstIndex());
}
if (temporalMesh.isBoundary(edge.getSecondIndex())) {
boundaryVertices.add(edge.getSecondIndex());
}
}
}
List<CreasePoint> creasePoints = new ArrayList<CreasePoint>(temporalMesh.getVertexCount());
for (int i = 0; i < temporalMesh.getVertexCount(); ++i) {
// finding adjacent edges that were created by dividing original edges
List<Edge> adjacentOriginalEdges = new ArrayList<Edge>();
Collection<Edge> adjacentEdges = temporalMesh.getAdjacentEdges(i);
if (adjacentEdges != null) {
// this can be null if a vertex with index 'i' is not connected to any face nor edge
for (Edge edge : temporalMesh.getAdjacentEdges(i)) {
if (verticesOnOriginalEdges.contains(edge.getFirstIndex()) || verticesOnOriginalEdges.contains(edge.getSecondIndex())) {
adjacentOriginalEdges.add(edge);
}
}
creasePoints.add(new CreasePoint(i, boundaryVertices.contains(i), adjacentOriginalEdges, temporalMesh));
} else {
//the count of crease points must be equal to vertex count; otherwise we'll get IndexOutofBoundsException later
creasePoints.add(null);
}
}
Vector3f[] averageVert = new Vector3f[temporalMesh.getVertexCount()];
int[] averageCount = new int[temporalMesh.getVertexCount()];
for (Face face : temporalMesh.getFaces()) {
Vector3f centroid = face.computeCentroid();
for (Integer index : face.getIndexes()) {
if (boundaryVertices.contains(index)) {
Edge edge = this.findEdge(temporalMesh, index, face.getIndexes().getNextIndex(index));
if (temporalMesh.isBoundary(edge)) {
averageVert[index] = averageVert[index] == null ? edge.computeCentroid() : averageVert[index].addLocal(edge.computeCentroid());
averageCount[index] += 1;
}
edge = this.findEdge(temporalMesh, face.getIndexes().getPreviousIndex(index), index);
if (temporalMesh.isBoundary(edge)) {
averageVert[index] = averageVert[index] == null ? edge.computeCentroid() : averageVert[index].addLocal(edge.computeCentroid());
averageCount[index] += 1;
}
} else {
averageVert[index] = averageVert[index] == null ? centroid.clone() : averageVert[index].addLocal(centroid);
averageCount[index] += 1;
}
}
}
for (Edge edge : temporalMesh.getEdges()) {
if (!edge.isInFace()) {
Vector3f centroid = temporalMesh.getVertices().get(edge.getFirstIndex()).add(temporalMesh.getVertices().get(edge.getSecondIndex())).divideLocal(2);
averageVert[edge.getFirstIndex()] = averageVert[edge.getFirstIndex()] == null ? centroid.clone() : averageVert[edge.getFirstIndex()].addLocal(centroid);
averageVert[edge.getSecondIndex()] = averageVert[edge.getSecondIndex()] == null ? centroid.clone() : averageVert[edge.getSecondIndex()].addLocal(centroid);
averageCount[edge.getFirstIndex()] += 1;
averageCount[edge.getSecondIndex()] += 1;
}
}
for (int i = 0; i < averageVert.length; ++i) {
if (averageVert[i] != null && averageCount[i] > 0) {
Vector3f v = temporalMesh.getVertices().get(i);
averageVert[i].divideLocal(averageCount[i]);
// computing translation vector
Vector3f t = averageVert[i].subtract(v);
if (!boundaryVertices.contains(i)) {
t.multLocal(4 / (float) averageCount[i]);
}
// moving the vertex
v.addLocal(t);
// applying crease weight if neccessary
CreasePoint creasePoint = creasePoints.get(i);
if (creasePoint.getTarget() != null && creasePoint.getWeight() != 0) {
t = creasePoint.getTarget().subtractLocal(v).multLocal(creasePoint.getWeight());
v.addLocal(t);
}
}
}
}
use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class SubdivisionSurfaceModifier method subdivideSimple.
/**
* The method performs a simple subdivision of the mesh.
*
* @param temporalMesh
* the mesh to be subdivided
*/
private void subdivideSimple(TemporalMesh temporalMesh) {
Map<Edge, Integer> edgePoints = new HashMap<Edge, Integer>();
Map<Face, Integer> facePoints = new HashMap<Face, Integer>();
Set<Face> newFaces = new LinkedHashSet<Face>();
Set<Edge> newEdges = new LinkedHashSet<Edge>(temporalMesh.getEdges().size() * 4);
int originalFacesCount = temporalMesh.getFaces().size();
List<Map<String, Float>> vertexGroups = temporalMesh.getVertexGroups();
// the result vertex array will have verts in the following order [[original_verts], [face_verts], [edge_verts]]
List<Vector3f> vertices = temporalMesh.getVertices();
List<Vector3f> edgeVertices = new ArrayList<Vector3f>();
List<Vector3f> faceVertices = new ArrayList<Vector3f>();
// the same goes for normals
List<Vector3f> normals = temporalMesh.getNormals();
List<Vector3f> edgeNormals = new ArrayList<Vector3f>();
List<Vector3f> faceNormals = new ArrayList<Vector3f>();
List<Face> faces = temporalMesh.getFaces();
for (Face face : faces) {
Map<String, List<Vector2f>> uvSets = face.getUvSets();
Vector3f facePoint = face.computeCentroid();
Integer facePointIndex = vertices.size() + faceVertices.size();
facePoints.put(face, facePointIndex);
faceVertices.add(facePoint);
faceNormals.add(this.computeFaceNormal(face));
Map<String, Vector2f> faceUV = this.computeFaceUVs(face);
byte[] faceVertexColor = this.computeFaceVertexColor(face);
Map<String, Float> faceVertexGroups = this.computeFaceVertexGroups(face);
if (vertexGroups.size() > 0) {
vertexGroups.add(faceVertexGroups);
}
for (int i = 0; i < face.getIndexes().size(); ++i) {
int vIndex = face.getIndexes().get(i);
int vPrevIndex = i == 0 ? face.getIndexes().get(face.getIndexes().size() - 1) : face.getIndexes().get(i - 1);
int vNextIndex = i == face.getIndexes().size() - 1 ? face.getIndexes().get(0) : face.getIndexes().get(i + 1);
Edge prevEdge = this.findEdge(temporalMesh, vPrevIndex, vIndex);
Edge nextEdge = this.findEdge(temporalMesh, vIndex, vNextIndex);
int vPrevEdgeVertIndex = edgePoints.containsKey(prevEdge) ? edgePoints.get(prevEdge) : -1;
int vNextEdgeVertIndex = edgePoints.containsKey(nextEdge) ? edgePoints.get(nextEdge) : -1;
Vector3f v = temporalMesh.getVertices().get(vIndex);
if (vPrevEdgeVertIndex < 0) {
vPrevEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size();
verticesOnOriginalEdges.add(vPrevEdgeVertIndex);
edgeVertices.add(vertices.get(vPrevIndex).add(v).divideLocal(2));
edgeNormals.add(normals.get(vPrevIndex).add(normals.get(vIndex)).normalizeLocal());
edgePoints.put(prevEdge, vPrevEdgeVertIndex);
if (vertexGroups.size() > 0) {
vertexGroups.add(this.interpolateVertexGroups(Arrays.asList(vertexGroups.get(vPrevIndex), vertexGroups.get(vIndex))));
}
}
if (vNextEdgeVertIndex < 0) {
vNextEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size();
verticesOnOriginalEdges.add(vNextEdgeVertIndex);
edgeVertices.add(vertices.get(vNextIndex).add(v).divideLocal(2));
edgeNormals.add(normals.get(vNextIndex).add(normals.get(vIndex)).normalizeLocal());
edgePoints.put(nextEdge, vNextEdgeVertIndex);
if (vertexGroups.size() > 0) {
vertexGroups.add(this.interpolateVertexGroups(Arrays.asList(vertexGroups.get(vNextIndex), vertexGroups.get(vIndex))));
}
}
Integer[] indexes = new Integer[] { vIndex, vNextEdgeVertIndex, facePointIndex, vPrevEdgeVertIndex };
Map<String, List<Vector2f>> newUVSets = null;
if (uvSets != null) {
newUVSets = new HashMap<String, List<Vector2f>>(uvSets.size());
for (Entry<String, List<Vector2f>> uvset : uvSets.entrySet()) {
int indexOfvIndex = i;
int indexOfvPrevIndex = face.getIndexes().indexOf(vPrevIndex);
int indexOfvNextIndex = face.getIndexes().indexOf(vNextIndex);
Vector2f uv1 = uvset.getValue().get(indexOfvIndex);
Vector2f uv2 = uvset.getValue().get(indexOfvNextIndex).add(uv1).divideLocal(2);
Vector2f uv3 = faceUV.get(uvset.getKey());
Vector2f uv4 = uvset.getValue().get(indexOfvPrevIndex).add(uv1).divideLocal(2);
List<Vector2f> uvList = Arrays.asList(uv1, uv2, uv3, uv4);
newUVSets.put(uvset.getKey(), new ArrayList<Vector2f>(uvList));
}
}
List<byte[]> vertexColors = null;
if (face.getVertexColors() != null) {
int indexOfvIndex = i;
int indexOfvPrevIndex = face.getIndexes().indexOf(vPrevIndex);
int indexOfvNextIndex = face.getIndexes().indexOf(vNextIndex);
byte[] vCol1 = face.getVertexColors().get(indexOfvIndex);
byte[] vCol2 = this.interpolateVertexColors(face.getVertexColors().get(indexOfvNextIndex), vCol1);
byte[] vCol3 = faceVertexColor;
byte[] vCol4 = this.interpolateVertexColors(face.getVertexColors().get(indexOfvPrevIndex), vCol1);
vertexColors = new ArrayList<byte[]>(Arrays.asList(vCol1, vCol2, vCol3, vCol4));
}
newFaces.add(new Face(indexes, face.isSmooth(), face.getMaterialNumber(), newUVSets, vertexColors, temporalMesh));
newEdges.add(new Edge(vIndex, vNextEdgeVertIndex, nextEdge.getCrease(), true, temporalMesh));
newEdges.add(new Edge(vNextEdgeVertIndex, facePointIndex, 0, true, temporalMesh));
newEdges.add(new Edge(facePointIndex, vPrevEdgeVertIndex, 0, true, temporalMesh));
newEdges.add(new Edge(vPrevEdgeVertIndex, vIndex, prevEdge.getCrease(), true, temporalMesh));
}
}
vertices.addAll(faceVertices);
vertices.addAll(edgeVertices);
normals.addAll(faceNormals);
normals.addAll(edgeNormals);
for (Edge edge : temporalMesh.getEdges()) {
if (!edge.isInFace()) {
int newVertexIndex = vertices.size();
vertices.add(vertices.get(edge.getFirstIndex()).add(vertices.get(edge.getSecondIndex())).divideLocal(2));
normals.add(normals.get(edge.getFirstIndex()).add(normals.get(edge.getSecondIndex())).normalizeLocal());
newEdges.add(new Edge(edge.getFirstIndex(), newVertexIndex, edge.getCrease(), false, temporalMesh));
newEdges.add(new Edge(newVertexIndex, edge.getSecondIndex(), edge.getCrease(), false, temporalMesh));
verticesOnOriginalEdges.add(newVertexIndex);
}
}
temporalMesh.getFaces().clear();
temporalMesh.getFaces().addAll(newFaces);
temporalMesh.getEdges().clear();
temporalMesh.getEdges().addAll(newEdges);
temporalMesh.rebuildIndexesMappings();
}
use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class Edge method getCrossPoint.
/**
* The method computes the crossing pint of this edge and another edge. If
* there is no crossing then null is returned. Also null is returned if the edges are parallel.
* This method also allows to get the crossing point of the straight lines that contain these edges if
* you set the 'extend' parameter to true.
*
* @param edge
* the edge to compute corss point with
* @param extendThisEdge
* set to <b>true</b> to find a crossing point along the whole
* straight that contains the current edge
* @param extendSecondEdge
* set to <b>true</b> to find a crossing point along the whole
* straight that contains the given edge
* @return cross point on null if none exist or the edges are parallel
*/
public Vector3f getCrossPoint(Edge edge, boolean extendThisEdge, boolean extendSecondEdge) {
Vector3d P1 = new Vector3d(this.getFirstVertex());
Vector3d P2 = new Vector3d(edge.getFirstVertex());
Vector3d u = new Vector3d(this.getSecondVertex()).subtract(P1).normalizeLocal();
Vector3d v = new Vector3d(edge.getSecondVertex()).subtract(P2).normalizeLocal();
if (Math.abs(u.dot(v)) >= 1 - FastMath.DBL_EPSILON) {
// the edges are parallel; do not care about the crossing point
return null;
}
double t1 = 0, t2 = 0;
if (u.x == 0 && v.x == 0) {
t2 = (u.z * (P2.y - P1.y) - u.y * (P2.z - P1.z)) / (u.y * v.z - u.z * v.y);
t1 = (P2.z - P1.z + v.z * t2) / u.z;
} else if (u.y == 0 && v.y == 0) {
t2 = (u.x * (P2.z - P1.z) - u.z * (P2.x - P1.x)) / (u.z * v.x - u.x * v.z);
t1 = (P2.x - P1.x + v.x * t2) / u.x;
} else if (u.z == 0 && v.z == 0) {
t2 = (u.x * (P2.y - P1.y) - u.y * (P2.x - P1.x)) / (u.y * v.x - u.x * v.y);
t1 = (P2.x - P1.x + v.x * t2) / u.x;
} else {
t2 = (P1.y * u.x - P1.x * u.y + P2.x * u.y - P2.y * u.x) / (v.y * u.x - u.y * v.x);
t1 = (P2.x - P1.x + v.x * t2) / u.x;
if (Math.abs(P1.z - P2.z + u.z * t1 - v.z * t2) > FastMath.FLT_EPSILON) {
return null;
}
}
Vector3d p1 = P1.add(u.mult(t1));
Vector3d p2 = P2.add(v.mult(t2));
if (p1.distance(p2) <= FastMath.FLT_EPSILON) {
if (extendThisEdge && extendSecondEdge) {
return p1.toVector3f();
}
// the lines cross, check if p1 and p2 are within the edges
Vector3d p = p1.subtract(P1);
double cos = p.dot(u) / p.length();
if (extendThisEdge || p.length() <= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() - this.getLength() <= FastMath.FLT_EPSILON) {
// p1 is inside the first edge, lets check the other edge now
p = p2.subtract(P2);
cos = p.dot(v) / p.length();
if (extendSecondEdge || p.length() <= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() - edge.getLength() <= FastMath.FLT_EPSILON) {
return p1.toVector3f();
}
}
}
return null;
}
use of com.jme3.scene.plugins.blender.meshes.Edge in project jmonkeyengine by jMonkeyEngine.
the class TestShadowBug method simpleInitApp.
@Override
public void simpleInitApp() {
flyCam.setMoveSpeed(100f);
rootNode.attachChild(makeFloor());
Node characters = new Node("Characters");
characters.setShadowMode(ShadowMode.Cast);
rootNode.attachChild(characters);
Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
golem.scale(0.5f);
golem.setLocalTranslation(200.0f, -6f, 200f);
golem.setShadowMode(ShadowMode.CastAndReceive);
characters.attachChild(golem);
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-1f, -1f, 1f));
sun.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(sun);
characters.addLight(sun);
SpotLight spot = new SpotLight();
// distance
spot.setSpotRange(13f);
// inner light cone (central beam)
spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD);
// outer light cone (edge of the light)
spot.setSpotOuterAngle(20f * FastMath.DEG_TO_RAD);
// light color
spot.setColor(ColorRGBA.White.mult(1.3f));
spot.setPosition(new Vector3f(192.0f, -1f, 192f));
spot.setDirection(new Vector3f(1, -0.5f, 1));
rootNode.addLight(spot);
PointLight lamp_light = new PointLight();
lamp_light.setColor(ColorRGBA.Yellow);
lamp_light.setRadius(20f);
lamp_light.setPosition(new Vector3f(210.0f, 0f, 210f));
rootNode.addLight(lamp_light);
SpotLightShadowRenderer slsr = new SpotLightShadowRenderer(assetManager, 512);
slsr.setLight(spot);
slsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
slsr.setShadowIntensity(0.6f);
slsr.setFlushQueues(false);
viewPort.addProcessor(slsr);
PointLightShadowRenderer plsr = new PointLightShadowRenderer(assetManager, 512);
plsr.setLight(lamp_light);
plsr.setShadowIntensity(0.6f);
plsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
plsr.setFlushQueues(false);
viewPort.addProcessor(plsr);
viewPort.getCamera().setLocation(new Vector3f(192.0f, 10f, 192f));
float[] angles = new float[] { 3.14f / 2, 3.14f / 2, 0 };
viewPort.getCamera().setRotation(new Quaternion(angles));
}
Aggregations