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);
  22. my $sphereRad = 0.3;
  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.     return;
  175. }
  176.  
  177. sub raySphereIntersection {
  178.     my ($r0,$dir) = @_;
  179.  
  180.     my $a = $dir . $dir;
  181.     my $b = 2.0 * ($dir . ( $r0 - $spherePos ) );
  182.     my $c = (($r0 - $spherePos) . ($r0 - $spherePos)) - $sphereRad*$sphereRad;
  183.  
  184.     my $discriminant = $b*$b - 4.0*$a*$c;
  185.     if ($discriminant<0.0) {
  186.         return ;
  187.     } else {
  188.         my $root = sqrt($discriminant);
  189.         my $lambda0 = (-$b - $root)/(2.0*$a);
  190.         my $lambda1 = (-$b - $root)/(2.0*$a);
  191.  
  192.         my $lambda;
  193.         if ($lambda1<$lambda0) { $lambda=$lambda1; } else { $lambda=$lambda0; }
  194.  
  195.         my $intersection = $r0 + $lambda*$dir;
  196.         return $intersection;
  197.     }
  198. }
  199.  
  200.  
  201. sub drawViewer {
  202.     glPushMatrix;
  203.     glTranslate($viewerPos->array);
  204.     glColor(1,1,1,1);
  205.     glutSolidSphere(0.1,10,10);
  206.     glPopMatrix;
  207. }
  208.  
  209. sub drawPlane {
  210.     my $r0 = $viewerPos + $viewerForward;
  211.  
  212.     my $r;
  213.     glPushMatrix;
  214.  
  215.     glColor(0.7,0.7,0.7,0.5);
  216.     glDisable(GL_CULL_FACE);
  217.  
  218.     glBegin(GL_QUADS);
  219.         glVertex(($r0 - $viewerPlaneX - $viewerPlaneY)->array);
  220.         glVertex(($r0 - $viewerPlaneX + $viewerPlaneY)->array);
  221.         glVertex(($r0 + $viewerPlaneX + $viewerPlaneY)->array);
  222.         glVertex(($r0 + $viewerPlaneX - $viewerPlaneY)->array);
  223.     glEnd;
  224.  
  225.     glPopMatrix;
  226. }
  227.  
  228.  
  229. sub drawFloor {
  230.     my $r0 = $floorPos;
  231.  
  232.     my $r;
  233.     glPushMatrix;
  234.  
  235.     glColor(0,1,0,0.5);
  236.     glDisable(GL_CULL_FACE);
  237.  
  238.     glBegin(GL_QUADS);
  239.         glVertex(($r0 - $floorX - $floorY)->array);
  240.         glVertex(($r0 - $floorX + $floorY)->array);
  241.         glVertex(($r0 + $floorX + $floorY)->array);
  242.         glVertex(($r0 + $floorX - $floorY)->array);
  243.     glEnd;
  244.  
  245.     glPopMatrix;
  246. }
  247.  
  248. sub drawSphere {
  249.     glPushMatrix;
  250.         glTranslate($spherePos->array);
  251.         glColor(1,0,0,1.0);
  252.         glutSolidSphere($sphereRad,16,16);
  253.     glPopMatrix;
  254. }

Raw Paste


Login or Register to edit or fork this paste. It's free.