1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.jme3.bounding; 33 34 import com.jme3.math.FastMath; 35 import com.jme3.math.Plane; 36 import com.jme3.math.Vector3f; 37 import com.jme3.util.TempVars; 38 import static java.lang.Math.max; 39 import static java.lang.Math.min; 40 41 /** 42 * This class includes some utility methods for computing intersection 43 * between bounding volumes and triangles. 44 * @author Kirill 45 */ 46 public class Intersection { 47 findMinMax(float x0, float x1, float x2, Vector3f minMax)48 private static final void findMinMax(float x0, float x1, float x2, Vector3f minMax) { 49 minMax.set(x0, x0, 0); 50 if (x1 < minMax.x) { 51 minMax.setX(x1); 52 } 53 if (x1 > minMax.y) { 54 minMax.setY(x1); 55 } 56 if (x2 < minMax.x) { 57 minMax.setX(x2); 58 } 59 if (x2 > minMax.y) { 60 minMax.setY(x2); 61 } 62 } 63 64 // private boolean axisTest(float a, float b, float fa, float fb, Vector3f v0, Vector3f v1, ) 65 // private boolean axisTestX01(float a, float b, float fa, float fb, 66 // Vector3f center, Vector3f ext, 67 // Vector3f v1, Vector3f v2, Vector3f v3){ 68 // float p0 = a * v0.y - b * v0.z; 69 // float p2 = a * v2.y - b * v2.z; 70 // if(p0 < p2){ 71 // min = p0; 72 // max = p2; 73 // } else { 74 // min = p2; 75 // max = p0; 76 // } 77 // float rad = fa * boxhalfsize.y + fb * boxhalfsize.z; 78 // if(min > rad || max < -rad) 79 // return false; 80 // } intersect(BoundingBox bbox, Vector3f v1, Vector3f v2, Vector3f v3)81 public static boolean intersect(BoundingBox bbox, Vector3f v1, Vector3f v2, Vector3f v3) { 82 // use separating axis theorem to test overlap between triangle and box 83 // need to test for overlap in these directions: 84 // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle 85 // we do not even need to test these) 86 // 2) normal of the triangle 87 // 3) crossproduct(edge from tri, {x,y,z}-directin) 88 // this gives 3x3=9 more tests 89 90 TempVars vars = TempVars.get(); 91 92 93 Vector3f tmp0 = vars.vect1, 94 tmp1 = vars.vect2, 95 tmp2 = vars.vect3; 96 97 Vector3f e0 = vars.vect4, 98 e1 = vars.vect5, 99 e2 = vars.vect6; 100 101 Vector3f center = bbox.getCenter(); 102 Vector3f extent = bbox.getExtent(null); 103 104 // float min,max,p0,p1,p2,rad,fex,fey,fez; 105 // float normal[3] 106 107 // This is the fastest branch on Sun 108 // move everything so that the boxcenter is in (0,0,0) 109 v1.subtract(center, tmp0); 110 v2.subtract(center, tmp1); 111 v3.subtract(center, tmp2); 112 113 // compute triangle edges 114 tmp1.subtract(tmp0, e0); // tri edge 0 115 tmp2.subtract(tmp1, e1); // tri edge 1 116 tmp0.subtract(tmp2, e2); // tri edge 2 117 118 // Bullet 3: 119 // test the 9 tests first (this was faster) 120 float min, max; 121 float p0, p1, p2, rad; 122 float fex = FastMath.abs(e0.x); 123 float fey = FastMath.abs(e0.y); 124 float fez = FastMath.abs(e0.z); 125 126 127 128 //AXISTEST_X01(e0[Z], e0[Y], fez, fey); 129 p0 = e0.z * tmp0.y - e0.y * tmp0.z; 130 p2 = e0.z * tmp2.y - e0.y * tmp2.z; 131 min = min(p0, p2); 132 max = max(p0, p2); 133 rad = fez * extent.y + fey * extent.z; 134 if (min > rad || max < -rad) { 135 vars.release(); 136 return false; 137 } 138 139 // AXISTEST_Y02(e0[Z], e0[X], fez, fex); 140 p0 = -e0.z * tmp0.x + e0.x * tmp0.z; 141 p2 = -e0.z * tmp2.x + e0.x * tmp2.z; 142 min = min(p0, p2); 143 max = max(p0, p2); 144 rad = fez * extent.x + fex * extent.z; 145 if (min > rad || max < -rad) { 146 vars.release(); 147 return false; 148 } 149 150 // AXISTEST_Z12(e0[Y], e0[X], fey, fex); 151 p1 = e0.y * tmp1.x - e0.x * tmp1.y; 152 p2 = e0.y * tmp2.x - e0.x * tmp2.y; 153 min = min(p1, p2); 154 max = max(p1, p2); 155 rad = fey * extent.x + fex * extent.y; 156 if (min > rad || max < -rad) { 157 vars.release(); 158 return false; 159 } 160 161 fex = FastMath.abs(e1.x); 162 fey = FastMath.abs(e1.y); 163 fez = FastMath.abs(e1.z); 164 165 // AXISTEST_X01(e1[Z], e1[Y], fez, fey); 166 p0 = e1.z * tmp0.y - e1.y * tmp0.z; 167 p2 = e1.z * tmp2.y - e1.y * tmp2.z; 168 min = min(p0, p2); 169 max = max(p0, p2); 170 rad = fez * extent.y + fey * extent.z; 171 if (min > rad || max < -rad) { 172 vars.release(); 173 return false; 174 } 175 176 // AXISTEST_Y02(e1[Z], e1[X], fez, fex); 177 p0 = -e1.z * tmp0.x + e1.x * tmp0.z; 178 p2 = -e1.z * tmp2.x + e1.x * tmp2.z; 179 min = min(p0, p2); 180 max = max(p0, p2); 181 rad = fez * extent.x + fex * extent.z; 182 if (min > rad || max < -rad) { 183 vars.release(); 184 return false; 185 } 186 187 // AXISTEST_Z0(e1[Y], e1[X], fey, fex); 188 p0 = e1.y * tmp0.x - e1.x * tmp0.y; 189 p1 = e1.y * tmp1.x - e1.x * tmp1.y; 190 min = min(p0, p1); 191 max = max(p0, p1); 192 rad = fey * extent.x + fex * extent.y; 193 if (min > rad || max < -rad) { 194 vars.release(); 195 return false; 196 } 197 // 198 fex = FastMath.abs(e2.x); 199 fey = FastMath.abs(e2.y); 200 fez = FastMath.abs(e2.z); 201 202 // AXISTEST_X2(e2[Z], e2[Y], fez, fey); 203 p0 = e2.z * tmp0.y - e2.y * tmp0.z; 204 p1 = e2.z * tmp1.y - e2.y * tmp1.z; 205 min = min(p0, p1); 206 max = max(p0, p1); 207 rad = fez * extent.y + fey * extent.z; 208 if (min > rad || max < -rad) { 209 vars.release(); 210 return false; 211 } 212 213 // AXISTEST_Y1(e2[Z], e2[X], fez, fex); 214 p0 = -e2.z * tmp0.x + e2.x * tmp0.z; 215 p1 = -e2.z * tmp1.x + e2.x * tmp1.z; 216 min = min(p0, p1); 217 max = max(p0, p1); 218 rad = fez * extent.x + fex * extent.y; 219 if (min > rad || max < -rad) { 220 vars.release(); 221 return false; 222 } 223 224 // AXISTEST_Z12(e2[Y], e2[X], fey, fex); 225 p1 = e2.y * tmp1.x - e2.x * tmp1.y; 226 p2 = e2.y * tmp2.x - e2.x * tmp2.y; 227 min = min(p1, p2); 228 max = max(p1, p2); 229 rad = fey * extent.x + fex * extent.y; 230 if (min > rad || max < -rad) { 231 vars.release(); 232 return false; 233 } 234 235 // Bullet 1: 236 // first test overlap in the {x,y,z}-directions 237 // find min, max of the triangle each direction, and test for overlap in 238 // that direction -- this is equivalent to testing a minimal AABB around 239 // the triangle against the AABB 240 241 242 Vector3f minMax = vars.vect7; 243 244 // test in X-direction 245 findMinMax(tmp0.x, tmp1.x, tmp2.x, minMax); 246 if (minMax.x > extent.x || minMax.y < -extent.x) { 247 vars.release(); 248 return false; 249 } 250 251 // test in Y-direction 252 findMinMax(tmp0.y, tmp1.y, tmp2.y, minMax); 253 if (minMax.x > extent.y || minMax.y < -extent.y) { 254 vars.release(); 255 return false; 256 } 257 258 // test in Z-direction 259 findMinMax(tmp0.z, tmp1.z, tmp2.z, minMax); 260 if (minMax.x > extent.z || minMax.y < -extent.z) { 261 vars.release(); 262 return false; 263 } 264 265 // // Bullet 2: 266 // // test if the box intersects the plane of the triangle 267 // // compute plane equation of triangle: normal * x + d = 0 268 // Vector3f normal = new Vector3f(); 269 // e0.cross(e1, normal); 270 Plane p = vars.plane; 271 272 p.setPlanePoints(v1, v2, v3); 273 if (bbox.whichSide(p) == Plane.Side.Negative) { 274 vars.release(); 275 return false; 276 } 277 // 278 // if(!planeBoxOverlap(normal,v0,boxhalfsize)) return false; 279 280 vars.release(); 281 282 return true; /* box and triangle overlaps */ 283 } 284 } 285