com.bulletphysics.collision.shapes.BvhTriangleMeshShape Maven / Gradle / Ivy
Show all versions of jbullet Show documentation
/*
* Java port of Bullet (c) 2008 Martin Dvorak
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
package com.bulletphysics.collision.shapes;
import com.bulletphysics.BulletGlobals;
import com.bulletphysics.util.ObjectPool;
import com.bulletphysics.collision.broadphase.BroadphaseNativeType;
import com.bulletphysics.linearmath.VectorUtil;
import cz.advel.stack.Stack;
import javax.vecmath.Vector3f;
/**
* BvhTriangleMeshShape is a static-triangle mesh shape with several optimizations,
* such as bounding volume hierarchy. It is recommended to enable useQuantizedAabbCompression
* for better memory usage.
*
* It takes a triangle mesh as input, for example a {@link TriangleMesh} or
* {@link TriangleIndexVertexArray}. The BvhTriangleMeshShape class allows for
* triangle mesh deformations by a refit or partialRefit method.
*
* Instead of building the bounding volume hierarchy acceleration structure, it is
* also possible to serialize (save) and deserialize (load) the structure from disk.
* See ConcaveDemo for an example.
*
* @author jezek2
*/
public class BvhTriangleMeshShape extends TriangleMeshShape {
private OptimizedBvh bvh;
private boolean useQuantizedAabbCompression;
private boolean ownsBvh;
private ObjectPool myNodeCallbacks = ObjectPool.get(MyNodeOverlapCallback.class);
public BvhTriangleMeshShape() {
super(null);
this.bvh = null;
this.ownsBvh = false;
}
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, boolean useQuantizedAabbCompression) {
this(meshInterface, useQuantizedAabbCompression, true);
}
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, boolean useQuantizedAabbCompression, boolean buildBvh) {
super(meshInterface);
this.bvh = null;
this.useQuantizedAabbCompression = useQuantizedAabbCompression;
this.ownsBvh = false;
// construct bvh from meshInterface
//#ifndef DISABLE_BVH
Vector3f bvhAabbMin = new Vector3f(), bvhAabbMax = new Vector3f();
meshInterface.calculateAabbBruteForce(bvhAabbMin, bvhAabbMax);
if (buildBvh) {
bvh = new OptimizedBvh();
bvh.build(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax);
ownsBvh = true;
// JAVA NOTE: moved from TriangleMeshShape
recalcLocalAabb();
}
//#endif //DISABLE_BVH
}
/**
* Optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb.
*/
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, boolean useQuantizedAabbCompression, Vector3f bvhAabbMin, Vector3f bvhAabbMax) {
this(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax, true);
}
/**
* Optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb.
*/
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, boolean useQuantizedAabbCompression, Vector3f bvhAabbMin, Vector3f bvhAabbMax, boolean buildBvh) {
super(meshInterface);
this.bvh = null;
this.useQuantizedAabbCompression = useQuantizedAabbCompression;
this.ownsBvh = false;
// construct bvh from meshInterface
//#ifndef DISABLE_BVH
if (buildBvh) {
bvh = new OptimizedBvh();
bvh.build(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax);
ownsBvh = true;
}
// JAVA NOTE: moved from TriangleMeshShape
recalcLocalAabb();
//#endif //DISABLE_BVH
}
public boolean getOwnsBvh() {
return ownsBvh;
}
@Override
public BroadphaseNativeType getShapeType() {
return BroadphaseNativeType.TRIANGLE_MESH_SHAPE_PROXYTYPE;
}
public void performRaycast(TriangleCallback callback, Vector3f raySource, Vector3f rayTarget) {
MyNodeOverlapCallback myNodeCallback = myNodeCallbacks.get();
myNodeCallback.init(callback, meshInterface);
bvh.reportRayOverlappingNodex(myNodeCallback, raySource, rayTarget);
myNodeCallbacks.release(myNodeCallback);
}
public void performConvexcast(TriangleCallback callback, Vector3f raySource, Vector3f rayTarget, Vector3f aabbMin, Vector3f aabbMax) {
MyNodeOverlapCallback myNodeCallback = myNodeCallbacks.get();
myNodeCallback.init(callback, meshInterface);
bvh.reportBoxCastOverlappingNodex(myNodeCallback, raySource, rayTarget, aabbMin, aabbMax);
myNodeCallbacks.release(myNodeCallback);
}
/**
* Perform bvh tree traversal and report overlapping triangles to 'callback'.
*/
@Override
public void processAllTriangles(TriangleCallback callback, Vector3f aabbMin, Vector3f aabbMax) {
//#ifdef DISABLE_BVH
// // brute force traverse all triangles
//btTriangleMeshShape::processAllTriangles(callback,aabbMin,aabbMax);
//#else
// first get all the nodes
MyNodeOverlapCallback myNodeCallback = myNodeCallbacks.get();
myNodeCallback.init(callback, meshInterface);
bvh.reportAabbOverlappingNodex(myNodeCallback, aabbMin, aabbMax);
myNodeCallbacks.release(myNodeCallback);
//#endif//DISABLE_BVH
}
public void refitTree(Vector3f aabbMin, Vector3f aabbMax) {
// JAVA NOTE: update it for 2.70b1
//bvh.refit(meshInterface, aabbMin, aabbMax);
bvh.refit(meshInterface);
recalcLocalAabb();
}
/**
* For a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will become more conservative, it never shrinks.
*/
public void partialRefitTree(Vector3f aabbMin, Vector3f aabbMax) {
bvh.refitPartial(meshInterface,aabbMin,aabbMax );
VectorUtil.setMin(localAabbMin, aabbMin);
VectorUtil.setMax(localAabbMax, aabbMax);
}
@Override
public String getName() {
return "BVHTRIANGLEMESH";
}
@Override
public void setLocalScaling(Vector3f scaling) {
Vector3f tmp = Stack.alloc(Vector3f.class);
tmp.sub(getLocalScaling(Stack.alloc(Vector3f.class)), scaling);
if (tmp.lengthSquared() > BulletGlobals.SIMD_EPSILON) {
super.setLocalScaling(scaling);
/*
if (ownsBvh)
{
m_bvh->~btOptimizedBvh();
btAlignedFree(m_bvh);
}
*/
///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work
bvh = new OptimizedBvh();
// rebuild the bvh...
bvh.build(meshInterface, useQuantizedAabbCompression, localAabbMin, localAabbMax);
ownsBvh = true;
}
}
public OptimizedBvh getOptimizedBvh() {
return bvh;
}
public void setOptimizedBvh(OptimizedBvh bvh) {
Vector3f scaling = Stack.alloc(Vector3f.class);
scaling.set(1f, 1f, 1f);
setOptimizedBvh(bvh, scaling);
}
public void setOptimizedBvh(OptimizedBvh bvh, Vector3f scaling) {
assert (this.bvh == null);
assert (!ownsBvh);
this.bvh = bvh;
ownsBvh = false;
// update the scaling without rebuilding the bvh
Vector3f tmp = Stack.alloc(Vector3f.class);
tmp.sub(getLocalScaling(Stack.alloc(Vector3f.class)), scaling);
if (tmp.lengthSquared() > BulletGlobals.SIMD_EPSILON) {
super.setLocalScaling(scaling);
}
}
public boolean usesQuantizedAabbCompression() {
return useQuantizedAabbCompression;
}
////////////////////////////////////////////////////////////////////////////
protected static class MyNodeOverlapCallback extends NodeOverlapCallback {
public StridingMeshInterface meshInterface;
public TriangleCallback callback;
private Vector3f[] triangle/*[3]*/ = new Vector3f[] { new Vector3f(), new Vector3f(), new Vector3f() };
public MyNodeOverlapCallback() {
}
public void init(TriangleCallback callback, StridingMeshInterface meshInterface) {
this.meshInterface = meshInterface;
this.callback = callback;
}
public void processNode(int nodeSubPart, int nodeTriangleIndex) {
VertexData data = meshInterface.getLockedReadOnlyVertexIndexBase(nodeSubPart);
Vector3f meshScaling = meshInterface.getScaling(Stack.alloc(Vector3f.class));
data.getTriangle(nodeTriangleIndex*3, meshScaling, triangle);
/* Perform ray vs. triangle collision here */
callback.processTriangle(triangle, nodeSubPart, nodeTriangleIndex);
meshInterface.unLockReadOnlyVertexBase(nodeSubPart);
}
}
}