1
1
package org .andresoviedo .app .model3D .collision ;
2
2
3
3
import android .opengl .GLU ;
4
+ import android .opengl .Matrix ;
4
5
import android .util .Log ;
5
6
6
7
import org .andresoviedo .app .model3D .entities .BoundingBox ;
7
8
import org .andresoviedo .app .model3D .model .Object3DData ;
8
9
import org .andresoviedo .app .model3D .view .ModelRenderer ;
9
10
import org .andresoviedo .app .util .math .Math3DUtils ;
10
11
12
+ import java .nio .FloatBuffer ;
13
+ import java .util .Arrays ;
11
14
import java .util .List ;
12
15
13
16
/**
@@ -26,30 +29,32 @@ public class CollisionDetection {
26
29
* @param windowY the window y coordinate
27
30
* @return the nearest object intersected by the specified coordinates or null
28
31
*/
29
- public static Object3DData getIntersection (List <Object3DData > objects , ModelRenderer mRenderer , float windowX , float windowY ) {
32
+ public static Object3DData getBoxIntersection (List <Object3DData > objects , ModelRenderer mRenderer , float windowX , float windowY ) {
30
33
float [] nearHit = unproject (mRenderer , windowX , windowY , 0 );
31
34
float [] farHit = unproject (mRenderer , windowX , windowY , 1 );
32
- return getIntersection (objects , nearHit , farHit );
35
+ float [] direction = Math3DUtils .substract (farHit , nearHit );
36
+ Math3DUtils .normalize (direction );
37
+ return getBoxIntersection (objects , nearHit , direction );
33
38
}
34
39
35
40
/**
36
41
* Get the nearest object intersected by the specified ray or null if no object is intersected
37
42
*
38
- * @param objects the list of objects to test
39
- * @param p1 the ray start point
40
- * @param p2 the ray end point
43
+ * @param objects the list of objects to test
44
+ * @param p1 the ray start point
45
+ * @param direction the ray direction
41
46
* @return the object intersected by the specified ray
42
47
*/
43
- public static Object3DData getIntersection (List <Object3DData > objects , float [] p1 , float [] p2 ) {
44
- float [] direction = Math3DUtils .substract (p2 , p1 );
45
- Math3DUtils .normalize (direction );
48
+ public static Object3DData getBoxIntersection (List <Object3DData > objects , float [] p1 , float [] direction ) {
46
49
float min = Float .MAX_VALUE ;
47
50
Object3DData ret = null ;
48
51
for (Object3DData obj : objects ) {
49
- if (obj .getId ().startsWith ("Line" )) continue ;
52
+ if (obj .getId ().equals ("Point" ) || obj .getId ().equals ("Line" )) {
53
+ continue ;
54
+ }
50
55
BoundingBox box = obj .getBoundingBox ();
51
56
float [] intersection = getBoxIntersection (p1 , direction , box );
52
- if (intersection [0 ] > 0 && intersection [0 ] < intersection [1 ] && intersection [0 ] < min ) {
57
+ if (intersection [0 ] > 0 && intersection [0 ] <= intersection [1 ] && intersection [0 ] < min ) {
53
58
min = intersection [0 ];
54
59
ret = obj ;
55
60
}
@@ -68,17 +73,16 @@ public static Object3DData getIntersection(List<Object3DData> objects, float[] p
68
73
* @param p2 ray end point
69
74
* @return the entry and exit point of the ray intersecting the nearest object
70
75
*/
71
- public static float [] getIntersectionPoint (List <Object3DData > objects , float [] p1 , float [] p2 ) {
76
+ public static float [] getBoxIntersectionPoint (List <Object3DData > objects , float [] p1 , float [] p2 ) {
72
77
float [] direction = Math3DUtils .substract (p2 , p1 );
73
78
Math3DUtils .normalize (direction );
74
79
float min = Float .MAX_VALUE ;
75
80
float [] intersection2 = null ;
76
81
Object3DData ret = null ;
77
82
for (Object3DData obj : objects ) {
78
- if (obj .getId ().startsWith ("Line" )) continue ;
79
83
BoundingBox box = obj .getBoundingBox ();
80
84
float [] intersection = getBoxIntersection (p1 , direction , box );
81
- if (intersection [0 ] > 0 && intersection [0 ] < intersection [1 ] && intersection [0 ] < min ) {
85
+ if (intersection [0 ] > 0 && intersection [0 ] <= intersection [1 ] && intersection [0 ] < min ) {
82
86
min = intersection [0 ];
83
87
ret = obj ;
84
88
intersection2 = intersection ;
@@ -113,8 +117,8 @@ public static boolean isBoxIntersection(float[] origin, float[] dir, BoundingBox
113
117
* @return the intersection points of the near and far plane
114
118
*/
115
119
public static float [] getBoxIntersection (float [] origin , float [] dir , BoundingBox b ) {
116
- float [] tMin = Math3DUtils .divide (Math3DUtils .substract (b .getCurrentMin (), origin ), dir );
117
- float [] tMax = Math3DUtils .divide (Math3DUtils .substract (b .getCurrentMax (), origin ), dir );
120
+ float [] tMin = Math3DUtils .divide (Math3DUtils .substract (b .getMin (), origin ), dir );
121
+ float [] tMax = Math3DUtils .divide (Math3DUtils .substract (b .getMax (), origin ), dir );
118
122
float [] t1 = Math3DUtils .min (tMin , tMax );
119
123
float [] t2 = Math3DUtils .max (tMin , tMax );
120
124
float tNear = Math .max (Math .max (t1 [0 ], t1 [1 ]), t1 [2 ]);
@@ -143,4 +147,136 @@ public static float[] unproject(ModelRenderer mRenderer, float rx, float ry, flo
143
147
xyzw [3 ] = 1 ;
144
148
return xyzw ;
145
149
}
150
+
151
+ public static float [] getTriangleIntersection (List <Object3DData > objects , ModelRenderer mRenderer , float windowX , float windowY ) {
152
+ float [] nearHit = unproject (mRenderer , windowX , windowY , 0 );
153
+ float [] farHit = unproject (mRenderer , windowX , windowY , 1 );
154
+ float [] direction = Math3DUtils .substract (farHit , nearHit );
155
+ Math3DUtils .normalize (direction );
156
+ Object3DData intersected = getBoxIntersection (objects , nearHit , direction );
157
+ if (intersected != null ) {
158
+ Log .d ("CollisionDetection" , "intersected:" + intersected .getId () + ", rayOrigin:" + Arrays .toString (nearHit ) + ", rayVector:" + Arrays .toString (direction ));
159
+ FloatBuffer buffer = intersected .getVertexArrayBuffer ().asReadOnlyBuffer ();
160
+ float [] modelMatrix = intersected .getModelMatrix ();
161
+ buffer .position (0 );
162
+ float [] selectedv1 = null ;
163
+ float [] selectedv2 = null ;
164
+ float [] selectedv3 = null ;
165
+ float min = Float .MAX_VALUE ;
166
+ for (int i = 0 ; i < buffer .capacity (); i += 9 ) {
167
+ float [] v1 = new float []{buffer .get (), buffer .get (), buffer .get (), 1 };
168
+ float [] v2 = new float []{buffer .get (), buffer .get (), buffer .get (), 1 };
169
+ float [] v3 = new float []{buffer .get (), buffer .get (), buffer .get (), 1 };
170
+ Matrix .multiplyMV (v1 , 0 , modelMatrix , 0 , v1 , 0 );
171
+ Matrix .multiplyMV (v2 , 0 , modelMatrix , 0 , v2 , 0 );
172
+ Matrix .multiplyMV (v3 , 0 , modelMatrix , 0 , v3 , 0 );
173
+ float t = getTriangleIntersection (nearHit , direction , v1 , v2 , v3 );
174
+ if (t != -1 && t < min ) {
175
+ min = t ;
176
+ selectedv1 = v1 ;
177
+ selectedv2 = v2 ;
178
+ selectedv3 = v3 ;
179
+ }
180
+ }
181
+ if (selectedv1 != null ) {
182
+ float [] outIntersectionPoint = Math3DUtils .add (nearHit , Math3DUtils .multiply (direction , min ));
183
+ return outIntersectionPoint ;
184
+ }
185
+ }
186
+ return null ;
187
+ }
188
+
189
+ public static float [] getTriangleIntersection2 (List <Object3DData > objects , ModelRenderer mRenderer , float windowX , float windowY ) {
190
+ float [] nearHit = unproject (mRenderer , windowX , windowY , 0 );
191
+ float [] farHit = unproject (mRenderer , windowX , windowY , 1 );
192
+ float [] direction = Math3DUtils .substract (farHit , nearHit );
193
+ Math3DUtils .normalize (direction );
194
+ Object3DData intersected = getBoxIntersection (objects , nearHit , direction );
195
+ if (intersected != null ) {
196
+ Log .d ("CollisionDetection" , "intersected 2:" +intersected .getId ());
197
+ Octree octree = null ;
198
+ synchronized (intersected ) {
199
+ octree = intersected .getOctree ();
200
+ if (octree == null ) {
201
+ octree = Octree .build (intersected );
202
+ intersected .setOctree (octree );
203
+ }
204
+ }
205
+ float intersection = getTriangleIntersection2_Impl (octree , nearHit , direction );
206
+ if (intersection != -1 ) {
207
+ return Math3DUtils .add (nearHit , Math3DUtils .multiply (direction , intersection ));
208
+ }
209
+ else {
210
+ return null ;
211
+ }
212
+ }
213
+ return null ;
214
+ }
215
+
216
+ private static float getTriangleIntersection2_Impl (Octree octree , float [] rayOrigin , float [] rayDirection ){
217
+ //Log.v("CollisionDetection","Testing octree "+octree);
218
+ if (!isBoxIntersection (rayOrigin , rayDirection , octree .boundingBox )) {
219
+ return -1 ;
220
+ }
221
+ Octree selected = null ;
222
+ float min = Float .MAX_VALUE ;
223
+ for (Octree child : octree .children ) {
224
+ if (child == null ) {
225
+ continue ;
226
+ }
227
+ float intersection = getTriangleIntersection2_Impl (child , rayOrigin , rayDirection );
228
+ if (intersection != -1 && intersection < min ){
229
+ min = intersection ;
230
+ selected = child ;
231
+ }
232
+ }
233
+ float [] selectedTriangle = null ;
234
+ for (float [] triangle : octree .triangles ){
235
+ float [] vertex0 = new float []{triangle [0 ], triangle [1 ], triangle [2 ]};
236
+ float [] vertex1 = new float []{triangle [4 ], triangle [5 ], triangle [6 ]};
237
+ float [] vertex2 = new float []{triangle [8 ], triangle [9 ], triangle [10 ]};
238
+ float intersection = getTriangleIntersection (rayOrigin , rayDirection , vertex0 , vertex1 , vertex2 );
239
+ if (intersection != -1 && intersection < min ){
240
+ min = intersection ;
241
+ selectedTriangle = triangle ;
242
+ selected = octree ;
243
+ }
244
+ }
245
+ if (min != Float .MAX_VALUE ){
246
+ return min ;
247
+ }
248
+ return -1 ;
249
+ }
250
+
251
+ public static float getTriangleIntersection (float [] rayOrigin ,
252
+ float [] rayVector ,
253
+ float [] vertex0 , float [] vertex1 , float [] vertex2 ) {
254
+ float EPSILON = 0.0000001f ;
255
+ float [] edge1 , edge2 , h , s , q ;
256
+ float a , f , u , v ;
257
+ edge1 = Math3DUtils .substract (vertex1 , vertex0 );
258
+ edge2 = Math3DUtils .substract (vertex2 , vertex0 );
259
+ h = Math3DUtils .crossProduct (rayVector , edge2 );
260
+ a = Math3DUtils .dotProduct (edge1 , h );
261
+ if (a > -EPSILON && a < EPSILON )
262
+ return -1 ;
263
+ f = 1 / a ;
264
+ s = Math3DUtils .substract (rayOrigin , vertex0 );
265
+ u = f * Math3DUtils .dotProduct (s , h );
266
+ if (u < 0.0 || u > 1.0 )
267
+ return -1 ;
268
+ q = Math3DUtils .crossProduct (s , edge1 );
269
+ v = f * Math3DUtils .dotProduct (rayVector , q );
270
+ if (v < 0.0 || u + v > 1.0 )
271
+ return -1 ;
272
+ // At this stage we can compute t to find out where the intersection point is on the line.
273
+ float t = f * Math3DUtils .dotProduct (edge2 , q );
274
+ if (t > EPSILON ) // ray intersection
275
+ {
276
+ Log .d ("CollisionDetection" , "Triangle intersection at: " + t );
277
+ return t ;
278
+ } else // This means that there is a line intersection but not a ray intersection.
279
+ return -1 ;
280
+ }
146
281
}
282
+
0 commit comments