Search in sources :

Example 16 with Curve

use of com.jme3.scene.shape.Curve 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 17 with Curve

use of com.jme3.scene.shape.Curve in project jmonkeyengine by jMonkeyEngine.

the class AnimationHelper method fromIpoStructure.

/**
     * This method creates an ipo object used for interpolation calculations.
     * 
     * @param ipoStructure
     *            the structure with ipo definition
     * @param blenderContext
     *            the blender context
     * @return the ipo object
     * @throws BlenderFileException
     *             this exception is thrown when the blender file is somehow
     *             corrupted
     */
public Ipo fromIpoStructure(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
    Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");
    // preparing bezier curves
    Ipo result = null;
    // IpoCurve
    List<Structure> curves = curvebase.evaluateListBase();
    if (curves.size() > 0) {
        BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
        int frame = 0;
        for (Structure curve : curves) {
            Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
            List<Structure> bezTriples = pBezTriple.fetchData();
            int type = ((Number) curve.getFieldValue("adrcode")).intValue();
            bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
        }
        curves.clear();
        result = new Ipo(bezierCurves, fixUpAxis, blenderContext.getBlenderVersion());
        Long ipoOma = ipoStructure.getOldMemoryAddress();
        blenderContext.addLoadedFeatures(ipoOma, LoadedDataType.STRUCTURE, ipoStructure);
        blenderContext.addLoadedFeatures(ipoOma, LoadedDataType.FEATURE, result);
    }
    return result;
}
Also used : ConstIpo(com.jme3.scene.plugins.blender.animations.Ipo.ConstIpo) Pointer(com.jme3.scene.plugins.blender.file.Pointer) Structure(com.jme3.scene.plugins.blender.file.Structure) BezierCurve(com.jme3.scene.plugins.blender.curves.BezierCurve)

Example 18 with Curve

use of com.jme3.scene.shape.Curve in project jmonkeyengine by jMonkeyEngine.

the class Ipo method calculateTrack.

/**
     * This method calculates the value of the curves as a bone track between
     * the specified frames.
     * 
     * @param targetIndex
     *            the index of the target for which the method calculates the
     *            tracks IMPORTANT! Aet to -1 (or any negative number) if you
     *            want to load spatial animation.
     * @param localTranslation
     *            the local translation of the object/bone that will be animated by
     *            the track
     * @param localRotation
     *            the local rotation of the object/bone that will be animated by
     *            the track
     * @param localScale
     *            the local scale of the object/bone that will be animated by
     *            the track
     * @param startFrame
     *            the first frame of tracks (inclusive)
     * @param stopFrame
     *            the last frame of the tracks (inclusive)
     * @param fps
     *            frame rate (frames per second)
     * @param spatialTrack
     *            this flag indicates if the track belongs to a spatial or to a
     *            bone; the difference is important because it appears that bones
     *            in blender have the same type of coordinate system (Y as UP)
     *            as jme while other features have different one (Z is UP)
     * @return bone track for the specified bone
     */
public Track calculateTrack(int targetIndex, BoneContext boneContext, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) {
    if (calculatedTrack == null) {
        // preparing data for track
        int framesAmount = stopFrame - startFrame;
        float timeBetweenFrames = 1.0f / fps;
        float[] times = new float[framesAmount + 1];
        Vector3f[] translations = new Vector3f[framesAmount + 1];
        float[] translation = new float[3];
        Quaternion[] rotations = new Quaternion[framesAmount + 1];
        float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW() };
        float[] eulerRotation = localRotation.toAngles(null);
        Vector3f[] scales = new Vector3f[framesAmount + 1];
        float[] scale = new float[] { localScale.x, localScale.y, localScale.z };
        float degreeToRadiansFactor = 1;
        if (blenderVersion < 250) {
            // in blender earlier than 2.50 the values are stored in degrees
            // the values in blender are divided by 10, so we need to mult it here
            degreeToRadiansFactor *= FastMath.DEG_TO_RAD * 10;
        }
        int yIndex = 1, zIndex = 2;
        boolean swapAxes = spatialTrack && fixUpAxis;
        if (swapAxes) {
            yIndex = 2;
            zIndex = 1;
        }
        boolean eulerRotationUsed = false, queternionRotationUsed = false;
        // calculating track data
        for (int frame = startFrame; frame <= stopFrame; ++frame) {
            boolean translationSet = false;
            translation[0] = translation[1] = translation[2] = 0;
            int index = frame - startFrame;
            // start + (frame - 1) * timeBetweenFrames;
            times[index] = index * timeBetweenFrames;
            for (int j = 0; j < bezierCurves.length; ++j) {
                double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
                switch(bezierCurves[j].getType()) {
                    // LOCATION
                    case AC_LOC_X:
                        translation[0] = (float) value;
                        translationSet = true;
                        break;
                    case AC_LOC_Y:
                        if (swapAxes && value != 0) {
                            value = -value;
                        }
                        translation[yIndex] = (float) value;
                        translationSet = true;
                        break;
                    case AC_LOC_Z:
                        translation[zIndex] = (float) value;
                        translationSet = true;
                        break;
                    // EULER ROTATION
                    case OB_ROT_X:
                        eulerRotationUsed = true;
                        eulerRotation[0] = (float) value * degreeToRadiansFactor;
                        break;
                    case OB_ROT_Y:
                        eulerRotationUsed = true;
                        if (swapAxes && value != 0) {
                            value = -value;
                        }
                        eulerRotation[yIndex] = (float) value * degreeToRadiansFactor;
                        break;
                    case OB_ROT_Z:
                        eulerRotationUsed = true;
                        eulerRotation[zIndex] = (float) value * degreeToRadiansFactor;
                        break;
                    // SIZE
                    case AC_SIZE_X:
                        scale[0] = (float) value;
                        break;
                    case AC_SIZE_Y:
                        scale[yIndex] = (float) value;
                        break;
                    case AC_SIZE_Z:
                        scale[zIndex] = (float) value;
                        break;
                    // QUATERNION ROTATION (used with bone animation)
                    case AC_QUAT_W:
                        queternionRotationUsed = true;
                        quaternionRotation[3] = (float) value;
                        break;
                    case AC_QUAT_X:
                        queternionRotationUsed = true;
                        quaternionRotation[0] = (float) value;
                        break;
                    case AC_QUAT_Y:
                        queternionRotationUsed = true;
                        if (swapAxes && value != 0) {
                            value = -value;
                        }
                        quaternionRotation[yIndex] = (float) value;
                        break;
                    case AC_QUAT_Z:
                        quaternionRotation[zIndex] = (float) value;
                        break;
                    default:
                        LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType());
                }
            }
            if (translationSet) {
                translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
            } else {
                translations[index] = new Vector3f();
            }
            if (boneContext != null) {
                if (boneContext.getBone().getParent() == null && boneContext.is(BoneContext.NO_LOCAL_LOCATION)) {
                    float temp = translations[index].z;
                    translations[index].z = -translations[index].y;
                    translations[index].y = temp;
                }
            }
            if (queternionRotationUsed) {
                rotations[index] = new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
            } else {
                rotations[index] = new Quaternion().fromAngles(eulerRotation);
            }
            scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
        }
        if (spatialTrack) {
            calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
        } else {
            calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
        }
        if (queternionRotationUsed && eulerRotationUsed) {
            LOGGER.warning("Animation uses both euler and quaternion tracks for rotations. Quaternion rotation is applied. Make sure that this is what you wanted!");
        }
    }
    return calculatedTrack;
}
Also used : SpatialTrack(com.jme3.animation.SpatialTrack) BoneTrack(com.jme3.animation.BoneTrack) Quaternion(com.jme3.math.Quaternion) Vector3f(com.jme3.math.Vector3f)

Example 19 with Curve

use of com.jme3.scene.shape.Curve in project jmonkeyengine by jMonkeyEngine.

the class BezierCurve method getControlPoints.

/**
     * This method returns a list of control points for this curve.
     * @return a list of control points for this curve.
     */
public List<Vector3f> getControlPoints() {
    List<Vector3f> controlPoints = new ArrayList<Vector3f>(bezierPoints.length * 3);
    for (int i = 0; i < bezierPoints.length; ++i) {
        controlPoints.add(new Vector3f((float) bezierPoints[i][0][0], (float) bezierPoints[i][0][1], (float) bezierPoints[i][0][2]));
        controlPoints.add(new Vector3f((float) bezierPoints[i][1][0], (float) bezierPoints[i][1][1], (float) bezierPoints[i][1][2]));
        controlPoints.add(new Vector3f((float) bezierPoints[i][2][0], (float) bezierPoints[i][2][1], (float) bezierPoints[i][2][2]));
    }
    return controlPoints;
}
Also used : Vector3f(com.jme3.math.Vector3f) ArrayList(java.util.ArrayList)

Example 20 with Curve

use of com.jme3.scene.shape.Curve in project jmonkeyengine by jMonkeyEngine.

the class CurvesHelper method transformBevel.

/**
     * The method transforms the bevel along the curve.
     * 
     * @param bevel
     *            the bevel to be transformed
     * @param prevPos
     *            previous curve point
     * @param currPos
     *            current curve point (here the center of the new bevel will be
     *            set)
     * @param nextPos
     *            next curve point
     * @return points of transformed bevel
     */
protected Vector3f[] transformBevel(Vector3f[] bevel, Vector3f prevPos, Vector3f currPos, Vector3f nextPos) {
    bevel = bevel.clone();
    // currPos and directionVector define the line in 3D space
    Vector3f directionVector = prevPos != null ? currPos.subtract(prevPos) : nextPos.subtract(currPos);
    directionVector.normalizeLocal();
    // plane is described by equation: Ax + By + Cz + D = 0 where planeNormal = [A, B, C] and D = -(Ax + By + Cz)
    Vector3f planeNormal = null;
    if (prevPos != null) {
        planeNormal = currPos.subtract(prevPos).normalizeLocal();
        if (nextPos != null) {
            planeNormal.addLocal(nextPos.subtract(currPos).normalizeLocal()).normalizeLocal();
        }
    } else {
        planeNormal = nextPos.subtract(currPos).normalizeLocal();
    }
    // D = -(Ax + By + Cz)
    float D = -planeNormal.dot(currPos);
    // now we need to compute paralell cast of each bevel point on the plane, the leading line is already known
    // parametric equation of a line: x = px + vx * t; y = py + vy * t; z = pz + vz * t
    // where p = currPos and v = directionVector
    // using x, y and z in plane equation we get value of 't' that will allow us to compute the point where plane and line cross
    float temp = planeNormal.dot(directionVector);
    for (int i = 0; i < bevel.length; ++i) {
        float t = -(planeNormal.dot(bevel[i]) + D) / temp;
        if (fixUpAxis) {
            bevel[i] = new Vector3f(bevel[i].x + directionVector.x * t, bevel[i].y + directionVector.y * t, bevel[i].z + directionVector.z * t);
        } else {
            bevel[i] = new Vector3f(bevel[i].x + directionVector.x * t, -bevel[i].z + directionVector.z * t, bevel[i].y + directionVector.y * t);
        }
    }
    return bevel;
}
Also used : Vector3f(com.jme3.math.Vector3f)

Aggregations

Vector3f (com.jme3.math.Vector3f)14 Pointer (com.jme3.scene.plugins.blender.file.Pointer)8 Structure (com.jme3.scene.plugins.blender.file.Structure)6 Curve (com.jme3.scene.shape.Curve)5 ArrayList (java.util.ArrayList)4 Quaternion (com.jme3.math.Quaternion)3 Spline (com.jme3.math.Spline)3 Geometry (com.jme3.scene.Geometry)3 FileBlockHeader (com.jme3.scene.plugins.blender.file.FileBlockHeader)3 Face (com.jme3.scene.plugins.blender.meshes.Face)3 FloatBuffer (java.nio.FloatBuffer)3 BoneTrack (com.jme3.animation.BoneTrack)2 SpatialTrack (com.jme3.animation.SpatialTrack)2 Material (com.jme3.material.Material)2 Node (com.jme3.scene.Node)2 BlenderInputStream (com.jme3.scene.plugins.blender.file.BlenderInputStream)2 DynamicArray (com.jme3.scene.plugins.blender.file.DynamicArray)2 MeshHelper (com.jme3.scene.plugins.blender.meshes.MeshHelper)2 TemporalMesh (com.jme3.scene.plugins.blender.meshes.TemporalMesh)2 BoundingBox (com.jme3.bounding.BoundingBox)1