@@ -56,7 +56,19 @@ public class VRGraphics extends PGraphics3D {
56
56
private Viewport eyeViewport ;
57
57
private float [] eyeView ;
58
58
private float [] eyePerspective ;
59
+
59
60
private PMatrix3D eyeMatrix ;
61
+ private PMatrix3D objMatrix ;
62
+
63
+ // Variables used in ray casting
64
+ private PVector [] ray ;
65
+ private PVector hit = new PVector ();
66
+ private PVector screen = new PVector ();
67
+ private PVector objCenter = new PVector ();
68
+ private PVector objToOrig = new PVector ();
69
+ private PVector origInObjCoord = new PVector ();
70
+ private PVector hitInObjCoord = new PVector ();
71
+ private PVector dirInObjCoord = new PVector ();
60
72
61
73
@ Override
62
74
protected PGL createPGL (PGraphicsOpenGL pg ) {
@@ -112,8 +124,7 @@ public void eye() {
112
124
modelview .set (camera );
113
125
modelview .apply (eyeMatrix );
114
126
115
- // The 3x3 block of eyeMatrix is orthogonal, so taking the transpose
116
- // inverts it...
127
+ // The 3x3 block of eyeMatrix is orthogonal, so taking the transpose inverts it...
117
128
eyeMatrix .transpose ();
118
129
// ...and then invert the translation separately:
119
130
eyeMatrix .m03 = -cameraX ;
@@ -133,36 +144,173 @@ public void eye() {
133
144
134
145
135
146
@ Override
136
- public boolean intersectsBox (float w , PVector origin , PVector dir ) {
137
- showMissingWarning ("intersectsBox" );
138
- return false ;
147
+ public PVector [] getRayFromScreen (float screenX , float screenY , PVector [] ray ) {
148
+ if (ray == null || ray .length < 2 ) {
149
+ ray = new PVector [2 ];
150
+ ray [0 ] = new PVector ();
151
+ ray [1 ] = new PVector ();
152
+ }
153
+ getRayFromScreen (screenX , screenY , ray [0 ], ray [1 ]);
154
+ return ray ;
139
155
}
140
156
141
157
142
158
@ Override
143
- public boolean intersectsBox (float w , float h , float d , PVector origin , PVector dir ) {
144
- showMissingWarning ("intersectsBox" );
145
- return false ;
159
+ public void getRayFromScreen (float screenX , float screenY , PVector origin , PVector direction ) {
160
+ eyeMatrix = getEyeMatrix (eyeMatrix );
161
+
162
+ // Transforming screen coordinates to world coordinates
163
+ screen .x = screenX ;
164
+ screen .y = screenY ;
165
+ screen .z = 0 ;
166
+ eyeMatrix .mult (screen , origin );
167
+
168
+ // The direction of the ray is simply extracted from the third column of the eye matrix (the
169
+ // forward vector).
170
+ direction .set (eyeMatrix .m02 , eyeMatrix .m12 , eyeMatrix .m22 );
146
171
}
147
172
148
173
149
174
@ Override
150
- public PVector intersectsPlane (PVector origin , PVector dir ) {
151
- showMissingWarning ("intersectsPlane" );
152
- return null ;
175
+ public boolean intersectsSphere (float r , float screenX , float screenY ) {
176
+ ray = getRayFromScreen (screenX , screenY , ray );
177
+ return intersectsSphere (r , ray [0 ], ray [1 ]);
178
+ }
179
+
180
+
181
+ @ Override
182
+ public boolean intersectsSphere (float r , PVector origin , PVector direction ) {
183
+ // Get the center of the sphere in world coordinates
184
+ objCenter .x = modelview .m03 ;
185
+ objCenter .y = modelview .m13 ;
186
+ objCenter .z = modelview .m23 ;
187
+
188
+ PVector .sub (origin , objCenter , objToOrig );
189
+ float d = objToOrig .mag ();
190
+
191
+ // The eye is inside the sphere
192
+ if (d <= r ) return true ;
193
+
194
+ // Check if sphere is in front of ray
195
+ if (PVector .dot (objToOrig , direction ) > 0 ) return false ;
196
+
197
+ // Check intersection of ray with sphere
198
+ float b = 2 * PVector .dot (direction , objToOrig );
199
+ float c = d * d - r * r ;
200
+ float det = b * b - 4 * c ;
201
+ return det >= 0 ;
202
+ }
203
+
204
+
205
+ @ Override
206
+ public boolean intersectsBox (float size , float screenX , float screenY ) {
207
+ ray = getRayFromScreen (screenX , screenY , ray );
208
+ return intersectsBox (size , size , size , ray [0 ], ray [1 ]);
209
+ }
210
+
211
+
212
+ @ Override
213
+ public boolean intersectsBox (float w , float h , float d , float screenX , float screenY ) {
214
+ ray = getRayFromScreen (screenX , screenY , ray );
215
+ return intersectsBox (w , h , d , ray [0 ], ray [1 ]);
216
+ }
217
+
218
+
219
+ @ Override
220
+ public boolean intersectsBox (float size , PVector origin , PVector direction ) {
221
+ return intersectsBox (size , size , size , origin , direction );
153
222
}
154
223
155
224
156
225
@ Override
157
- public boolean intersectsSphere (float r , PVector origin , PVector dir ) {
158
- showMissingWarning ("intersectsSphere" );
226
+ public boolean intersectsBox (float w , float h , float d , PVector origin , PVector direction ) {
227
+ objMatrix = getObjectMatrix (objMatrix );
228
+ objMatrix .mult (origin , origInObjCoord );
229
+ PVector .add (origin , direction , hit );
230
+ objMatrix .mult (hit , hitInObjCoord );
231
+
232
+ PVector .sub (hitInObjCoord , origInObjCoord , dirInObjCoord );
233
+ return lineIntersectsAABB (origInObjCoord , dirInObjCoord , w , h , d );
234
+ }
235
+
236
+
237
+ // Line intersection with an axis-aligned bounding box (AABB), calculated using the algorithm
238
+ // from Amy William et al: http:// dl.acm.org/citation.cfm?id=1198748
239
+ protected boolean lineIntersectsAABB (PVector orig , PVector dir , float w , float h , float d ) {
240
+ float minx = -w /2 ;
241
+ float miny = -h /2 ;
242
+ float minz = -d /2 ;
243
+
244
+ float maxx = +w /2 ;
245
+ float maxy = +h /2 ;
246
+ float maxz = +d /2 ;
247
+
248
+ float idx = 1 /dir .x ;
249
+ float idy = 1 /dir .y ;
250
+ float idz = 1 /dir .z ;
251
+
252
+ boolean sdx = idx < 0 ;
253
+ boolean sdy = idy < 0 ;
254
+ boolean sdz = idz < 0 ;
255
+
256
+ float bbx = sdx ? maxx : minx ;
257
+ float txmin = (bbx - orig .x ) * idx ;
258
+ bbx = sdx ? minx : maxx ;
259
+ float txmax = (bbx - orig .x ) * idx ;
260
+ float bby = sdy ? maxy : miny ;
261
+ float tymin = (bby - orig .y ) * idy ;
262
+ bby = sdy ? miny : maxy ;
263
+ float tymax = (bby - orig .y ) * idy ;
264
+
265
+ if ((txmin > tymax ) || (tymin > txmax )) {
266
+ return false ;
267
+ }
268
+ if (tymin > txmin ) {
269
+ txmin = tymin ;
270
+ }
271
+ if (tymax < txmax ) {
272
+ txmax = tymax ;
273
+ }
274
+
275
+ float bbz = sdz ? maxz : minz ;
276
+ float tzmin = (bbz - orig .z ) * idz ;
277
+ bbz = sdz ? minz : maxz ;
278
+ float tzmax = (bbz - orig .z ) * idz ;
279
+
280
+ if ((txmin > tzmax ) || (tzmin > txmax )) {
281
+ return false ;
282
+ }
283
+ if (tzmin > txmin ) {
284
+ txmin = tzmin ;
285
+ }
286
+ if (tzmax < txmax ) {
287
+ txmax = tzmax ;
288
+ }
289
+
290
+ if ((txmin < defCameraFar ) && (txmax > 0 )) {
291
+ // The intersection coordinates:
292
+ // x = orig.x + txmin * dir.x;
293
+ // y = orig.y + txmin * dir.y;
294
+ // z = orig.z + txmin * dir.z;
295
+ return true ;
296
+ }
297
+
159
298
return false ;
160
299
}
161
300
162
301
302
+
303
+
163
304
@ Override
164
- public PVector [] getRayFromScreen (float screenX , float screenY ) {
165
- showMissingWarning ("getRayFromScreen" );
305
+ public PVector intersectsPlane (float screenX , float screenY ) {
306
+ ray = getRayFromScreen (screenX , screenY , ray );
307
+ return intersectsPlane (ray [0 ], ray [1 ]);
308
+ }
309
+
310
+
311
+ @ Override
312
+ public PVector intersectsPlane (PVector origin , PVector direction ) {
313
+ showMissingWarning ("intersectsPlane" );
166
314
return null ;
167
315
}
168
316
0 commit comments