program raygl use opengl_gl use opengl_glu use opengl_glut implicit none type ray real, dimension(0:2) :: origin real, dimension(0:2) :: direction end type ray type hit_record real :: t real, dimension(0:2) :: p real, dimension(0:2) :: normal end type hit_record integer, parameter :: nx = 500 integer, parameter :: ny = 500 integer :: i, j, ir, ig, ib, dummy, inp = 0 real :: u, v, PI character :: c real, dimension(0:2) :: col,lower_left_corner,horizontal,vertical,origin,forwards_back,left_right type(ray) :: r integer :: handle call glutinit call glutinitdisplaymode(ior(GLUT_SINGLE,GLUT_RGB)) call glutInitWindowSize(500_glcint,500_glcint) call glutInitWindowPosition (0_glcint, 0_glcint) handle = glutCreateWindow ("Raytrace Sphere Test") call glutSpecialFunc(processNormalKeys) call glutDisplayFunc(display) call glutIdleFunc(display) call myinit call glutMainLoop contains subroutine myinit call glClearColor(1.0_glclampf, 1.0_glclampf, 1.0_glclampf, 1.0_glclampf) call glColor3f(1.0_glclampf, 0.0_glclampf, 0.0_glclampf) call glMatrixMode(GL_PROJECTION) call glLoadIdentity call gluOrtho2D(0.0_gldouble, 500.0_gldouble, 0.0_gldouble, 500.0_gldouble) call glMatrixMode(GL_MODELVIEW) call glPointSize(3.0_glfloat) PI = 4*atan(1.) lower_left_corner = [-2.0, -1.0, -1.0] horizontal = [4.0, 0.0, 0.0] vertical = [0.0, 2.0, 0.0] origin = [0.0, 0.0, 0.0] end subroutine myinit subroutine display do j = ny-1, 0, -1 do i = 1, nx, 1 u = real(i)/real(nx) v = real(j)/real(ny) r%origin = origin r%direction = lower_left_corner + u*horizontal + v*vertical call color(r, col) call glBegin(GL_POINTS) ir = int(255.99*col(0)) ig = int(255.99*col(1)) ib = int(255.99*col(2)) call glColor3f(real(ir)/255.0, real(ig)/255.0, real(ib)/255.0) call glVertex3f(real(i), real(j), 0.0_glfloat) call glEnd end do end do call glFlush end subroutine display subroutine processNormalKeys(key,x,y) integer(kind=glint) , intent(in out) :: key integer(kind=glcint) , intent(in out) :: x, y call cross(forwards_back,horizontal,vertical) call norm(forwards_back) call cross(left_right,vertical,forwards_back) call norm(left_right) select case (key) case(iachar('W'),iachar('w')) !w origin = origin - forwards_back/16. case(iachar('A'),iachar('a')) !a origin = origin - left_right/16. case(iachar('S'),iachar('s')) !s origin = origin + forwards_back/16. case(iachar('D'),iachar('d')) !d origin = origin + left_right/16. case(iachar('Q'),iachar('q')) !q call turn_y(lower_left_corner,PI/16.) call turn_y(horizontal,PI/16.) call turn_y(vertical,PI/16.) case(iachar('E'),iachar('e')) !e call turn_y(lower_left_corner,-PI/16.) call turn_y(horizontal,-PI/16.) call turn_y(vertical,-PI/16.) end select end subroutine processNormalKeys subroutine color(r, o) type(ray),intent(inout) :: r real, dimension(0:2), intent(inout) :: o real, dimension(0:2) :: unit_direction, o2, N real :: t, h call hit_sphere([0.0,0.0,-1.0], 0.5, r, h) if ( h > 0.0 ) then call point_at_parameter(r,h,o2) call unit_vector( o2 - [0.0,0.0,-1.0] , N ) o = 0.5*[N(0)+1, N(1)+1, N(2)+1] return end if call unit_vector(r%direction,unit_direction) t = 0.5 * unit_direction(1) + 1 o = (1.0-t) * [1.0,1.0,1.0] + t * [0.5,0.7,1.0] end subroutine color subroutine hit_sphere(center, radius, r, hit) type(ray), intent(in) :: r real, intent(in) :: radius real, dimension(0:2), intent(in) :: center real, intent(inout) :: hit real, dimension(0:2) :: oc real :: a,b,c,discriminant oc = r%origin - center a = dot_product(r%direction,r%direction) b = 2.0 * dot_product(oc,r%direction) c = dot_product(oc,oc) - radius*radius discriminant = b*b - 4*a*c if (discriminant < 0) then hit = -1.0 else hit = (-b - sqrt(discriminant)) / (2.0*a) end if end subroutine hit_sphere subroutine unit_vector(v,v2) real, dimension(0:2), intent(in) :: v real, dimension(0:2), intent(out) :: v2 v2 = v / sqrt(v(0)*v(0) + v(1)*v(1) + v(2)*v(2)) end subroutine unit_vector subroutine point_at_parameter(r,t,o) type(ray),intent(inout) :: r real, intent(in) :: t real, dimension(0:2), intent(inout) :: o o = r%origin + t*r%direction end subroutine point_at_parameter subroutine turn_x(v, d) real, dimension(0:2),intent(inout) :: v real, intent(in) :: d v(1) = cos(d) * v(1) + (-(sin(d))) * v(2) v(2) = sin(d) * v(1) + cos(d) * v(2) end subroutine subroutine turn_y(v, d) real, dimension(0:2),intent(inout) :: v real, intent(in) :: d v(0) = cos(d) * v(0) + sin(d) * v(2) v(2) = (-(sin(d))) * v(0) + cos(d) * v(2) end subroutine turn_y subroutine turn_z(v, d) real, dimension(0:2),intent(inout) :: v real, intent(in) :: d v(0) = cos(d) * v(0) + (-(sin(d))) * v(1) v(1) = sin(d) * v(0) + cos(d) * v(1) end subroutine turn_z subroutine norm(vec3) real,dimension(0:2),intent(inout) :: vec3 vec3(0) = vec3(0)/norm2(vec3) vec3(1) = vec3(1)/norm2(vec3) vec3(2) = vec3(2)/norm2(vec3) end subroutine norm subroutine cross(cp, a, b) real,dimension(0:2),intent(out) :: cp real,dimension(0:2),intent(in) :: a real,dimension(0:2),intent(in) :: b cp(0) = a(1) * b(2) - a(2) * b(1) cp(1) = a(2) * b(0) - a(0) * b(2) cp(2) = a(0) * b(1) - a(1) * b(0) end subroutine cross end program raygl