Search in sources :

Example 6 with Face

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

the class SubdivisionSurfaceModifier method computeFaceNormal.

/**
     * The method computes the face's normal vector.
     * @param face
     *            the face of the mesh
     * @return face's normal vector
     */
private Vector3f computeFaceNormal(Face face) {
    Vector3f result = new Vector3f();
    for (Integer index : face.getIndexes()) {
        result.addLocal(face.getTemporalMesh().getNormals().get(index));
    }
    result.divideLocal(face.getIndexes().size());
    return result;
}
Also used : Vector3f(com.jme3.math.Vector3f)

Example 7 with Face

use of com.jme3.scene.plugins.blender.meshes.Face 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 8 with Face

use of com.jme3.scene.plugins.blender.meshes.Face 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)

Example 9 with Face

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

the class Face method loadAll.

/**
     * Loads all faces of a given mesh.
     * @param meshStructure
     *            the mesh structure we read the faces from
     * @param userUVGroups
     *            UV groups defined by the user
     * @param verticesColors
     *            the vertices colors of the mesh
     * @param temporalMesh
     *            the temporal mesh the faces will belong to
     * @param blenderContext
     *            the blender context
     * @return list of faces read from the given mesh structure
     * @throws BlenderFileException
     *             an exception is thrown when problems with file reading occur
     */
public static List<Face> loadAll(Structure meshStructure, Map<String, List<Vector2f>> userUVGroups, List<byte[]> verticesColors, TemporalMesh temporalMesh, BlenderContext blenderContext) throws BlenderFileException {
    LOGGER.log(Level.FINE, "Loading all faces from mesh: {0}", meshStructure.getName());
    List<Face> result = new ArrayList<Face>();
    MeshHelper meshHelper = blenderContext.getHelper(MeshHelper.class);
    if (meshHelper.isBMeshCompatible(meshStructure)) {
        LOGGER.fine("Reading BMesh.");
        Pointer pMLoop = (Pointer) meshStructure.getFieldValue("mloop");
        Pointer pMPoly = (Pointer) meshStructure.getFieldValue("mpoly");
        if (pMPoly.isNotNull() && pMLoop.isNotNull()) {
            List<Structure> polys = pMPoly.fetchData();
            List<Structure> loops = pMLoop.fetchData();
            for (Structure poly : polys) {
                int materialNumber = ((Number) poly.getFieldValue("mat_nr")).intValue();
                int loopStart = ((Number) poly.getFieldValue("loopstart")).intValue();
                int totLoop = ((Number) poly.getFieldValue("totloop")).intValue();
                boolean smooth = (((Number) poly.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
                Integer[] vertexIndexes = new Integer[totLoop];
                for (int i = loopStart; i < loopStart + totLoop; ++i) {
                    vertexIndexes[i - loopStart] = ((Number) loops.get(i).getFieldValue("v")).intValue();
                }
                // uvs always must be added wheater we have texture or not
                Map<String, List<Vector2f>> uvCoords = new HashMap<String, List<Vector2f>>();
                for (Entry<String, List<Vector2f>> entry : userUVGroups.entrySet()) {
                    List<Vector2f> uvs = entry.getValue().subList(loopStart, loopStart + totLoop);
                    uvCoords.put(entry.getKey(), new ArrayList<Vector2f>(uvs));
                }
                List<byte[]> vertexColors = null;
                if (verticesColors != null && verticesColors.size() > 0) {
                    vertexColors = new ArrayList<byte[]>(totLoop);
                    for (int i = loopStart; i < loopStart + totLoop; ++i) {
                        vertexColors.add(verticesColors.get(i));
                    }
                }
                result.add(new Face(vertexIndexes, smooth, materialNumber, uvCoords, vertexColors, temporalMesh));
            }
        }
    } else {
        LOGGER.fine("Reading traditional faces.");
        Pointer pMFace = (Pointer) meshStructure.getFieldValue("mface");
        List<Structure> mFaces = pMFace.isNotNull() ? pMFace.fetchData() : null;
        if (mFaces != null && mFaces.size() > 0) {
            // indicates if the material with the specified number should have a texture attached
            for (int i = 0; i < mFaces.size(); ++i) {
                Structure mFace = mFaces.get(i);
                int materialNumber = ((Number) mFace.getFieldValue("mat_nr")).intValue();
                boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
                int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
                int v2 = ((Number) mFace.getFieldValue("v2")).intValue();
                int v3 = ((Number) mFace.getFieldValue("v3")).intValue();
                int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
                int vertCount = v4 == 0 ? 3 : 4;
                // uvs always must be added wheater we have texture or not
                Map<String, List<Vector2f>> faceUVCoords = new HashMap<String, List<Vector2f>>();
                for (Entry<String, List<Vector2f>> entry : userUVGroups.entrySet()) {
                    List<Vector2f> uvCoordsForASingleFace = new ArrayList<Vector2f>(vertCount);
                    for (int j = 0; j < vertCount; ++j) {
                        uvCoordsForASingleFace.add(entry.getValue().get(i * 4 + j));
                    }
                    faceUVCoords.put(entry.getKey(), uvCoordsForASingleFace);
                }
                List<byte[]> vertexColors = null;
                if (verticesColors != null && verticesColors.size() > 0) {
                    vertexColors = new ArrayList<byte[]>(vertCount);
                    vertexColors.add(verticesColors.get(v1));
                    vertexColors.add(verticesColors.get(v2));
                    vertexColors.add(verticesColors.get(v3));
                    if (vertCount == 4) {
                        vertexColors.add(verticesColors.get(v4));
                    }
                }
                result.add(new Face(vertCount == 4 ? new Integer[] { v1, v2, v3, v4 } : new Integer[] { v1, v2, v3 }, smooth, materialNumber, faceUVCoords, vertexColors, temporalMesh));
            }
        }
    }
    LOGGER.log(Level.FINE, "Loaded {0} faces.", result.size());
    return result;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Pointer(com.jme3.scene.plugins.blender.file.Pointer) Vector2f(com.jme3.math.Vector2f) ArrayList(java.util.ArrayList) List(java.util.List) Structure(com.jme3.scene.plugins.blender.file.Structure)

Example 10 with Face

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

the class MeshHelper method loadUVCoordinates.

/**
     * The method loads the UV coordinates. The result is a map where the key is the user's UV set name and the values are UV coordinates.
     * But depending on the mesh type (triangle/quads or bmesh) the lists in the map have different meaning.
     * For bmesh they are enlisted just like they are stored in the blend file (in loops).
     * For traditional faces every 4 UV's should be assigned for a single face.
     * @param meshStructure
     *            the mesh structure
     * @return a map that sorts UV coordinates between different UV sets
     * @throws BlenderFileException
     *             an exception is thrown when problems with blend file occur
     */
@SuppressWarnings("unchecked")
public LinkedHashMap<String, List<Vector2f>> loadUVCoordinates(Structure meshStructure) throws BlenderFileException {
    LOGGER.log(Level.FINE, "Loading UV coordinates from mesh: {0}.", meshStructure.getName());
    LinkedHashMap<String, List<Vector2f>> result = new LinkedHashMap<String, List<Vector2f>>();
    if (this.isBMeshCompatible(meshStructure)) {
        // in this case the UV's are assigned to vertices (an array is the same length as the vertex array)
        Structure loopData = (Structure) meshStructure.getFieldValue("ldata");
        Pointer pLoopDataLayers = (Pointer) loopData.getFieldValue("layers");
        List<Structure> loopDataLayers = pLoopDataLayers.fetchData();
        for (Structure structure : loopDataLayers) {
            Pointer p = (Pointer) structure.getFieldValue("data");
            if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == MeshHelper.UV_DATA_LAYER_TYPE_BMESH) {
                String uvSetName = structure.getFieldValue("name").toString();
                List<Structure> uvsStructures = p.fetchData();
                List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
                for (Structure uvStructure : uvsStructures) {
                    DynamicArray<Number> loopUVS = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
                    uvs.add(new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue()));
                }
                result.put(uvSetName, uvs);
            }
        }
    } else {
        // in this case UV's are assigned to faces (the array has the same legnth as the faces count)
        Structure facesData = (Structure) meshStructure.getFieldValue("fdata");
        Pointer pFacesDataLayers = (Pointer) facesData.getFieldValue("layers");
        if (pFacesDataLayers.isNotNull()) {
            List<Structure> facesDataLayers = pFacesDataLayers.fetchData();
            for (Structure structure : facesDataLayers) {
                Pointer p = (Pointer) structure.getFieldValue("data");
                if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == MeshHelper.UV_DATA_LAYER_TYPE_FMESH) {
                    String uvSetName = structure.getFieldValue("name").toString();
                    List<Structure> uvsStructures = p.fetchData();
                    List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
                    for (Structure uvStructure : uvsStructures) {
                        DynamicArray<Number> mFaceUVs = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
                        uvs.add(new Vector2f(mFaceUVs.get(0).floatValue(), mFaceUVs.get(1).floatValue()));
                        uvs.add(new Vector2f(mFaceUVs.get(2).floatValue(), mFaceUVs.get(3).floatValue()));
                        uvs.add(new Vector2f(mFaceUVs.get(4).floatValue(), mFaceUVs.get(5).floatValue()));
                        uvs.add(new Vector2f(mFaceUVs.get(6).floatValue(), mFaceUVs.get(7).floatValue()));
                    }
                    result.put(uvSetName, uvs);
                }
            }
        }
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) Pointer(com.jme3.scene.plugins.blender.file.Pointer) LinkedHashMap(java.util.LinkedHashMap) Vector2f(com.jme3.math.Vector2f) DynamicArray(com.jme3.scene.plugins.blender.file.DynamicArray) ArrayList(java.util.ArrayList) List(java.util.List) Structure(com.jme3.scene.plugins.blender.file.Structure)

Aggregations

Vector3f (com.jme3.math.Vector3f)24 ArrayList (java.util.ArrayList)13 ColorRGBA (com.jme3.math.ColorRGBA)8 Face (com.jme3.scene.plugins.blender.meshes.Face)8 List (java.util.List)8 FloatBuffer (java.nio.FloatBuffer)7 Vector2f (com.jme3.math.Vector2f)6 Structure (com.jme3.scene.plugins.blender.file.Structure)6 VertexBuffer (com.jme3.scene.VertexBuffer)5 Pointer (com.jme3.scene.plugins.blender.file.Pointer)5 Edge (com.jme3.scene.plugins.blender.meshes.Edge)5 TextureCubeMap (com.jme3.texture.TextureCubeMap)5 BlenderFileException (com.jme3.scene.plugins.blender.file.BlenderFileException)4 ByteBuffer (java.nio.ByteBuffer)4 IndexBuffer (com.jme3.scene.mesh.IndexBuffer)3 DynamicArray (com.jme3.scene.plugins.blender.file.DynamicArray)3 Image (com.jme3.texture.Image)3 IOException (java.io.IOException)3 HashMap (java.util.HashMap)3 CubeMapWrapper (com.jme3.environment.util.CubeMapWrapper)2