@@ -56,7 +56,19 @@ public class VRGraphics extends PGraphics3D {
5656 private Viewport eyeViewport ;
5757 private float [] eyeView ;
5858 private float [] eyePerspective ;
59+
5960 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 ();
6072
6173 @ Override
6274 protected PGL createPGL (PGraphicsOpenGL pg ) {
@@ -112,8 +124,7 @@ public void eye() {
112124 modelview .set (camera );
113125 modelview .apply (eyeMatrix );
114126
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...
117128 eyeMatrix .transpose ();
118129 // ...and then invert the translation separately:
119130 eyeMatrix .m03 = -cameraX ;
@@ -133,36 +144,173 @@ public void eye() {
133144
134145
135146 @ 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 ;
139155 }
140156
141157
142158 @ 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 );
146171 }
147172
148173
149174 @ 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 );
153222 }
154223
155224
156225 @ 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+
159298 return false ;
160299 }
161300
162301
302+
303+
163304 @ 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" );
166314 return null ;
167315 }
168316
0 commit comments