@@ -520,6 +520,27 @@ public void dispose() {
520
520
521
521
// ........................................................
522
522
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
+
523
544
// Error strings:
524
545
525
546
static final String OPENGL_THREAD_ERROR =
@@ -830,6 +851,264 @@ public boolean saveImpl(String filename) {
830
851
}
831
852
832
853
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
+
833
1112
//////////////////////////////////////////////////////////////
834
1113
835
1114
// IMAGE METADATA FOR THIS RENDERER
@@ -4605,6 +4884,18 @@ public void camera(float eyeX, float eyeY, float eyeZ,
4605
4884
y1 = -z0 * x2 + z2 * x0 ;
4606
4885
y2 = z0 * x1 - z1 * x0 ;
4607
4886
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
+
4608
4899
// Cross product gives area of parallelogram, which is < 1.0 for
4609
4900
// non-perpendicular unit-length vectors; so normalize x, y here:
4610
4901
float xmag = PApplet .sqrt (x0 * x0 + x1 * x1 + x2 * x2 );
0 commit comments