@@ -520,6 +520,27 @@ public void dispose() {
520520
521521 // ........................................................
522522
523+ protected PMatrix3D eyeMatrix ;
524+ protected PMatrix3D objMatrix ;
525+
526+ public float forwardX , forwardY , forwardZ ;
527+ public float rightX , rightY , rightZ ;
528+ public float upX , upY , upZ ;
529+
530+ // Variables used in ray casting
531+ protected PVector [] ray ;
532+ protected PVector hit = new PVector ();
533+ protected PVector screen = new PVector ();
534+ protected PVector objCenter = new PVector ();
535+ protected PVector objToOrig = new PVector ();
536+ protected PVector origInObjCoord = new PVector ();
537+ protected PVector hitInObjCoord = new PVector ();
538+ protected PVector dirInObjCoord = new PVector ();
539+ protected PVector origInWorldCoord = new PVector ();
540+ protected PVector dirInWorldCoord = new PVector ();
541+
542+ // ........................................................
543+
523544 // Error strings:
524545
525546 static final String OPENGL_THREAD_ERROR =
@@ -830,6 +851,264 @@ public boolean saveImpl(String filename) {
830851 }
831852
832853
854+ //////////////////////////////////////////////////////////////
855+
856+ // EYE/OBJECT MATRICES
857+
858+
859+ @ Override
860+ public PMatrix3D getEyeMatrix () {
861+ return getEyeMatrix (null );
862+ }
863+
864+
865+ @ Override
866+ public PMatrix3D getEyeMatrix (PMatrix3D target ) {
867+ if (target == null ) {
868+ target = new PMatrix3D ();
869+ }
870+ float sign = cameraUp ? +1 : -1 ;
871+ target .set (rightX , sign * upX , forwardX , cameraX ,
872+ rightY , sign * upY , forwardY , cameraY ,
873+ rightZ , sign * upZ , forwardZ , cameraZ ,
874+ 0 , 0 , 0 , 1 );
875+ return target ;
876+ }
877+
878+
879+ @ Override
880+ public PMatrix3D getObjectMatrix () {
881+ PMatrix3D mat = new PMatrix3D ();
882+ mat .set (modelviewInv );
883+ mat .apply (camera );
884+ return mat ;
885+ }
886+
887+
888+ @ Override
889+ public PMatrix3D getObjectMatrix (PMatrix3D target ) {
890+ if (target == null ) {
891+ target = new PMatrix3D ();
892+ }
893+ target .set (modelviewInv );
894+ target .apply (camera );
895+ return target ;
896+ }
897+
898+
899+ @ Override
900+ public void eye () {
901+ eyeMatrix = getEyeMatrix (eyeMatrix );
902+
903+ // Erasing any previous transformation in modelview
904+ modelview .set (camera );
905+ modelview .apply (eyeMatrix );
906+
907+ // The 3x3 block of eyeMatrix is orthogonal, so taking the transpose inverts it...
908+ eyeMatrix .transpose ();
909+ // ...and then invert the translation separately:
910+ eyeMatrix .m03 = -cameraX ;
911+ eyeMatrix .m13 = -cameraY ;
912+ eyeMatrix .m23 = -cameraZ ;
913+ eyeMatrix .m30 = 0 ;
914+ eyeMatrix .m31 = 0 ;
915+ eyeMatrix .m32 = 0 ;
916+
917+ // Applying the inverse of the previous transformations in the opposite order
918+ // to compute the modelview inverse
919+ modelviewInv .set (eyeMatrix );
920+ modelviewInv .preApply (cameraInv );
921+
922+ updateProjmodelview ();
923+ }
924+
925+
926+ //////////////////////////////////////////////////////////////
927+
928+ // RAY CASTING
929+
930+
931+ @ Override
932+ public PVector [] getRayFromScreen (float screenX , float screenY , PVector [] ray ) {
933+ if (ray == null || ray .length < 2 ) {
934+ ray = new PVector [2 ];
935+ ray [0 ] = new PVector ();
936+ ray [1 ] = new PVector ();
937+ }
938+ getRayFromScreen (screenX , screenY , ray [0 ], ray [1 ]);
939+ return ray ;
940+ }
941+
942+
943+ @ Override
944+ public void getRayFromScreen (float screenX , float screenY , PVector origin , PVector direction ) {
945+ eyeMatrix = getEyeMatrix (eyeMatrix );
946+
947+ // Transforming screen coordinates to world coordinates
948+ screen .x = screenX ;
949+ screen .y = screenY ;
950+ screen .z = 0 ;
951+ eyeMatrix .mult (screen , origin );
952+
953+ // The direction of the ray is simply extracted from the third column of the eye matrix (the
954+ // forward vector).
955+ direction .set (eyeMatrix .m02 , eyeMatrix .m12 , eyeMatrix .m22 );
956+ }
957+
958+
959+ @ Override
960+ public boolean intersectsSphere (float r , float screenX , float screenY ) {
961+ ray = getRayFromScreen (screenX , screenY , ray );
962+ return intersectsSphere (r , ray [0 ], ray [1 ]);
963+ }
964+
965+
966+ @ Override
967+ public boolean intersectsSphere (float r , PVector origin , PVector direction ) {
968+ // Get the center of the sphere in world coordinates
969+ objCenter .x = modelview .m03 ;
970+ objCenter .y = modelview .m13 ;
971+ objCenter .z = modelview .m23 ;
972+
973+ PVector .sub (origin , objCenter , objToOrig );
974+ float d = objToOrig .mag ();
975+
976+ // The eye is inside the sphere
977+ if (d <= r ) return true ;
978+
979+ // Check if sphere is in front of ray
980+ if (PVector .dot (objToOrig , direction ) > 0 ) return false ;
981+
982+ // Check intersection of ray with sphere
983+ float b = 2 * PVector .dot (direction , objToOrig );
984+ float c = d * d - r * r ;
985+ float det = b * b - 4 * c ;
986+ return det >= 0 ;
987+ }
988+
989+
990+ @ Override
991+ public boolean intersectsBox (float size , float screenX , float screenY ) {
992+ ray = getRayFromScreen (screenX , screenY , ray );
993+ return intersectsBox (size , size , size , ray [0 ], ray [1 ]);
994+ }
995+
996+
997+ @ Override
998+ public boolean intersectsBox (float w , float h , float d , float screenX , float screenY ) {
999+ ray = getRayFromScreen (screenX , screenY , ray );
1000+ return intersectsBox (w , h , d , ray [0 ], ray [1 ]);
1001+ }
1002+
1003+
1004+ @ Override
1005+ public boolean intersectsBox (float size , PVector origin , PVector direction ) {
1006+ return intersectsBox (size , size , size , origin , direction );
1007+ }
1008+
1009+
1010+ @ Override
1011+ public boolean intersectsBox (float w , float h , float d , PVector origin , PVector direction ) {
1012+ objMatrix = getObjectMatrix (objMatrix );
1013+ objMatrix .mult (origin , origInObjCoord );
1014+ PVector .add (origin , direction , hit );
1015+ objMatrix .mult (hit , hitInObjCoord );
1016+
1017+ PVector .sub (hitInObjCoord , origInObjCoord , dirInObjCoord );
1018+ return lineIntersectsAABB (origInObjCoord , dirInObjCoord , w , h , d );
1019+ }
1020+
1021+
1022+ // Line intersection with an axis-aligned bounding box (AABB), calculated using the algorithm
1023+ // from Amy William et al: http:// dl.acm.org/citation.cfm?id=1198748
1024+ protected boolean lineIntersectsAABB (PVector orig , PVector dir , float w , float h , float d ) {
1025+ float minx = -w /2 ;
1026+ float miny = -h /2 ;
1027+ float minz = -d /2 ;
1028+
1029+ float maxx = +w /2 ;
1030+ float maxy = +h /2 ;
1031+ float maxz = +d /2 ;
1032+
1033+ float idx = 1 /dir .x ;
1034+ float idy = 1 /dir .y ;
1035+ float idz = 1 /dir .z ;
1036+
1037+ boolean sdx = idx < 0 ;
1038+ boolean sdy = idy < 0 ;
1039+ boolean sdz = idz < 0 ;
1040+
1041+ float bbx = sdx ? maxx : minx ;
1042+ float txmin = (bbx - orig .x ) * idx ;
1043+ bbx = sdx ? minx : maxx ;
1044+ float txmax = (bbx - orig .x ) * idx ;
1045+ float bby = sdy ? maxy : miny ;
1046+ float tymin = (bby - orig .y ) * idy ;
1047+ bby = sdy ? miny : maxy ;
1048+ float tymax = (bby - orig .y ) * idy ;
1049+
1050+ if ((txmin > tymax ) || (tymin > txmax )) {
1051+ return false ;
1052+ }
1053+ if (tymin > txmin ) {
1054+ txmin = tymin ;
1055+ }
1056+ if (tymax < txmax ) {
1057+ txmax = tymax ;
1058+ }
1059+
1060+ float bbz = sdz ? maxz : minz ;
1061+ float tzmin = (bbz - orig .z ) * idz ;
1062+ bbz = sdz ? minz : maxz ;
1063+ float tzmax = (bbz - orig .z ) * idz ;
1064+
1065+ if ((txmin > tzmax ) || (tzmin > txmax )) {
1066+ return false ;
1067+ }
1068+ if (tzmin > txmin ) {
1069+ txmin = tzmin ;
1070+ }
1071+ if (tzmax < txmax ) {
1072+ txmax = tzmax ;
1073+ }
1074+
1075+ if ((txmin < defCameraFar ) && (txmax > 0 )) {
1076+ // The intersection coordinates:
1077+ // x = orig.x + txmin * dir.x;
1078+ // y = orig.y + txmin * dir.y;
1079+ // z = orig.z + txmin * dir.z;
1080+ return true ;
1081+ }
1082+
1083+ return false ;
1084+ }
1085+
1086+
1087+ @ Override
1088+ public PVector intersectsPlane (float screenX , float screenY ) {
1089+ ray = getRayFromScreen (screenX , screenY , ray );
1090+ return intersectsPlane (ray [0 ], ray [1 ]);
1091+ }
1092+
1093+
1094+ @ Override
1095+ public PVector intersectsPlane (PVector origin , PVector direction ) {
1096+ modelview .mult (origin , origInWorldCoord );
1097+ modelview .mult (direction , dirInWorldCoord );
1098+
1099+ // Ray-plane intersection algorithm
1100+ PVector w = new PVector (-origInWorldCoord .x , -origInWorldCoord .y , -origInWorldCoord .z );
1101+ float d = PApplet .abs (dirInWorldCoord .z * dirInWorldCoord .z );
1102+
1103+ if (d == 0 ) return null ;
1104+
1105+ float k = PApplet .abs ((w .z * w .z )/d );
1106+ PVector p = PVector .add (origInWorldCoord , dirInWorldCoord ).setMag (k );
1107+
1108+ return p ;
1109+ }
1110+
1111+
8331112 //////////////////////////////////////////////////////////////
8341113
8351114 // IMAGE METADATA FOR THIS RENDERER
@@ -4605,6 +4884,18 @@ public void camera(float eyeX, float eyeY, float eyeZ,
46054884 y1 = -z0 * x2 + z2 * x0 ;
46064885 y2 = z0 * x1 - z1 * x0 ;
46074886
4887+ forwardX = 0 ;
4888+ forwardY = 0 ;
4889+ forwardZ = 1 ;
4890+
4891+ rightX = 1 ;
4892+ rightY = 0 ;
4893+ rightZ = 0 ;
4894+
4895+ this .upX = 0 ;
4896+ this .upY = -1 ;
4897+ this .upZ = 0 ;
4898+
46084899 // Cross product gives area of parallelogram, which is < 1.0 for
46094900 // non-perpendicular unit-length vectors; so normalize x, y here:
46104901 float xmag = PApplet .sqrt (x0 * x0 + x1 * x1 + x2 * x2 );
0 commit comments