| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /*
- * Copyright (c) 2009-2010 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.jme3.bullet.util;
- import com.jme3.bounding.BoundingBox;
- import com.jme3.bullet.collision.shapes.BoxCollisionShape;
- import com.jme3.bullet.collision.shapes.CollisionShape;
- import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
- import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
- import com.jme3.bullet.collision.shapes.HullCollisionShape;
- import com.jme3.bullet.collision.shapes.MeshCollisionShape;
- import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape;
- import com.jme3.math.Matrix3f;
- import com.jme3.math.Quaternion;
- import com.jme3.math.Transform;
- import com.jme3.math.Vector3f;
- import com.jme3.scene.Geometry;
- import com.jme3.scene.Mesh;
- import com.jme3.scene.Node;
- import com.jme3.scene.Spatial;
- import com.jme3.terrain.geomipmap.TerrainQuad;
- import java.util.Iterator;
- import java.util.LinkedList;
- /**
- *
- * @author normenhansen, tim8dev
- */
- public class CollisionShapeFactory {
- /**
- * returns the correct transform for a collisionshape in relation
- * to the ancestor for which the collisionshape is generated
- * @param spat
- * @param parent
- * @return
- */
- private static Transform getTransform(Spatial spat, Spatial parent) {
- Transform shapeTransform = new Transform();
- Spatial parentNode = spat.getParent() != null ? spat.getParent() : spat;
- Spatial currentSpatial = spat;
- //if we have parents combine their transforms
- while (parentNode != null) {
- if (parent == currentSpatial) {
- //real parent -> only apply scale, not transform
- Transform trans = new Transform();
- trans.setScale(currentSpatial.getLocalScale());
- shapeTransform.combineWithParent(trans);
- parentNode = null;
- } else {
- shapeTransform.combineWithParent(currentSpatial.getLocalTransform());
- parentNode = currentSpatial.getParent();
- currentSpatial = parentNode;
- }
- }
- return shapeTransform;
- }
- private static CompoundCollisionShape createCompoundShape(Node realRootNode,
- Node rootNode, CompoundCollisionShape shape, boolean meshAccurate, boolean dynamic) {
- for (Spatial spatial : rootNode.getChildren()) {
- if (spatial instanceof Node) {
- createCompoundShape(realRootNode, (Node) spatial, shape, meshAccurate, dynamic);
- } else if (spatial instanceof Geometry) {
- if (meshAccurate) {
- CollisionShape childShape = dynamic
- ? createSingleDynamicMeshShape((Geometry) spatial, realRootNode)
- : createSingleMeshShape((Geometry) spatial, realRootNode);
- if (childShape != null) {
- Transform trans = getTransform(spatial, realRootNode);
- shape.addChildShape(childShape,
- trans.getTranslation(),
- trans.getRotation().toRotationMatrix());
- }
- } else {
- Transform trans = getTransform(spatial, realRootNode);
- shape.addChildShape(createSingleBoxShape(spatial, realRootNode),
- trans.getTranslation(),
- trans.getRotation().toRotationMatrix());
- }
- }
- }
- return shape;
- }
- private static CompoundCollisionShape createCompoundShape(
- Node rootNode, CompoundCollisionShape shape, boolean meshAccurate) {
- return createCompoundShape(rootNode, rootNode, shape, meshAccurate, false);
- }
- /**
- * This type of collision shape is mesh-accurate and meant for immovable "world objects".
- * Examples include terrain, houses or whole shooter levels.<br>
- * Objects with "mesh" type collision shape will not collide with each other.
- */
- private static CompoundCollisionShape createMeshCompoundShape(Node rootNode) {
- return createCompoundShape(rootNode, new CompoundCollisionShape(), true);
- }
- /**
- * This type of collision shape creates a CompoundShape made out of boxes that
- * are based on the bounds of the Geometries in the tree.
- * @param rootNode
- * @return
- */
- private static CompoundCollisionShape createBoxCompoundShape(Node rootNode) {
- return createCompoundShape(rootNode, new CompoundCollisionShape(), false);
- }
- /**
- * This type of collision shape is mesh-accurate and meant for immovable "world objects".
- * Examples include terrain, houses or whole shooter levels.<br/>
- * Objects with "mesh" type collision shape will not collide with each other.<br/>
- * Creates a HeightfieldCollisionShape if the supplied spatial is a TerrainQuad.
- * @return A MeshCollisionShape or a CompoundCollisionShape with MeshCollisionShapes as children if the supplied spatial is a Node. A HeightieldCollisionShape if a TerrainQuad was supplied.
- */
- public static CollisionShape createMeshShape(Spatial spatial) {
- if (spatial instanceof TerrainQuad) {
- TerrainQuad terrain = (TerrainQuad) spatial;
- return new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale());
- } else if (spatial instanceof Geometry) {
- return createSingleMeshShape((Geometry) spatial, spatial);
- } else if (spatial instanceof Node) {
- return createMeshCompoundShape((Node) spatial);
- } else {
- throw new IllegalArgumentException("Supplied spatial must either be Node or Geometry!");
- }
- }
- /**
- * This method creates a hull shape for the given Spatial.<br>
- * If you want to have mesh-accurate dynamic shapes (CPU intense!!!) use GImpact shapes, its probably best to do so with a low-poly version of your model.
- * @return A HullCollisionShape or a CompoundCollisionShape with HullCollisionShapes as children if the supplied spatial is a Node.
- */
- public static CollisionShape createDynamicMeshShape(Spatial spatial) {
- if (spatial instanceof Geometry) {
- return createSingleDynamicMeshShape((Geometry) spatial, spatial);
- } else if (spatial instanceof Node) {
- return createCompoundShape((Node) spatial, (Node) spatial, new CompoundCollisionShape(), true, true);
- } else {
- throw new IllegalArgumentException("Supplied spatial must either be Node or Geometry!");
- }
- }
- public static CollisionShape createBoxShape(Spatial spatial) {
- if (spatial instanceof Geometry) {
- return createSingleBoxShape((Geometry) spatial, spatial);
- } else if (spatial instanceof Node) {
- return createBoxCompoundShape((Node) spatial);
- } else {
- throw new IllegalArgumentException("Supplied spatial must either be Node or Geometry!");
- }
- }
- /**
- * This type of collision shape is mesh-accurate and meant for immovable "world objects".
- * Examples include terrain, houses or whole shooter levels.<br>
- * Objects with "mesh" type collision shape will not collide with each other.
- */
- private static MeshCollisionShape createSingleMeshShape(Geometry geom, Spatial parent) {
- Mesh mesh = geom.getMesh();
- Transform trans = getTransform(geom, parent);
- if (mesh != null) {
- MeshCollisionShape mColl = new MeshCollisionShape(mesh);
- mColl.setScale(trans.getScale());
- return mColl;
- } else {
- return null;
- }
- }
- /**
- * Uses the bounding box of the supplied spatial to create a BoxCollisionShape
- * @param spatial
- * @return BoxCollisionShape with the size of the spatials BoundingBox
- */
- private static BoxCollisionShape createSingleBoxShape(Spatial spatial, Spatial parent) {
- spatial.setModelBound(new BoundingBox());
- //TODO: using world bound here instead of "local world" bound...
- BoxCollisionShape shape = new BoxCollisionShape(
- ((BoundingBox) spatial.getWorldBound()).getExtent(new Vector3f()));
- return shape;
- }
- /**
- * This method creates a hull collision shape for the given mesh.<br>
- */
- private static HullCollisionShape createSingleDynamicMeshShape(Geometry geom, Spatial parent) {
- Mesh mesh = geom.getMesh();
- Transform trans = getTransform(geom, parent);
- if (mesh != null) {
- HullCollisionShape dynamicShape = new HullCollisionShape(mesh);
- dynamicShape.setScale(trans.getScale());
- return dynamicShape;
- } else {
- return null;
- }
- }
- /**
- * This method moves each child shape of a compound shape by the given vector
- * @param vector
- */
- public static void shiftCompoundShapeContents(CompoundCollisionShape compoundShape, Vector3f vector) {
- for (Iterator<ChildCollisionShape> it = new LinkedList(compoundShape.getChildren()).iterator(); it.hasNext();) {
- ChildCollisionShape childCollisionShape = it.next();
- CollisionShape child = childCollisionShape.shape;
- Vector3f location = childCollisionShape.location;
- Matrix3f rotation = childCollisionShape.rotation;
- compoundShape.removeChildShape(child);
- compoundShape.addChildShape(child, location.add(vector), rotation);
- }
- }
- }
|