⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boundingbox.java

📁 java 3d game jme 工程开发源代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * 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.bounding;

import java.io.IOException;
import java.nio.FloatBuffer;

import com.jme.intersection.IntersectionRecord;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Plane;
import com.jme.math.Plane.Side;
import com.jme.math.Quaternion;
import com.jme.math.Ray;
import com.jme.math.Triangle;
import com.jme.math.Vector3f;
import com.jme.scene.TriMesh;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;
import com.jme.util.geom.BufferUtils;

/**
 * <code>BoundingBox</code> defines an axis-aligned cube that defines a
 * container for a group of vertices of a particular piece of geometry. This box
 * defines a center and extents from that center along the x, y and z axis. <br>
 * <br>
 * A typical usage is to allow the class define the center and radius by calling
 * either <code>containAABB</code> or <code>averagePoints</code>. A call to
 * <code>computeFramePoint</code> in turn calls <code>containAABB</code>.
 * 
 * @author Joshua Slack
 * @version $Id: BoundingBox.java,v 1.50 2007/09/22 16:46:35 irrisor Exp $
 */
public class BoundingBox extends BoundingVolume {

    private static final long serialVersionUID = 2L;

    public float xExtent, yExtent, zExtent;

    private static final transient Matrix3f _compMat = new Matrix3f();
    private static final float[] fWdU = new float[3];
    private static final float[] fAWdU = new float[3];
    private static final float[] fDdU = new float[3];
    private static final float[] fADdU = new float[3];
    private static final float[] fAWxDdU = new float[3];


	private static final Vector3f[] verts = new Vector3f[3];
    /**
     * Default constructor instantiates a new <code>BoundingBox</code>
     * object.
     */
    public BoundingBox() {
    }

    /**
     * Contstructor instantiates a new <code>BoundingBox</code> object with
     * given specs.
     */
    public BoundingBox(Vector3f c, float x, float y, float z) {
        this.center.set(c);
        this.xExtent = x;
        this.yExtent = y;
        this.zExtent = z;
    }

    public Type getType() {
        return Type.AABB;
    }

    /**
     * <code>computeFromPoints</code> creates a new Bounding Box from a given
     * set of points. It uses the <code>containAABB</code> method as default.
     * 
     * @param points
     *            the points to contain.
     */
    public void computeFromPoints(FloatBuffer points) {
        containAABB(points);
    }

    /**
     * <code>computeFromTris</code> creates a new Bounding Box from a given
     * set of triangles. It is used in OBBTree calculations.
     * 
     * @param tris
     * @param start
     * @param end
     */
    public void computeFromTris(Triangle[] tris, int start, int end) {
        if (end - start <= 0) {
            return;
        }

        Vector3f min = _compVect1.set(new Vector3f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
        Vector3f max = _compVect2.set(new Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
        
        Vector3f point;
        for (int i = start; i < end; i++) {
            point = tris[i].get(0);
            checkMinMax(min, max, point);
            point = tris[i].get(1);
            checkMinMax(min, max, point);
            point = tris[i].get(2);
            checkMinMax(min, max, point);
        }
        
        center.set(min.addLocal(max));
        center.multLocal(0.5f);

        xExtent = max.x - center.x;
        yExtent = max.y - center.y;
        zExtent = max.z - center.z;
    }
    
    public void computeFromTris(int[] indices, TriMesh mesh, int start, int end) {
    	if (end - start <= 0) {
            return;
        }
    	
    	Vector3f min = _compVect1.set(new Vector3f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
        Vector3f max = _compVect2.set(new Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
        Vector3f point;
        
        for (int i = start; i < end; i++) {
        	mesh.getTriangle(indices[i], verts);
        	point = verts[0];
            checkMinMax(min, max, point);
            point = verts[1];
            checkMinMax(min, max, point);
            point = verts[2];
            checkMinMax(min, max, point);
        }
        
        center.set(min.addLocal(max));
        center.multLocal(0.5f);

        xExtent = max.x - center.x;
        yExtent = max.y - center.y;
        zExtent = max.z - center.z;
    }

    private void checkMinMax(Vector3f min, Vector3f max, Vector3f point) {
        if (point.x < min.x)
            min.x = point.x;
        else if (point.x > max.x)
            max.x = point.x;
        if (point.y < min.y)
            min.y = point.y;
        else if (point.y > max.y)
            max.y = point.y;
        if (point.z < min.z)
            min.z = point.z;
        else if (point.z > max.z)
            max.z = point.z;
    }

    /**
     * <code>containAABB</code> creates a minimum-volume axis-aligned bounding
     * box of the points, then selects the smallest enclosing sphere of the box
     * with the sphere centered at the boxes center.
     * 
     * @param points
     *            the list of points.
     */
    public void containAABB(FloatBuffer points) {
        if (points == null)
            return;

        points.rewind();
        if (points.remaining() <= 2) // we need at least a 3 float vector
            return;

        BufferUtils.populateFromBuffer(_compVect1, points, 0);
        float minX = _compVect1.x, minY = _compVect1.y, minZ = _compVect1.z;
        float maxX = _compVect1.x, maxY = _compVect1.y, maxZ = _compVect1.z;

        for (int i = 1, len = points.remaining() / 3; i < len; i++) {
            BufferUtils.populateFromBuffer(_compVect1, points, i);

            if (_compVect1.x < minX)
                minX = _compVect1.x;
            else if (_compVect1.x > maxX)
                maxX = _compVect1.x;

            if (_compVect1.y < minY)
                minY = _compVect1.y;
            else if (_compVect1.y > maxY)
                maxY = _compVect1.y;

            if (_compVect1.z < minZ)
                minZ = _compVect1.z;
            else if (_compVect1.z > maxZ)
                maxZ = _compVect1.z;
        }

        center.set(minX + maxX, minY + maxY, minZ + maxZ);
        center.multLocal(0.5f);

        xExtent = maxX - center.x;
        yExtent = maxY - center.y;
        zExtent = maxZ - center.z;
    }

    /**
     * <code>transform</code> modifies the center of the box to reflect the
     * change made via a rotation, translation and scale.
     * 
     * @param rotate
     *            the rotation change.
     * @param translate
     *            the translation change.
     * @param scale
     *            the size change.
     * @param store
     *            box to store result in
     */
    public BoundingVolume transform(Quaternion rotate, Vector3f translate,
            Vector3f scale, BoundingVolume store) {

        BoundingBox box;
        if (store == null || store.getType() != Type.AABB) {
            box = new BoundingBox();
        } else {
            box = (BoundingBox) store;
        }

        center.mult(scale, box.center);
        rotate.mult(box.center, box.center);
        box.center.addLocal(translate);

        Matrix3f transMatrix = _compMat;
        transMatrix.set(rotate);
        // Make the rotation matrix all positive to get the maximum x/y/z extent
        transMatrix.m00 = FastMath.abs(transMatrix.m00);
        transMatrix.m01 = FastMath.abs(transMatrix.m01);
        transMatrix.m02 = FastMath.abs(transMatrix.m02);
        transMatrix.m10 = FastMath.abs(transMatrix.m10);
        transMatrix.m11 = FastMath.abs(transMatrix.m11);
        transMatrix.m12 = FastMath.abs(transMatrix.m12);
        transMatrix.m20 = FastMath.abs(transMatrix.m20);
        transMatrix.m21 = FastMath.abs(transMatrix.m21);
        transMatrix.m22 = FastMath.abs(transMatrix.m22);

        _compVect1.set(xExtent * scale.x, yExtent * scale.y, zExtent * scale.z);
        transMatrix.mult(_compVect1, _compVect2);
        // Assign the biggest rotations after scales.
        box.xExtent = FastMath.abs(_compVect2.x);
        box.yExtent = FastMath.abs(_compVect2.y);
        box.zExtent = FastMath.abs(_compVect2.z);

        return box;
    }

    /**
     * <code>whichSide</code> takes a plane (typically provided by a view
     * frustum) to determine which side this bound is on.
     * 
     * @param plane
     *            the plane to check against.
     */
    public Side whichSide(Plane plane) {
        float radius = FastMath.abs(xExtent * plane.normal.x)
                + FastMath.abs(yExtent * plane.normal.y)
                + FastMath.abs(zExtent * plane.normal.z);

        float distance = plane.pseudoDistance(center);

        //changed to < and > to prevent floating point precision problems
        if (distance < -radius) { return Side.NEGATIVE; }
        if (distance >  radius) { return Side.POSITIVE; }
        return Side.NONE;
    }

    /**
     * <code>merge</code> combines this sphere with a second bounding sphere.
     * This new sphere contains both bounding spheres and is returned.
     * 
     * @param volume
     *            the sphere to combine with this sphere.
     * @return the new sphere
     */
    public BoundingVolume merge(BoundingVolume volume) {
        if (volume == null) {
            return this;
        }

        switch (volume.getType()) {
            case AABB: {
                BoundingBox vBox = (BoundingBox) volume;
                return merge(vBox.center, vBox.xExtent, vBox.yExtent,
                        vBox.zExtent, new BoundingBox(new Vector3f(0, 0, 0), 0,
                                0, 0));
            }

            case Sphere: {
                BoundingSphere vSphere = (BoundingSphere) volume;
                return merge(vSphere.center, vSphere.radius, vSphere.radius,
                        vSphere.radius, new BoundingBox(new Vector3f(0, 0, 0),
                                0, 0, 0));
            }
            
            //Treating Capsule like sphere, inefficient
            case Capsule: {
                BoundingCapsule capsule = (BoundingCapsule) volume;
                float totalRadius = capsule.getRadius() + capsule.getLineSegment().getExtent();
                return merge(capsule.center, totalRadius, totalRadius,
                        totalRadius, new BoundingBox(new Vector3f(0, 0, 0),
                                0, 0, 0));
            }

            case OBB: {
                OrientedBoundingBox box = (OrientedBoundingBox) volume;
                BoundingBox rVal = (BoundingBox) this.clone(null);
                return rVal.mergeOBB(box);
            }

            default:
                return null;
        }
    }

    /**
     * <code>mergeLocal</code> combines this sphere with a second bounding
     * sphere locally. Altering this sphere to contain both the original and the
     * additional sphere volumes;
     * 
     * @param volume
     *            the sphere to combine with this sphere.
     * @return this
     */
    public BoundingVolume mergeLocal(BoundingVolume volume) {
        if (volume == null) {
            return this;
        }

        switch (volume.getType()) {
            case AABB: {
                BoundingBox vBox = (BoundingBox) volume;
                return merge(vBox.center, vBox.xExtent, vBox.yExtent,
                        vBox.zExtent, this);
            }

            case Sphere: {
                BoundingSphere vSphere = (BoundingSphere) volume;
                return merge(vSphere.center, vSphere.radius, vSphere.radius,
                        vSphere.radius, this);
            }
            
            //Treating capsule like sphere, inefficient
            case Capsule: {
                BoundingCapsule capsule = (BoundingCapsule) volume;
                float totalRadius = capsule.getRadius() + capsule.getLineSegment().getExtent();
                return merge(capsule.center, totalRadius, totalRadius,
                		totalRadius, this);
            }

            case OBB: {
                return mergeOBB((OrientedBoundingBox) volume);
            }

            default:
                return null;
        }
    }

    /**
     * Merges this AABB with the given OBB.
     * 
     * @param volume
     *            the OBB to merge this AABB with.
     * @return This AABB extended to fit the given OBB.
     */
    private BoundingBox mergeOBB(OrientedBoundingBox volume) {
        if (!volume.correctCorners)
            volume.computeCorners();

        Vector3f min = _compVect1.set(center.x - xExtent, center.y - yExtent,

⌨️ 快捷键说明

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