Search in sources :

Example 56 with Face

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

the class OBJLoader method constructMesh.

protected Mesh constructMesh(ArrayList<Face> faceList) {
    Mesh m = new Mesh();
    m.setMode(Mode.Triangles);
    boolean hasTexCoord = false;
    boolean hasNormals = false;
    ArrayList<Face> newFaces = new ArrayList<Face>(faceList.size());
    for (int i = 0; i < faceList.size(); i++) {
        Face f = faceList.get(i);
        for (Vertex v : f.verticies) {
            findVertexIndex(v);
            if (!hasTexCoord && v.vt != null)
                hasTexCoord = true;
            if (!hasNormals && v.vn != null)
                hasNormals = true;
        }
        if (f.verticies.length == 4) {
            Face[] t = quadToTriangle(f);
            newFaces.add(t[0]);
            newFaces.add(t[1]);
        } else {
            newFaces.add(f);
        }
    }
    FloatBuffer posBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 3);
    FloatBuffer normBuf = null;
    FloatBuffer tcBuf = null;
    if (hasNormals) {
        normBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 3);
        m.setBuffer(VertexBuffer.Type.Normal, 3, normBuf);
    }
    if (hasTexCoord) {
        tcBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 2);
        m.setBuffer(VertexBuffer.Type.TexCoord, 2, tcBuf);
    }
    IndexBuffer indexBuf = null;
    if (vertIndexMap.size() >= 65536) {
        // too many verticies: use intbuffer instead of shortbuffer
        IntBuffer ib = BufferUtils.createIntBuffer(newFaces.size() * 3);
        m.setBuffer(VertexBuffer.Type.Index, 3, ib);
        indexBuf = new IndexIntBuffer(ib);
    } else {
        ShortBuffer sb = BufferUtils.createShortBuffer(newFaces.size() * 3);
        m.setBuffer(VertexBuffer.Type.Index, 3, sb);
        indexBuf = new IndexShortBuffer(sb);
    }
    int numFaces = newFaces.size();
    for (int i = 0; i < numFaces; i++) {
        Face f = newFaces.get(i);
        if (f.verticies.length != 3)
            continue;
        Vertex v0 = f.verticies[0];
        Vertex v1 = f.verticies[1];
        Vertex v2 = f.verticies[2];
        posBuf.position(v0.index * 3);
        posBuf.put(v0.v.x).put(v0.v.y).put(v0.v.z);
        posBuf.position(v1.index * 3);
        posBuf.put(v1.v.x).put(v1.v.y).put(v1.v.z);
        posBuf.position(v2.index * 3);
        posBuf.put(v2.v.x).put(v2.v.y).put(v2.v.z);
        if (normBuf != null) {
            if (v0.vn != null) {
                normBuf.position(v0.index * 3);
                normBuf.put(v0.vn.x).put(v0.vn.y).put(v0.vn.z);
                normBuf.position(v1.index * 3);
                normBuf.put(v1.vn.x).put(v1.vn.y).put(v1.vn.z);
                normBuf.position(v2.index * 3);
                normBuf.put(v2.vn.x).put(v2.vn.y).put(v2.vn.z);
            }
        }
        if (tcBuf != null) {
            if (v0.vt != null) {
                tcBuf.position(v0.index * 2);
                tcBuf.put(v0.vt.x).put(v0.vt.y);
                tcBuf.position(v1.index * 2);
                tcBuf.put(v1.vt.x).put(v1.vt.y);
                tcBuf.position(v2.index * 2);
                tcBuf.put(v2.vt.x).put(v2.vt.y);
            }
        }
        // current face * 3 = current index
        int index = i * 3;
        indexBuf.put(index, v0.index);
        indexBuf.put(index + 1, v1.index);
        indexBuf.put(index + 2, v2.index);
    }
    m.setBuffer(VertexBuffer.Type.Position, 3, posBuf);
    // index buffer and others were set on creation
    m.setStatic();
    m.updateBound();
    m.updateCounts();
    //m.setInterleaved();
    // clear data generated face statements
    // to prepare for next mesh
    vertIndexMap.clear();
    indexVertMap.clear();
    curIndex = 0;
    return m;
}
Also used : FloatBuffer(java.nio.FloatBuffer) IndexBuffer(com.jme3.scene.mesh.IndexBuffer) IndexShortBuffer(com.jme3.scene.mesh.IndexShortBuffer) IndexIntBuffer(com.jme3.scene.mesh.IndexIntBuffer) IndexIntBuffer(com.jme3.scene.mesh.IndexIntBuffer) IntBuffer(java.nio.IntBuffer) IndexShortBuffer(com.jme3.scene.mesh.IndexShortBuffer) ShortBuffer(java.nio.ShortBuffer)

Example 57 with Face

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

the class LodGenerator method computeEdgeCollapseCost.

float computeEdgeCollapseCost(Vertex src, Edge dstEdge) {
    // This is based on Ogre's collapse cost calculation algorithm.
    Vertex dest = dstEdge.destination;
    // then this would destroy the shape, so don't do this
    if (src.triangles.size() == 1 && dest.triangles.size() == 1) {
        return NEVER_COLLAPSE_COST;
    }
    // Look for a face normal changing by > 90 degrees
    for (Triangle triangle : src.triangles) {
        // Ignore the deleted faces (those including src & dest)
        if (!triangle.hasVertex(dest)) {
            // Test the new face normal
            Vertex pv0, pv1, pv2;
            // Replace src with dest wherever it is
            pv0 = (triangle.vertex[0] == src) ? dest : triangle.vertex[0];
            pv1 = (triangle.vertex[1] == src) ? dest : triangle.vertex[1];
            pv2 = (triangle.vertex[2] == src) ? dest : triangle.vertex[2];
            // Cross-product 2 edges
            tmpV1.set(pv1.position).subtractLocal(pv0.position);
            tmpV2.set(pv2.position).subtractLocal(pv1.position);
            //computing the normal
            Vector3f newNormal = tmpV1.crossLocal(tmpV2);
            newNormal.normalizeLocal();
            // If < 0 then more than 90 degree difference
            if (newNormal.dot(triangle.normal) < 0.0f) {
                // Don't do it!
                return NEVER_COLLAPSE_COST;
            }
        }
    }
    float cost;
    // If we're looking at a border vertex
    if (isBorderVertex(src)) {
        if (dstEdge.refCount > 1) {
            // src is on a border, but the src-dest edge has more than one tri on it
            // So it must be collapsing inwards
            // Mark as very high-value cost
            // curvature = 1.0f;
            cost = 1.0f;
        } else {
            // Collapsing ALONG a border
            // We can't use curvature to measure the effect on the model
            // Instead, see what effect it has on 'pulling' the other border edges
            // The more colinear, the less effect it will have
            // So measure the 'kinkiness' (for want of a better term)
            // Find the only triangle using this edge.
            // PMTriangle* triangle = findSideTriangle(src, dst);
            cost = 0.0f;
            Vector3f collapseEdge = tmpV1.set(src.position).subtractLocal(dest.position);
            collapseEdge.normalizeLocal();
            for (Edge edge : src.edges) {
                Vertex neighbor = edge.destination;
                //reference check intended
                if (neighbor != dest && edge.refCount == 1) {
                    Vector3f otherBorderEdge = tmpV2.set(src.position).subtractLocal(neighbor.position);
                    otherBorderEdge.normalizeLocal();
                    // This time, the nearer the dot is to -1, the better, because that means
                    // the edges are opposite each other, therefore less kinkiness
                    // Scale into [0..1]
                    float kinkiness = (otherBorderEdge.dot(collapseEdge) + 1.002f) * 0.5f;
                    cost = Math.max(cost, kinkiness);
                }
            }
        }
    } else {
        // not a border
        // Standard inner vertex
        // Calculate curvature
        // use the triangle facing most away from the sides
        // to determine our curvature term
        // Iterate over src's faces again
        cost = 0.001f;
        for (Triangle triangle : src.triangles) {
            // curve for face i and closer side to it
            float mincurv = 1.0f;
            for (Triangle triangle2 : src.triangles) {
                if (triangle2.hasVertex(dest)) {
                    // Dot product of face normal gives a good delta angle
                    float dotprod = triangle.normal.dot(triangle2.normal);
                    // NB we do (1-..) to invert curvature where 1 is high curvature [0..1]
                    // Whilst dot product is high when angle difference is low
                    mincurv = Math.min(mincurv, (1.002f - dotprod) * 0.5f);
                }
            }
            cost = Math.max(cost, mincurv);
        }
    }
    // check for texture seam ripping
    if (src.isSeam) {
        if (!dest.isSeam) {
            cost += meshBoundingSphereRadius;
        } else {
            cost += meshBoundingSphereRadius * 0.5;
        }
    }
    return cost * src.position.distanceSquared(dest.position);
}
Also used : Vector3f(com.jme3.math.Vector3f)

Example 58 with Face

use of com.jme3.scene.plugins.blender.meshes.Face in project chordatlas by twak.

the class GreebleSkel method createMesh.

public void createMesh(Output output) {
    float[] roofColor = new float[] { 0.3f, 0.3f, 0.3f, 1 }, wallColor = new float[] { 228 / 255f, 223 / 255f, 206 / 255f, 1.0f };
    if (output.faces == null)
        return;
    double bestWallArea = 0, bestRoofArea = 0;
    for (Face f : output.faces.values()) {
        double area = Loopz.area3(f.getLoopL());
        Tag t = getTag(f.profile, RoofTag.class);
        if (t != null && area > bestRoofArea && ((RoofTag) t).color != null) {
            roofColor = ((RoofTag) t).color;
            bestRoofArea = area;
        }
        t = getTag(f.profile, WallTag.class);
        if (t != null && area > bestWallArea && ((WallTag) t).color != null) {
            wallColor = ((WallTag) t).color;
            bestWallArea = area;
        }
    }
    greebleGrid = new GreebleGrid(tweed, mbs = new MMeshBuilderCache());
    output.addNonSkeletonSharedEdges(new RoofTag(roofColor));
    edges(output, roofColor);
    for (List<Face> chain : Campz.findChains(output)) {
        // for ( Face f : output.faces.values() )
        // mbs.get(roofColor).add3d( Loopz.insertInnerEdges( f.getLoopL() ), zToYup );
        Optional<Tag> opt = chain.stream().flatMap(f -> f.profile.stream()).filter(tag -> tag instanceof WallTag).findAny();
        WallTag wt = null;
        Set<QuadF> features = new HashSet<>();
        MiniFacade mf = null;
        if (opt.isPresent() && (wt = (WallTag) opt.get()).miniFacade != null) {
            MiniFacade mf2 = new MiniFacade(wt.miniFacade);
            Line facadeLine;
            {
                Edge e = chain.get(0).edge;
                // we might rotate the facade to apply a set of features to a different side of the building.
                facadeLine = new Line(e.end.x, e.end.y, e.start.x, e.start.y);
            }
            if (TweedSettings.settings.snapFacadeWidth) {
                // move/scale mf horizontally from mean-image-location to mesh-facade-location
                double[] meshSE = findSE(wt.miniFacade, facadeLine, chain);
                mf2.scaleX(meshSE[0], meshSE[1]);
            }
            // find window locations in 3 space
            mf2.rects.values().stream().flatMap(f -> f.stream()).map(r -> new QuadF(r, facadeLine)).forEach(q -> features.add(q));
            mf = mf2;
        }
        for (Face f : chain) {
            face(f, mf, features, roofColor, wallColor);
        }
        for (QuadF w : features) if ((w.original.f == Feature.WINDOW || w.original.f == Feature.SHOP) && w.foundAll()) {
            greebleGrid.createDormerWindow(w, mbs.WOOD, mbs.GLASS, (float) wt.sillDepth, (float) wt.sillHeight, (float) wt.corniceHeight, 0.6, 0.9);
        }
        // for ( String mName : mbs.cache.keySet() )
        // for (float[] mCol : mbs.cache.get( mName ).keySet() )
        // node.attachChild( mb2Geom( output, chain, mName, mCol ) );
        greebleGrid.attachAll(node, chain, output, new ClickMe() {

            @Override
            public void clicked(Object data) {
                try {
                    SwingUtilities.invokeAndWait(new Runnable() {

                        @Override
                        public void run() {
                            selected(output, node, findSuperEdge(output, chain));
                        }
                    });
                } catch (Throwable th) {
                    th.printStackTrace();
                }
            }
        });
    }
}
Also used : LinearForm3D(org.twak.utils.geom.LinearForm3D) PlanSkeleton(org.twak.siteplan.campskeleton.PlanSkeleton) Matrix4d(javax.vecmath.Matrix4d) ClickMe(org.twak.tweed.ClickMe) Tag(org.twak.camp.Tag) Vector3d(javax.vecmath.Vector3d) Bar(org.twak.camp.ui.Bar) Tweed(org.twak.tweed.Tweed) ArrayList(java.util.ArrayList) TweedSettings(org.twak.tweed.TweedSettings) HashSet(java.util.HashSet) SETag(org.twak.tweed.gen.skel.SETag) Loop(org.twak.utils.collections.Loop) Node(com.jme3.scene.Node) SwingUtilities(javax.swing.SwingUtilities) Pointz(org.twak.tweed.gen.Pointz) Mathz(org.twak.utils.Mathz) SuperEdge(org.twak.tweed.gen.SuperEdge) Point3d(javax.vecmath.Point3d) ColumnProperties(org.twak.siteplan.campskeleton.PlanSkeleton.ColumnProperties) LoopL(org.twak.utils.collections.LoopL) Iterator(java.util.Iterator) Output(org.twak.camp.Output) Edge(org.twak.camp.Edge) Line(org.twak.utils.Line) Set(java.util.Set) MeshBuilder(org.twak.siteplan.jme.MeshBuilder) LinearForm(org.twak.utils.geom.LinearForm) Collectors(java.util.stream.Collectors) LPoint2d(org.twak.viewTrace.facades.GreebleHelper.LPoint2d) Loopz(org.twak.utils.collections.Loopz) Point2d(javax.vecmath.Point2d) LPoint3d(org.twak.viewTrace.facades.GreebleHelper.LPoint3d) List(java.util.List) Loopable(org.twak.utils.collections.Loopable) DRectangle(org.twak.utils.geom.DRectangle) Optional(java.util.Optional) Face(org.twak.camp.Output.Face) Feature(org.twak.viewTrace.facades.MiniFacade.Feature) ClickMe(org.twak.tweed.ClickMe) Line(org.twak.utils.Line) Tag(org.twak.camp.Tag) SETag(org.twak.tweed.gen.skel.SETag) Face(org.twak.camp.Output.Face) SuperEdge(org.twak.tweed.gen.SuperEdge) Edge(org.twak.camp.Edge) HashSet(java.util.HashSet)

Example 59 with Face

use of com.jme3.scene.plugins.blender.meshes.Face in project chordatlas by twak.

the class ProfileGen method findMegaFaces.

private List<MegaFacade> findMegaFaces(double delta) {
    SliceParameters P = new SliceParameters(SLICE_SCALE);
    List<LineAtHeight> lines = new ArrayList();
    Map<Integer, LineSoup> slices = new HashMap<>();
    for (int hi = 0; getHeight(hi) < extent[3]; hi++) {
        int _i = hi;
        boolean error;
        int count = 0;
        do {
            error = false;
            try {
                LineSoup soup = new LineSoup(ObjSlice.sliceTri(blockGen.getCroppedMesh(), getHeight(hi), majorAxis));
                FindLines foundLines = new FindLines(soup, TweedSettings.settings.useGis ? gisBias : null, -1, null, P);
                foundLines.result.all.stream().forEach(x -> lines.add(new LineAtHeight(_i, delta, x, foundLines.result.all)));
                slices.put(hi, foundLines.result);
            } catch (Throwable th) {
                th.printStackTrace();
                error = true;
            }
        } while (error && count++ < 10);
    }
    Collections.sort(lines, new LAHComparator());
    // new Plot(lines.stream().map (lah -> lah.line).collect(Collectors.toList() ), gis);
    faces = new ArrayList<>();
    while (!lines.isEmpty()) {
        System.out.println("clustering megafacdes " + lines.size());
        // longest line
        LineAtHeight start = lines.get(0);
        lines.remove(start);
        MegaFacade face = new MegaFacade(start);
        Set<LineAtHeight> toProcess = new HashSet<>();
        toProcess.add(start);
        while (!toProcess.isEmpty()) {
            LineAtHeight lah = toProcess.iterator().next();
            toProcess.remove(lah);
            for (int _pmDelta : new int[] { -2, -1, 1, 2 }) {
                int hi = lah.height + _pmDelta;
                LineSoup ls = slices.get(hi);
                if (ls != null) {
                    for (Line l : ls.all) {
                        double lps = start.line.findPPram(l.start), lpe = start.line.findPPram(l.end);
                        double overlap = 0;
                        if (lpe < lps)
                            overlap = 0;
                        else if (lps > face.minP && lpe < face.maxP || lps < face.minP && lpe > face.maxP)
                            overlap = 1;
                        else if (lps < face.minP && lpe > face.minP)
                            overlap = (lpe - face.minP) / (lpe - lps);
                        else if (lps < face.maxP && lpe > face.maxP)
                            overlap = (face.maxP - lps) / (lpe - lps);
                        double angle = l.absAngle(start.line);
                        if (overlap > 0.8 && angle < 0.3 || overlap > 0.5 && /* 0.1 for aggressive clustering */
                        angle < 0.1) {
                            // if (overlap > 0.1 && angle < 0.5 ) {
                            if (l.distance(lah.line) < delta * TweedSettings.settings.megafacacadeClusterGradient) {
                                LineAtHeight toProc = new LineAtHeight(hi, l);
                                if (lines.contains(toProc)) {
                                    toProcess.add(toProc);
                                    face.put(hi, l);
                                    lines.remove(toProc);
                                    // bit strange: depends on the processing order of the set
                                    face.minP = Mathz.min(face.minP, lps);
                                    face.maxP = Mathz.max(face.maxP, lpe);
                                }
                            }
                        }
                    }
                }
            }
        }
        if (face.values().stream().flatMap(x -> x.stream()).count() > 5)
            faces.add(face);
        else
            System.out.println("skipping small megafacade");
    }
    Collections.sort(faces);
    processMegaFaces();
    return faces;
}
Also used : FindLines(org.twak.viewTrace.FindLines) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) CullHint(com.jme3.scene.Spatial.CullHint) Line(org.twak.utils.Line) SuperLine(org.twak.viewTrace.SuperLine) SliceParameters(org.twak.viewTrace.SliceParameters) LineSoup(org.twak.viewTrace.LineSoup) HashSet(java.util.HashSet)

Aggregations

Vector3f (com.jme3.math.Vector3f)26 ArrayList (java.util.ArrayList)19 List (java.util.List)13 ColorRGBA (com.jme3.math.ColorRGBA)10 FloatBuffer (java.nio.FloatBuffer)9 Vector2f (com.jme3.math.Vector2f)8 Face (com.jme3.scene.plugins.blender.meshes.Face)8 HashMap (java.util.HashMap)8 HashSet (java.util.HashSet)8 VertexBuffer (com.jme3.scene.VertexBuffer)7 Structure (com.jme3.scene.plugins.blender.file.Structure)6 Material (com.jme3.material.Material)5 Node (com.jme3.scene.Node)5 IndexBuffer (com.jme3.scene.mesh.IndexBuffer)5 Pointer (com.jme3.scene.plugins.blender.file.Pointer)5 Edge (com.jme3.scene.plugins.blender.meshes.Edge)5 Line (org.twak.utils.Line)5 Geometry (com.jme3.scene.Geometry)4 TextureCubeMap (com.jme3.texture.TextureCubeMap)4 File (java.io.File)4