📄 boundingbox.java
字号:
/*
* 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 + -