extrusion.java

来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 389 行

JAVA
389
字号
/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jme.scene.shape;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Line;
import com.jme.scene.TriMesh;
import com.jme.util.geom.BufferUtils;

/**
 * An extrusion of a 2D object ({@link Line}) along a path (List of Vector3f).
 * Either a convenience constructor can be used or the {@link #updateGeometry}
 * method. It is also capable of doing a cubic spline interpolation for a list
 * of supporting points
 * 
 * @author Irrisor
 */
public class Extrusion extends TriMesh {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    /**
     * Default Constructor. Creates an empty Extrusion.
     * 
     * @see #updateGeometry(Line, List, Vector3f)
     * @see #updateGeometry(Line, List, boolean, Vector3f)
     * @see #updateGeometry(Line, List, int, Vector3f)
     * @see #updateGeometry(Line, List, int, boolean, Vector3f)
     */
    public Extrusion() {
    }

    /**
     * Creates an empty named Extrusion.
     * 
     * @param name
     *            name
     * @see #updateGeometry(Line, List, Vector3f)
     * @see #updateGeometry(Line, List, boolean, Vector3f)
     * @see #updateGeometry(Line, List, int, Vector3f)
     * @see #updateGeometry(Line, List, int, boolean, Vector3f)
     */
    public Extrusion(String name) {
        super(name);
    }

    /**
     * Convenience constructor. Calls
     * {@link #updateGeometry(Line, List, Vector3f)}.
     * 
     * @param shape
     *            see {@link #updateGeometry(Line, List, Vector3f)}
     * @param path
     *            see {@link #updateGeometry(Line, List, Vector3f)}
     * @param up
     *            up vector
     */
    public Extrusion(Line shape, List<Vector3f> path, Vector3f up) {
        updateGeometry(shape, path, up);
    }

    /**
     * Convenience constructor. Sets the name and calls
     * {@link #updateGeometry(Line, List, Vector3f)}.
     * 
     * @param name
     *            name
     * @param shape
     *            see {@link #updateGeometry(Line, List, Vector3f)}
     * @param path
     *            see {@link #updateGeometry(Line, List, Vector3f)}
     * @param up
     *            up vector
     */
    public Extrusion(String name, Line shape, List<Vector3f> path, Vector3f up) {
        super(name);
        updateGeometry(shape, path, up);
    }

    /**
     * Update vertex, color, index and texture buffers (0) to contain an
     * extrusion of shape along path.
     * 
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param path
     *            a list of vectors that describe the path the shape should be
     *            extruded
     * @param up
     *            up vector
     */
    public void updateGeometry(Line shape, List<Vector3f> path, Vector3f up) {
        updateGeometry(shape, path, false, up);
    }

    /**
     * Update vertex, color, index and texture buffers (0) to contain an
     * extrusion of shape along path.
     * 
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param path
     *            a list of vectors that describe the path the shape should be
     *            extruded
     * @param closed
     *            true to connect first and last point
     * @param up
     *            up vector
     */
    public void updateGeometry(Line shape, List<Vector3f> path, boolean closed,
            Vector3f up) {
        FloatBuffer shapeBuffer = shape.getVertexBuffer();
        FloatBuffer shapeNormalBuffer = shape.getNormalBuffer();

        FloatBuffer vertices;
        FloatBuffer normals;
        int numVertices = path.size() * shapeBuffer.limit();
        if (getVertexBuffer() != null
                && getVertexBuffer().limit() == numVertices) {
            vertices = getVertexBuffer();
            normals = getNormalBuffer();
            vertices.rewind();
            normals.rewind();
        } else {
            vertices = BufferUtils.createFloatBuffer(numVertices);
            normals = BufferUtils.createFloatBuffer(numVertices);
        }
        int numIndices = (path.size() - 1) * 2 * shapeBuffer.limit();
        IntBuffer indices;
        if (getIndexBuffer() != null && getIndexBuffer().limit() == numIndices) {
            indices = getIndexBuffer();
            indices.rewind();
        } else {
            indices = BufferUtils.createIntBuffer(numIndices);
        }

        int shapeVertices = shapeBuffer.limit() / 3;
        Vector3f vector = new Vector3f();
        Vector3f direction = new Vector3f();
        Quaternion rotation = new Quaternion();
        for (int i = 0; i < path.size(); i++) {
            Vector3f point = path.get(i);
            shapeBuffer.rewind();
            shapeNormalBuffer.rewind();
            int shapeVertice = 0;
            do {

                Vector3f nextPoint = i < path.size() - 1 ? path.get(i + 1)
                        : closed ? path.get(0) : null;
                Vector3f lastPoint = i > 0 ? path.get(i - 1) : null;
                if (nextPoint != null) {
                    direction.set(nextPoint).subtractLocal(point);
                } else {
                    direction.set(point).subtractLocal(lastPoint);
                }
                rotation.lookAt(direction, up);

                vector.set(shapeNormalBuffer.get(), shapeNormalBuffer.get(),
                        shapeNormalBuffer.get());
                rotation.multLocal(vector);
                normals.put(vector.x);
                normals.put(vector.y);
                normals.put(vector.z);

                vector.set(shapeBuffer.get(), shapeBuffer.get(), shapeBuffer
                        .get());
                rotation.multLocal(vector);
                vector.addLocal(point);
                vertices.put(vector.x);
                vertices.put(vector.y);
                vertices.put(vector.z);

                if ((shapeVertice & 1) == 0) {
                    if (i < path.size() - 1) {
                        indices.put(i * shapeVertices + shapeVertice);
                        indices.put(i * shapeVertices + shapeVertice + 1);
                        indices.put((i + 1) * shapeVertices + shapeVertice);

                        indices.put((i + 1) * shapeVertices + shapeVertice + 1);
                        indices.put((i + 1) * shapeVertices + shapeVertice);
                        indices.put(i * shapeVertices + shapeVertice + 1);
                    } else if (closed) {
                        indices.put(i * shapeVertices + shapeVertice);
                        indices.put(i * shapeVertices + shapeVertice + 1);
                        indices.put(0 + shapeVertice);

                        indices.put(0 + shapeVertice + 1);
                        indices.put(0 + shapeVertice);
                        indices.put(i * shapeVertices + shapeVertice + 1);
                    }
                }
                shapeVertice++;
            } while (shapeBuffer.hasRemaining());
        }

        setVertexBuffer(vertices);
        setNormalBuffer(normals);
        setIndexBuffer(indices);
    }

    /**
     * Performs cubic spline interpolation to find a path through the supporting
     * points where the second derivative is zero. Then calls
     * {@link #updateGeometry(Line, List, Vector3f)} with this path.
     * 
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param points
     *            a list of supporting points for the spline interpolation
     * @param segments
     *            number of resulting path segments per supporting point
     * @param up
     *            up vector
     */
    public void updateGeometry(Line shape, List<Vector3f> points, int segments,
            Vector3f up) {
        updateGeometry(shape, points, segments, false, up);
    }

    /**
     * Performs cubic spline interpolation to find a path through the supporting
     * points where the second derivative is zero. Then calls
     * {@link #updateGeometry(Line, List, boolean, Vector3f)} with this path.
     * 
     * @param shape
     *            an instance of Line that describes the 2D shape
     * @param points
     *            a list of supporting points for the spline interpolation
     * @param segments
     *            number of resulting path segments per supporting point
     * @param closed
     *            true to close the shape (connect last and first point)
     * @param up
     *            up vector
     */
    public void updateGeometry(Line shape, List<Vector3f> points, int segments,
            boolean closed, Vector3f up) {
        int np = points.size(); // number of points
        if (closed) {
            np = np + 3;
        }
        float d[][] = new float[3][np]; // Newton form coefficients
        float x[] = new float[np]; // x-coordinates of nodes

        List<Vector3f> path = new ArrayList<Vector3f>();

        for (int i = 0; i < np; i++) {
            Vector3f p;
            if (!closed) {
                p = points.get(i);
            } else {
                if (i == 0) {
                    p = points.get(points.size() - 1);
                } else if (i >= np - 2) {
                    p = points.get(i - np + 2);
                } else {
                    p = points.get(i - 1);
                }
            }
            x[i] = i;
            d[0][i] = p.x;
            d[1][i] = p.y;
            d[2][i] = p.z;
        }

        if (np > 1) {
            float[][] a = new float[3][np];
            float h[] = new float[np];
            for (int i = 1; i <= np - 1; i++) {
                h[i] = x[i] - x[i - 1];
            }
            if (np > 2) {
                float sub[] = new float[np - 1];
                float diag[] = new float[np - 1];
                float sup[] = new float[np - 1];

                for (int i = 1; i <= np - 2; i++) {
                    diag[i] = (h[i] + h[i + 1]) / 3;
                    sup[i] = h[i + 1] / 6;
                    sub[i] = h[i] / 6;
                    for (int dim = 0; dim < 3; dim++) {
                        a[dim][i] = (d[dim][i + 1] - d[dim][i]) / h[i + 1]
                                - (d[dim][i] - d[dim][i - 1]) / h[i];
                    }
                }
                for (int dim = 0; dim < 3; dim++) {
                    solveTridiag(sub.clone(), diag.clone(), sup.clone(),
                            a[dim], np - 2);
                }
            }
            // note that a[0]=a[np-1]=0
            // draw
            if (!closed) {
                path.add(new Vector3f(d[0][0], d[1][0], d[2][0]));
            }
            float[] point = new float[3];
            for (int i = closed ? 2 : 1; i <= np - 2; i++) { // loop over
                                                                // intervals
                                                                // between nodes
                for (int j = 1; j <= segments; j++) {
                    for (int dim = 0; dim < 3; dim++) {
                        float t1 = (h[i] * j) / segments;
                        float t2 = h[i] - t1;
                        float v = ((-a[dim][i - 1] / 6 * (t2 + h[i]) * t1 + d[dim][i - 1])
                                * t2 + (-a[dim][i] / 6 * (t1 + h[i]) * t2 + d[dim][i])
                                * t1)
                                / h[i];
                        // float t = x[i - 1] + t1;
                        point[dim] = v;
                    }
                    path.add(new Vector3f(point[0], point[1], point[2]));
                }
            }
        }

        this.updateGeometry(shape, path, closed, up);
    }

    /*
     * solve linear system with tridiagonal n by n matrix a using Gaussian
     * elimination without pivoting where a(i,i-1) = sub[i] for 2<=i<=n a(i,i) =
     * diag[i] for 1<=i<=n a(i,i+1) = sup[i] for 1<=i<=n-1 (the values
     * sub[1], sup[n] are ignored) right hand side vector b[1:n] is overwritten
     * with solution NOTE: 1...n is used in all arrays, 0 is unused
     */
    private static void solveTridiag(float sub[], float diag[], float sup[],
            float b[], int n) {
        // factorization and forward substitution
        for (int i = 2; i <= n; i++) {
            sub[i] = sub[i] / diag[i - 1];
            diag[i] = diag[i] - sub[i] * sup[i - 1];
            b[i] = b[i] - sub[i] * b[i - 1];
        }
        b[n] = b[n] / diag[n];
        for (int i = n - 1; i >= 1; i--) {
            b[i] = (b[i] - sup[i] * b[i + 1]) / diag[i];
        }
    }
}

/*
 * $Log: Extrusion.java,v $ Revision 1.6 2007/04/03 14:30:17 nca ISSUE MINOR:
 * Lots of code clean-up (imports, qualifiers, brackets, etc) BoundingSphere
 * fix. ParticleSystem fix. Revision 1.5 2007/03/06 15:16:06 nca ISSUE MINOR:
 * Doc update Revision 1.4 2007/02/06 11:23:15 irrisor Topic 4479: mapping of
 * mouse buttons in awt events and query methods aligned; extracted static
 * method to set up AWTMouseInput. Revision 1.3 2006/12/16 13:51:44 irrisor
 * MINOR: tidied some comments Revision 1.2 2006/12/15 16:38:18 irrisor MINOR:
 * JavaDoc corrected Revision 1.1 2006/12/15 15:57:30 irrisor MINOR: Added
 * extrusion shape plus some helper methods MINOR: some javadoc corrected
 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?