PERL   62

# rt diagram

Guest on 10th June 2022 01:30:11 PM

1. #!/usr/bin/env perl
2. use strict;
3. use warnings;
4. use Math::VectorReal;
5. use OpenGL::Simple ':all';
6. use OpenGL::Simple::GLUT ':all';
7. use OpenGL::Simple::Viewer;
8.
9.
10. my \$viewerPos = vector(0,-0.8,0);
11. my \$viewerForward = vector(0,0.2,1); # also view plane pos
12. my \$viewerUp = vector(0,1,0);
13. my \$viewerPlaneX = (\$viewerForward x \$viewerUp)->norm;
14. my \$viewerPlaneY = \$viewerUp->norm;
15.
16. my \$floorUp = vector(0,1,0);
17. my \$floorX = vector(1,0,0);
18. my \$floorY = vector(0,0,1);
19. my \$floorPos = vector(0,-1,0);
20.
21. my \$spherePos = vector(0,0,2.5);
23.
24. glutInit;
25.
26. my \$v = new OpenGL::Simple::Viewer(
27.     draw_geometry => sub {
28.         drawViewer();
29.         drawPlane();
30.         drawFloor();
31.         drawSphere();
32.
33.         my \$rez = 0.1;
34.         for (my \$x=-0.5;\$x<0.5;\$x+=\$rez) {
35.         for (my \$y=-0.5;\$y<0.5;\$y+=\$rez) {
36.             castRay(\$x,\$y);
37.         }}
38.
39.     },
40. );
41.
42. glutMainLoop;
43.
44. exit 0;
45.
46. sub castRay {
47.     my (\$x,\$y) = @_;
48.     my \$r0 = \$viewerPos;
49.
50.     my \$rayScreenIntersection =
51.         \$viewerPos + \$viewerForward
52.         + \$x * \$viewerPlaneX
53.         + \$y * \$viewerPlaneY;
54.
55.     my \$dir = \$rayScreenIntersection - \$r0;
56.
57.     return drawRay(\$r0,\$dir,0);
58.
59. }
60.
61. sub drawRay {
62.     my (\$r0,\$dir,\$fromSphere) = @_;
63.
64.     my \$intersection = raySphereIntersection(\$r0,\$dir);
65.     if ( (!\$fromSphere) && defined(\$intersection)) {
66.         # We intersect the sphere.
67.
68.         # Draw this segment.
69.
70.         glColor(1,0,0,1);
71.         glBegin(GL_LINES);
72.             glVertex(\$r0->array);
73.             glVertex(\$intersection->array);
74.         glEnd;
75.
76.         # Find new ray.
77.
78.         my \$dirOld = \$dir->norm;
79.         my \$normal = (\$intersection-\$spherePos)->norm;
80.
81.         my \$cosTheta = \$dirOld . \$normal;
82.
83.         my \$dirNew = \$dirOld - 2.0*\$cosTheta * \$normal;
84.
85.         my \$reflectedColor = drawRay(\$intersection,\$dirNew,1);
86.
87.         # Let's make it a bit reddish.
88.
89.         my (\$rr,\$rg,\$rb) = @\$reflectedColor;
90.
91.         \$reflectedColor = [ \$rr*1.2,\$rg/1.2,\$rb/1.2 ];
92.
93.         glColor(@\$reflectedColor);
94.         glPushMatrix;
95.         glTranslate(\$intersection->array);
96.         glutSolidSphere(0.05,8,8);
97.         glPopMatrix;
98.
99.         return \$reflectedColor;
100.
101.
102.     } elsif (defined(\$intersection = rayFloorIntersection(\$r0,\$dir))) {
103.             # We hit the floor.
104.
105.             my \$floorVector = \$intersection - \$floorPos;
106.             my \$tileSize = 0.5;
107.
108.             my \$interX = int((\$floorVector . \$floorX)/\$tileSize);
109.             my \$interY = int((\$floorVector . \$floorY)/\$tileSize);
110.
111.             # (\$interX, \$interY) give floor tile coordinates.
112.
113.             my \$xType = (\$interX % 2 ) ;
114.             my \$yType = (\$interY % 2 ) ;
115.
116.             my \$brightness = 200.0/(\$floorVector . \$floorVector);
117.             if (\$brightness>1.0) { \$brightness = 1.0; }
118.             if (\$brightness<0.0) { \$brightness = 0.0; }
119.             my \$color;
120.             if (\$xType==\$yType) {
121.                 \$color = [\$brightness,\$brightness,\$brightness];
122.             } else {
123.                 \$color = [\$brightness,0,\$brightness];
124.             }
125.
126.             glColor(@\$color);
127.             glBegin(GL_LINES);
128.                 glVertex(\$r0->array);
129.                 glVertex(\$intersection->array);
130.             glEnd;
131.             glPushMatrix;
132.             glTranslate(\$intersection->array);
133.             glutSolidSphere(0.1,8,8);
134.             glPopMatrix;
135.             return \$color;
136.     } else {
137.             # Neither ray nor floor, therefore sky.
138.
139.             my \$cosTheta = (\$dir . \$floorUp) / (\$dir->length * \$floorUp->length);
140.             \$cosTheta *= 0.5;
141.
142.             my @horizonColor = ( 1,0.0,0.0);
143.             my @skyColor = ( 0.0,0.0,1.0 );
144.
145.             my @color;
146.             for (0..2) {
147.                 push @color,\$horizonColor[\$_]*\$cosTheta +
148.                 (1.0-\$cosTheta)*\$skyColor[\$_];
149.             }
150.             glColor(@color);
151.             glBegin(GL_LINES);
152.                 glVertex(\$r0->array);
153.                 glVertex((\$r0+2.0*\$dir)->array);
154.             glEnd;
155.
156.             return \@color;
157.     }
158.
159. }
160.
161. sub rayFloorIntersection {
162.     my (\$r0,\$dir) = @_;
163.
164.     my \$denom = \$floorUp . \$dir;
165.     if (\$denom == 0.0) { return ; } # line parallel to floor
166.
167.     my \$lambda = ( \$floorUp . (  \$floorPos - \$r0 ) ) / \$denom;
168.
169.     if (\$lambda>0.0) {
170.         my \$intersection = \$r0 + \$lambda*\$dir;
171.         return \$intersection;
172.     }
173.
174. }
175.
176. sub raySphereIntersection {
177.     my (\$r0,\$dir) = @_;
178.
179.     my \$a = \$dir . \$dir;
180.     my \$b = 2.0 * (\$dir . ( \$r0 - \$spherePos ) );
181.     my \$c = ((\$r0 - \$spherePos) . (\$r0 - \$spherePos)) - \$sphereRad*\$sphereRad;
182.
183.     my \$discriminant = \$b*\$b - 4.0*\$a*\$c;
184.     if (\$discriminant<0.0) {
185.     } else {
186.         my \$root = sqrt(\$discriminant);
187.         my \$lambda0 = (-\$b - \$root)/(2.0*\$a);
188.         my \$lambda1 = (-\$b - \$root)/(2.0*\$a);
189.
190.         my \$lambda;
191.         if (\$lambda1<\$lambda0) { \$lambda=\$lambda1; } else { \$lambda=\$lambda0; }
192.
193.         my \$intersection = \$r0 + \$lambda*\$dir;
194.         return \$intersection;
195.     }
196. }
197.
198.
199. sub drawViewer {
200.     glPushMatrix;
201.     glTranslate(\$viewerPos->array);
202.     glColor(1,1,1,1);
203.     glutSolidSphere(0.1,10,10);
204.     glPopMatrix;
205. }
206.
207. sub drawPlane {
208.     my \$r0 = \$viewerPos + \$viewerForward;
209.
210.     my \$r;
211.     glPushMatrix;
212.
213.     glColor(0.7,0.7,0.7,0.5);
214.     glDisable(GL_CULL_FACE);
215.
217.         glVertex((\$r0 - \$viewerPlaneX - \$viewerPlaneY)->array);
218.         glVertex((\$r0 - \$viewerPlaneX + \$viewerPlaneY)->array);
219.         glVertex((\$r0 + \$viewerPlaneX + \$viewerPlaneY)->array);
220.         glVertex((\$r0 + \$viewerPlaneX - \$viewerPlaneY)->array);
221.     glEnd;
222.
223.     glPopMatrix;
224. }
225.
226.
227. sub drawFloor {
228.     my \$r0 = \$floorPos;
229.
230.     my \$r;
231.     glPushMatrix;
232.
233.     glColor(0,1,0,0.5);
234.     glDisable(GL_CULL_FACE);
235.
237.         glVertex((\$r0 - \$floorX - \$floorY)->array);
238.         glVertex((\$r0 - \$floorX + \$floorY)->array);
239.         glVertex((\$r0 + \$floorX + \$floorY)->array);
240.         glVertex((\$r0 + \$floorX - \$floorY)->array);
241.     glEnd;
242.
243.     glPopMatrix;
244. }
245.
246. sub drawSphere {
247.     glPushMatrix;
248.         glTranslate(\$spherePos->array);
249.         glColor(1,0,0,1.0);