Search in sources :

Example 1 with TemporalMesh

use of com.jme3.scene.plugins.blender.meshes.TemporalMesh in project jmonkeyengine by jMonkeyEngine.

the class GeneratedTexture method triangulate.

/**
     * This method triangulates the texture. In the result we get a set of small
     * flat textures for each face of the given mesh. This can be later merged
     * into one flat texture.
     * 
     * @param mesh
     *            the mesh we create the texture for
     * @param geometriesOMA
     *            the old memory address of the geometries group that the given
     *            mesh belongs to (required for bounding box calculations)
     * @param coordinatesType
     *            the types of UV coordinates
     * @param blenderContext
     *            the blender context
     * @return triangulated texture
     */
public TriangulatedTexture triangulate(Mesh mesh, Long geometriesOMA, UVCoordinatesType coordinatesType, BlenderContext blenderContext) {
    TemporalMesh geometries = (TemporalMesh) blenderContext.getLoadedFeature(geometriesOMA, LoadedDataType.TEMPORAL_MESH);
    int[] coordinatesSwappingIndexes = new int[] { ((Number) mTex.getFieldValue("projx")).intValue(), ((Number) mTex.getFieldValue("projy")).intValue(), ((Number) mTex.getFieldValue("projz")).intValue() };
    List<Vector3f> uvs = UVCoordinatesGenerator.generateUVCoordinatesFor3DTexture(mesh, coordinatesType, coordinatesSwappingIndexes, geometries);
    Vector3f[] uvsArray = uvs.toArray(new Vector3f[uvs.size()]);
    BoundingBox boundingBox = UVCoordinatesGenerator.getBoundingBox(geometries);
    Set<TriangleTextureElement> triangleTextureElements = new TreeSet<TriangleTextureElement>(new Comparator<TriangleTextureElement>() {

        public int compare(TriangleTextureElement o1, TriangleTextureElement o2) {
            return o1.faceIndex - o2.faceIndex;
        }
    });
    int[] indices = new int[3];
    for (int i = 0; i < mesh.getTriangleCount(); ++i) {
        mesh.getTriangle(i, indices);
        triangleTextureElements.add(new TriangleTextureElement(i, boundingBox, this, uvsArray, indices, blenderContext));
    }
    return new TriangulatedTexture(triangleTextureElements, blenderContext);
}
Also used : TriangleTextureElement(com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement) TemporalMesh(com.jme3.scene.plugins.blender.meshes.TemporalMesh) TreeSet(java.util.TreeSet) Vector3f(com.jme3.math.Vector3f) BoundingBox(com.jme3.bounding.BoundingBox)

Example 2 with TemporalMesh

use of com.jme3.scene.plugins.blender.meshes.TemporalMesh 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);
        }
    }
}
Also used : TemporalMesh(com.jme3.scene.plugins.blender.meshes.TemporalMesh) ObjectHelper(com.jme3.scene.plugins.blender.objects.ObjectHelper) Vector3f(com.jme3.math.Vector3f) Node(com.jme3.scene.Node) BlenderFileException(com.jme3.scene.plugins.blender.file.BlenderFileException) Structure(com.jme3.scene.plugins.blender.file.Structure) Face(com.jme3.scene.plugins.blender.meshes.Face) Edge(com.jme3.scene.plugins.blender.meshes.Edge)

Example 3 with TemporalMesh

use of com.jme3.scene.plugins.blender.meshes.TemporalMesh 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);
            }
        }
    }
}
Also used : ArrayList(java.util.ArrayList) Vector3f(com.jme3.math.Vector3f) Face(com.jme3.scene.plugins.blender.meshes.Face) Edge(com.jme3.scene.plugins.blender.meshes.Edge) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 4 with TemporalMesh

use of com.jme3.scene.plugins.blender.meshes.TemporalMesh 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();
}
Also used : LinkedHashSet(java.util.LinkedHashSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Vector2f(com.jme3.math.Vector2f) ArrayList(java.util.ArrayList) List(java.util.List) Face(com.jme3.scene.plugins.blender.meshes.Face) Vector3f(com.jme3.math.Vector3f) Edge(com.jme3.scene.plugins.blender.meshes.Edge) HashMap(java.util.HashMap) Map(java.util.Map)

Example 5 with TemporalMesh

use of com.jme3.scene.plugins.blender.meshes.TemporalMesh in project jmonkeyengine by jMonkeyEngine.

the class SubdivisionSurfaceModifier method subdivideUVs.

/**
     * The method subdivides mesh's UV coordinates. It actually performs only Catmull-Clark modifications because if any UV's are present then they are
     * automatically subdivided by the simple algorithm.
     * @param temporalMesh
     *            the mesh whose UV coordinates will be applied Catmull-Clark algorithm
     */
private void subdivideUVs(TemporalMesh temporalMesh) {
    List<Face> faces = temporalMesh.getFaces();
    Map<String, UvCoordsSubdivideTemporalMesh> subdividedUVS = new HashMap<String, UvCoordsSubdivideTemporalMesh>();
    for (Face face : faces) {
        if (face.getUvSets() != null) {
            for (Entry<String, List<Vector2f>> uvset : face.getUvSets().entrySet()) {
                UvCoordsSubdivideTemporalMesh uvCoordsSubdivideTemporalMesh = subdividedUVS.get(uvset.getKey());
                if (uvCoordsSubdivideTemporalMesh == null) {
                    try {
                        uvCoordsSubdivideTemporalMesh = new UvCoordsSubdivideTemporalMesh(temporalMesh.getBlenderContext());
                    } catch (BlenderFileException e) {
                        assert false : "Something went really wrong! The UvCoordsSubdivideTemporalMesh class should NOT throw exceptions here!";
                    }
                    subdividedUVS.put(uvset.getKey(), uvCoordsSubdivideTemporalMesh);
                }
                uvCoordsSubdivideTemporalMesh.addFace(uvset.getValue());
            }
        }
    }
    for (Entry<String, UvCoordsSubdivideTemporalMesh> entry : subdividedUVS.entrySet()) {
        entry.getValue().rebuildIndexesMappings();
        this.subdivideCatmullClark(entry.getValue());
        for (int i = 0; i < faces.size(); ++i) {
            List<Vector2f> uvs = faces.get(i).getUvSets().get(entry.getKey());
            if (uvs != null) {
                uvs.clear();
                uvs.addAll(entry.getValue().faceToUVs(i));
            }
        }
    }
}
Also used : HashMap(java.util.HashMap) BlenderFileException(com.jme3.scene.plugins.blender.file.BlenderFileException) Vector2f(com.jme3.math.Vector2f) ArrayList(java.util.ArrayList) List(java.util.List) Face(com.jme3.scene.plugins.blender.meshes.Face)

Aggregations

ArrayList (java.util.ArrayList)11 TemporalMesh (com.jme3.scene.plugins.blender.meshes.TemporalMesh)10 Vector3f (com.jme3.math.Vector3f)8 Structure (com.jme3.scene.plugins.blender.file.Structure)7 List (java.util.List)7 BlenderFileException (com.jme3.scene.plugins.blender.file.BlenderFileException)6 Pointer (com.jme3.scene.plugins.blender.file.Pointer)5 Face (com.jme3.scene.plugins.blender.meshes.Face)5 Vector2f (com.jme3.math.Vector2f)4 Node (com.jme3.scene.Node)4 Edge (com.jme3.scene.plugins.blender.meshes.Edge)4 HashMap (java.util.HashMap)4 Light (com.jme3.light.Light)3 MeshHelper (com.jme3.scene.plugins.blender.meshes.MeshHelper)3 ObjectHelper (com.jme3.scene.plugins.blender.objects.ObjectHelper)3 Texture (com.jme3.texture.Texture)3 Map (java.util.Map)3 BoundingBox (com.jme3.bounding.BoundingBox)2 Filter (com.jme3.post.Filter)2 Camera (com.jme3.renderer.Camera)2