Skip to content

Commit b27d212

Browse files
committed
implemented AABB-line intersection algorithm
1 parent cd0c1ee commit b27d212

File tree

2 files changed

+165
-18
lines changed

2 files changed

+165
-18
lines changed

mode/libraries/vr/examples/IntersectsBox/IntersectsBox.pde

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ void draw() {
1515

1616
cam.setPosition(0, 0, 200);
1717
push();
18-
angleMode(DEGREES);
19-
rotateZ(rotAngle);
18+
rotateZ(radians(rotAngle));
2019
translate(100, 0, 0);
2120
fill(255, 0, 0);
22-
if (intersectsBox(50)) {
21+
if (intersectsBox(50, 0, 0)) {
2322
rotAngle += rotSpeed;
2423
fill(0, 0, 255);
2524
}

mode/libraries/vr/src/processing/vr/VRGraphics.java

Lines changed: 163 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)