1 /* 2 * To change this template, choose Tools | Templates 3 * and open the template in the editor. 4 */ 5 6 package com.jme3.bullet.collision.shapes; 7 8 import com.bulletphysics.dom.HeightfieldTerrainShape; 9 import com.jme3.bullet.util.Converter; 10 import com.jme3.export.InputCapsule; 11 import com.jme3.export.JmeExporter; 12 import com.jme3.export.JmeImporter; 13 import com.jme3.export.OutputCapsule; 14 import com.jme3.math.FastMath; 15 import com.jme3.math.Vector3f; 16 import com.jme3.scene.Mesh; 17 import java.io.IOException; 18 19 /** 20 * Uses Bullet Physics Heightfield terrain collision system. This is MUCH faster 21 * than using a regular mesh. 22 * There are a couple tricks though: 23 * -No rotation or translation is supported. 24 * -The collision bbox must be centered around 0,0,0 with the height above and below the y-axis being 25 * equal on either side. If not, the whole collision box is shifted vertically and things don't collide 26 * as they should. 27 * 28 * @author Brent Owens 29 */ 30 public class HeightfieldCollisionShape extends CollisionShape { 31 32 //protected HeightfieldTerrainShape heightfieldShape; 33 protected int heightStickWidth; 34 protected int heightStickLength; 35 protected float[] heightfieldData; 36 protected float heightScale; 37 protected float minHeight; 38 protected float maxHeight; 39 protected int upAxis; 40 protected boolean flipQuadEdges; 41 42 public HeightfieldCollisionShape() { 43 44 } 45 46 public HeightfieldCollisionShape(float[] heightmap) { 47 createCollisionHeightfield(heightmap, Vector3f.UNIT_XYZ); 48 } 49 50 public HeightfieldCollisionShape(float[] heightmap, Vector3f scale) { 51 createCollisionHeightfield(heightmap, scale); 52 } 53 54 protected void createCollisionHeightfield(float[] heightmap, Vector3f worldScale) { 55 this.scale = worldScale; 56 this.heightScale = 1;//don't change away from 1, we use worldScale instead to scale 57 58 this.heightfieldData = heightmap; 59 60 float min = heightfieldData[0]; 61 float max = heightfieldData[0]; 62 // calculate min and max height 63 for (int i=0; i<heightfieldData.length; i++) { 64 if (heightfieldData[i] < min) 65 min = heightfieldData[i]; 66 if (heightfieldData[i] > max) 67 max = heightfieldData[i]; 68 } 69 // we need to center the terrain collision box at 0,0,0 for BulletPhysics. And to do that we need to set the 70 // min and max height to be equal on either side of the y axis, otherwise it gets shifted and collision is incorrect. 71 if (max < 0) 72 max = -min; 73 else { 74 if (Math.abs(max) > Math.abs(min)) 75 min = -max; 76 else 77 max = -min; 78 } 79 this.minHeight = min; 80 this.maxHeight = max; 81 82 this.upAxis = HeightfieldTerrainShape.YAXIS; 83 this.flipQuadEdges = false; 84 85 heightStickWidth = (int) FastMath.sqrt(heightfieldData.length); 86 heightStickLength = heightStickWidth; 87 88 89 createShape(); 90 } 91 92 protected void createShape() { 93 94 HeightfieldTerrainShape shape = new HeightfieldTerrainShape(heightStickWidth, heightStickLength, heightfieldData, heightScale, minHeight, maxHeight, upAxis, flipQuadEdges); 95 shape.setLocalScaling(new javax.vecmath.Vector3f(scale.x, scale.y, scale.z)); 96 cShape = shape; 97 cShape.setLocalScaling(Converter.convert(getScale())); 98 cShape.setMargin(margin); 99 } 100 101 public Mesh createJmeMesh(){ 102 //TODO return Converter.convert(bulletMesh); 103 return null; 104 } 105 106 public void write(JmeExporter ex) throws IOException { 107 super.write(ex); 108 OutputCapsule capsule = ex.getCapsule(this); 109 capsule.write(heightStickWidth, "heightStickWidth", 0); 110 capsule.write(heightStickLength, "heightStickLength", 0); 111 capsule.write(heightScale, "heightScale", 0); 112 capsule.write(minHeight, "minHeight", 0); 113 capsule.write(maxHeight, "maxHeight", 0); 114 capsule.write(upAxis, "upAxis", 1); 115 capsule.write(heightfieldData, "heightfieldData", new float[0]); 116 capsule.write(flipQuadEdges, "flipQuadEdges", false); 117 } 118 119 public void read(JmeImporter im) throws IOException { 120 super.read(im); 121 InputCapsule capsule = im.getCapsule(this); 122 heightStickWidth = capsule.readInt("heightStickWidth", 0); 123 heightStickLength = capsule.readInt("heightStickLength", 0); 124 heightScale = capsule.readFloat("heightScale", 0); 125 minHeight = capsule.readFloat("minHeight", 0); 126 maxHeight = capsule.readFloat("maxHeight", 0); 127 upAxis = capsule.readInt("upAxis", 1); 128 heightfieldData = capsule.readFloatArray("heightfieldData", new float[0]); 129 flipQuadEdges = capsule.readBoolean("flipQuadEdges", false); 130 createShape(); 131 } 132 133 } 134