ray tracing tutorial

Everything related to 3D programming
User avatar
Hades
Enthusiast
Enthusiast
Posts: 188
Joined: Tue May 17, 2005 8:39 pm

ray tracing tutorial

Post by Hades »

Hi Guys,

I've played with the idea of posting a tutorial for ray tracing for many years now, but wasn't quite happy with what I was coming up with. Explaining stuff and neat, simple coding aren't my strong suit...
But whatever, I will just give it a try.

I will focus on making the individual programs as simple and easy to understand as possible. The downside of this is, that to add more functionality, I will have to change a lot of code between programs.
So, please, use this just as a means to understand ray tracing, not as a reference how to best implement it.

Code: Select all

ScreenWidth = 600 : ScreenHeight = 400

If OpenWindow(0, 0, 0, ScreenWidth, ScreenHeight, "Ray Tracing Tutorial 1", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, ScreenWidth, ScreenHeight)
    If StartDrawing(ImageOutput(0))
      
      ScreenZ = ScreenWidth ; Distance between the (virtual) eye and screen = width of screen for a 45 degrees horizontal field of view
      
      ; A sphere straight ahead and as high as the screen, but slightly further away
      SphereRadius.f = ScreenHeight / 2
      SphereX.f = 0
      SphereY.f = 0
      SphereZ.f = ScreenWidth * 1.2
      
      ; For every pixel on the screen
      For ScreenY = 0 To ScreenHeight - 1
        For ScreenX = 0 To ScreenWidth - 1
          
          ; Create a ray from the eye to the screen.
          RayOriginX.f = 0 ; Position
          RayOriginY.f = 0 ; of the
          RayOriginZ.f = 0 ; eye
          RayVecX.f = ScreenX - ScreenWidth / 2 ; Shift 0,0 to the center of the screen
          RayVecY.f = ScreenHeight / 2 - ScreenY ; and making sure that up is positive
          RayVecZ.f = ScreenZ
          ; Rays have a starting point and a direction (vector). When doing math with vectors the result will
          ; be in multiples of the length of the vector, so we need to make sure the lenght is 1, or it gets messy.
          ; This is called normalizing:
          RayLenght.f = Sqr(RayVecX * RayVecX + RayVecY * RayVecY + RayVecZ * RayVecZ)
          RayVecX = RayVecX / RayLenght
          RayVecY = RayVecY / RayLenght
          RayVecZ = RayVecZ / RayLenght
          
          ; Let's check if the ray hits the sphere. 
          RelPosX.f = RayOriginX - SphereX
          RelPosY.f = RayOriginY - SphereY
          RelPosZ.f = RayOriginZ - SphereZ
          b.f = RayVecX * RelPosX + RayVecY * RelPosY + RayVecZ * RelPosZ
          c.f = (RelPosX * RelPosX + RelPosY * RelPosY + RelPosZ * RelPosZ) - SphereRadius * SphereRadius
          d.f = b * b - c
          If d > 0.0 ; Ray vector intersects sphere. (Not testing if the sphere is in front or behind the ray origin for now) 
            Plot(ScreenX, ScreenY, RGB(200, 0 ,0))
          EndIf
        Next
      Next
      
      StopDrawing()
    EndIf
  EndIf
  ImageGadget(0, 0, 0, 0, 0, ImageID(0))
  
  Repeat
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow
  
EndIf

End
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: ray tracing tutorial

Post by djes »

Great news ! You have a follower :D
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: ray tracing tutorial

Post by applePi »

Thanks, can be useful for me since i was thinking to use ray tracing to know the size of a mesh without resorting to engine functions.
the small tutorials is the best to convey the ideas
User avatar
Hades
Enthusiast
Enthusiast
Posts: 188
Joined: Tue May 17, 2005 8:39 pm

Re: ray tracing tutorial

Post by Hades »

The result from the first code looked more like a filled circle than a sphere, and we actually shouldn't have been able to see it, because there was no light. Let's change that!

Code: Select all

ScreenWidth = 600 : ScreenHeight = 400

; Because we will use vectors and coordinates more and more, lets create a structure for it
Structure xyz
  x.f
  y.f
  z.f
EndStructure

; Also a procedure for normalizing vectors will be useful
Procedure.f Normalize(*Vector.xyz)
  Protected VectorLength.f
  VectorLength = Sqr(*Vector\x * *Vector\x + *Vector\y * *Vector\y + *Vector\z * *Vector\z)
  *Vector\x = *Vector\x / VectorLength
  *Vector\y = *Vector\y / VectorLength
  *Vector\z = *Vector\z / VectorLength
EndProcedure

If OpenWindow(0, 0, 0, ScreenWidth, ScreenHeight, "Ray Tracing Tutorial 2: Basic Light", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, ScreenWidth, ScreenHeight)
    If StartDrawing(ImageOutput(0))
      
      ScreenZ = ScreenWidth
      
      Define Sphere.xyz
      SphereRadius.f = ScreenHeight / 2
      Sphere\x = 0
      Sphere\y = 0
      Sphere\z = ScreenWidth * 1.2
      
      ; Create a directional light (like the sun, for all intents and purposes infinitly far away, with parallel light beams)
      Define LightVec.xyz
      LightVec\x = 1.0  ; from the right,
      LightVec\y = 1.0  ; above,
      LightVec\z = -1.0 ; and behind the eye
      ; and always normalize the vectors:
      Normalize(LightVec)
      
      For ScreenY = 0 To ScreenHeight - 1
        For ScreenX = 0 To ScreenWidth - 1
          
          Define RayOrigin.xyz, RayVec.xyz
          RayOrigin\x = 0
          RayOrigin\y = 0
          RayOrigin\z = 0
          RayVec\x = ScreenX - ScreenWidth / 2
          RayVec\y = ScreenHeight / 2 - ScreenY
          RayVec\z = ScreenZ
          Normalize(RayVec)
          
          Define RelPos.xyz
          RelPos\x = RayOrigin\x - Sphere\x
          RelPos\y = RayOrigin\y - Sphere\y
          RelPos\z = RayOrigin\z - Sphere\z
          b.f = RayVec\x * RelPos\x + RayVec\y * RelPos\y + RayVec\z * RelPos\z
          c.f = (RelPos\x * RelPos\x + RelPos\y * RelPos\y + RelPos\z * RelPos\z) - SphereRadius * SphereRadius
          d.f = b * b - c
          If d > 0.0
            ; As we will now need the distance to the intersection anyway, I'll add the rest of the intersection test
            d = Sqr(d)
            DistanceToIntersection.f = -b - d
            If DistanceToIntersection > 0.0 ; The intersection is in front of the ray origin. (Your not looking away from it)
              
              ; To figure out how much light hits the surface we need to determin the angle between the incoming light 
              ; and the normal (perpendicular vector) of the surface at the point of intersection.
              
              ; For point of intersection we go from the origin of the ray along it's direction for the distance the intersection test gave us
              Define Intersection.xyz
              Intersection\x = RayOrigin\x + RayVec\x * DistanceToIntersection
              Intersection\y = RayOrigin\y + RayVec\y * DistanceToIntersection
              Intersection\z = RayOrigin\z + RayVec\z * DistanceToIntersection
              
              ; The normal of a point on a sphere has the same direction as a vector from the center of the sphere to that point on its surface.
              Define SurfaceNormal.xyz
              SurfaceNormal\x = Intersection\x - Sphere\x
              SurfaceNormal\y = Intersection\y - Sphere\y
              SurfaceNormal\z = Intersection\z - Sphere\z
              Normalize(SurfaceNormal)
              
              ; The brightness of an ideal diffusely reflecting surface is directly proportional to the cosine of
              ; the angle between the surfaces normal and the incident light. (check Lambert's cosine law)
              ; And the 'dot product' (of two normalized vectors) gives us just that:
              Brightness.f = SurfaceNormal\x * LightVec\x + SurfaceNormal\y * LightVec\y + SurfaceNormal\z * LightVec\z
              
              If Brightness > 0.0
                Plot(ScreenX, ScreenY, RGB(Brightness * 200, 0 ,0))
              EndIf  
            EndIf  
          EndIf
        Next
      Next
      
      StopDrawing()
    EndIf
  EndIf
  ImageGadget(0, 0, 0, 0, 0, ImageID(0))
  
  Repeat
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow
  
EndIf

End
User avatar
Hades
Enthusiast
Enthusiast
Posts: 188
Joined: Tue May 17, 2005 8:39 pm

Re: ray tracing tutorial

Post by Hades »

With light we need shadow too...

(I am trying to keep the comments in the code down, to not wear you down with walls of text stating the obvious, but figuring out what is obvious and what just seems that way to me, because I am doing this for so long, is close to impossible for me. So, if there are questions and complaints, please don't hold back)

Code: Select all

ScreenWidth = 600 : ScreenHeight = 400

Structure xyz
  x.f
  y.f
  z.f
EndStructure

Structure sphere
  radius.f
  x.f
  y.f
  z.f
EndStructure
Global NewList Sphere.sphere()

Procedure Normalize(*Vector.xyz)
  Protected VectorLength.f
  VectorLength = Sqr(*Vector\x * *Vector\x + *Vector\y * *Vector\y + *Vector\z * *Vector\z)
  *Vector\x = *Vector\x / VectorLength
  *Vector\y = *Vector\y / VectorLength
  *Vector\z = *Vector\z / VectorLength
EndProcedure

Procedure.f IntersectSphere(*RayOrigin.xyz, *RayVec.xyz, *Sphere.sphere)
  Protected RelPos.xyz, b.f, c.f, d.f, DistanceToIntersection.f
  RelPos\x = *RayOrigin\x - *Sphere\x
  RelPos\y = *RayOrigin\y - *Sphere\y
  RelPos\z = *RayOrigin\z - *Sphere\z
  b = *RayVec\x * RelPos\x + *RayVec\y * RelPos\y + *RayVec\z * RelPos\z
  c = (RelPos\x * RelPos\x + RelPos\y * RelPos\y + RelPos\z * RelPos\z) - *Sphere\radius * *Sphere\radius
  d = b * b - c
  If d > 0.0
    d = Sqr(d)
    DistanceToIntersection = -b - d
    If DistanceToIntersection > 0.0
      ProcedureReturn DistanceToIntersection
    EndIf
  EndIf    
  ProcedureReturn -1.0 ; no hit
EndProcedure  

Procedure AddSphere(radius.f, x.f, y.f, z.f)
  AddElement(Sphere())
  Sphere()\radius = radius
  Sphere()\x = x
  Sphere()\y = y
  Sphere()\z = z
EndProcedure  

If OpenWindow(0, 0, 0, ScreenWidth, ScreenHeight, "Ray Tracing Tutorial 3: Shadow", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, ScreenWidth, ScreenHeight)
    If StartDrawing(ImageOutput(0))
      
      ScreenZ = ScreenWidth
      
      AddSphere(ScreenHeight / 2, 0, 0, ScreenWidth * 1.2)                                                    ; Well, I had thought that using multiples of the screen size for setting up
      AddSphere(ScreenHeight * 50, 0, -ScreenHeight * 50.5, ScreenWidth * 1.2)                                ; the scene would help you with getting a feel for what's going on with the math.
      AddSphere(ScreenHeight / 10, -ScreenHeight / 4, ScreenHeight / 4, ScreenWidth * 1.2 - ScreenHeight / 2) ; Somehow I start to doubt that now...
      
      Define LightVec.xyz
      LightVec\x = 1.0
      LightVec\y = 1.0
      LightVec\z = -1.0
      Normalize(LightVec)
      
      For ScreenY = 0 To ScreenHeight - 1
        For ScreenX = 0 To ScreenWidth - 1
          
          Define RayOrigin.xyz, RayVec.xyz
          RayOrigin\x = 0
          RayOrigin\y = 0
          RayOrigin\z = 0
          RayVec\x = ScreenX - ScreenWidth / 2
          RayVec\y = ScreenHeight / 2 - ScreenY
          RayVec\z = ScreenZ
          Normalize(RayVec)
          
          ; Check all spheres for intersection
          ClosestIntersection.f = 1000000.0 ; Arbitrary high value outside of the scene. (Can also be thought of as the lenght of the ray)
          SphereHit = -1
          ForEach Sphere()
            DistanceToIntersection.f = IntersectSphere(RayOrigin, RayVec, Sphere())
            ; We are only interested in the closest hit...  
            If DistanceToIntersection > 0.0 And DistanceToIntersection < ClosestIntersection
              ClosestIntersection = DistanceToIntersection ; so we need to keep track of that,
              SphereHit = ListIndex(Sphere()) ; and of the sphere that was hit.
            EndIf  
          Next
          
          If SphereHit >= 0
            SelectElement(Sphere(), SphereHit)
            
            Define Intersection.xyz
            Intersection\x = RayOrigin\x + RayVec\x * ClosestIntersection
            Intersection\y = RayOrigin\y + RayVec\y * ClosestIntersection
            Intersection\z = RayOrigin\z + RayVec\z * ClosestIntersection
            
            Define SurfaceNormal.xyz
            SurfaceNormal\x = Intersection\x - Sphere()\x
            SurfaceNormal\y = Intersection\y - Sphere()\y
            SurfaceNormal\z = Intersection\z - Sphere()\z
            Normalize(SurfaceNormal)
            
            Brightness.f = SurfaceNormal\x * LightVec\x + SurfaceNormal\y * LightVec\y + SurfaceNormal\z * LightVec\z
            
            If Brightness > 0.0
              ; Let's check if there is something blocking the light.
              Shadow = #False
              ForEach Sphere()
                ; The sphere can't cast a shadow on itself (but due to rounding errors it might), so let's skip it.
                If ListIndex(Sphere()) <> SphereHit
                  ; To check for shadow we use the point of intersection as a new ray origin and the vector to the light as the ray vector...
                  If IntersectSphere(Intersection, LightVec, Sphere()) > 0.0 ; and if that ray hits something...
                    Shadow = #True ; we have shadow...
                    Break ; and we can stop looking any further.
                  EndIf  
                EndIf
              Next  
              If Not Shadow
                Plot(ScreenX, ScreenY, RGB(Brightness * 200, 0 ,0))
              EndIf  
            EndIf  
          EndIf  
        Next
      Next
      
      StopDrawing()
    EndIf
  EndIf
  ImageGadget(0, 0, 0, 0, 0, ImageID(0))
  
  Repeat
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow
  
EndIf

End
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: ray tracing tutorial

Post by #NULL »

awesome, i love it :)
I didn't know you can do that with such little code.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: ray tracing tutorial

Post by djes »

Great ! :mrgreen:
User avatar
Hades
Enthusiast
Enthusiast
Posts: 188
Joined: Tue May 17, 2005 8:39 pm

Re: ray tracing tutorial

Post by Hades »

I am really happy you guys like it so far, because I was rather unsure about it.
I've taken a day off today, as I'm not feeling to well, so nothing for tomorrow. :(
User avatar
kenmo
Addict
Addict
Posts: 1967
Joined: Tue Dec 23, 2003 3:54 am

Re: ray tracing tutorial

Post by kenmo »

Take your time :)

I've played with ray-tracing in PureBasic, basically a few geometries with textures + bump-mapping... fun stuff.

I like these short, incremental demos too
User avatar
Kurzer
Enthusiast
Enthusiast
Posts: 664
Joined: Sun Jun 11, 2006 12:07 am
Location: Near Hamburg

Re: ray tracing tutorial

Post by Kurzer »

Hi Hades, thanks for your great tutorial.

Your code is easy to understand and clean, so that even someone without "raytracing experience" can follow all the steps. Really exciting to see how it works - also mathematically speaking. Since I never had to deal with complicated mathematics in my life, I have forgotten many things. All the more beautiful to see how elegantly it can actually be implemented.

This reminds me of my first contact with raytracing in the 80's on my old Amiga computer (the program was called Fastray, was extremely slow and - I think - programmed in pascal by an individual (a computer freak). I was fascinated.... today Fastray has become Cinema4D).

Thank you for this trip back in time.
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520, User age in 2023: 56y
"Happiness is a pet." | "Never run a changing system!"
User avatar
pf shadoko
Enthusiast
Enthusiast
Posts: 285
Joined: Thu Jul 09, 2015 9:07 am

Re: ray tracing tutorial

Post by pf shadoko »

very interesting

PS: Yes, you look bad indeed. You have a greyish tint and a yellow eye.
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: ray tracing tutorial

Post by DK_PETER »

Just a note:
You should've reserved a number of posts at the beginning for your tuturial.
Anyway: Please, keep going, I like your tutorial. :wink:
Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
User avatar
Hades
Enthusiast
Enthusiast
Posts: 188
Joined: Tue May 17, 2005 8:39 pm

Re: ray tracing tutorial

Post by Hades »

Thanks for the nice words guys! :D

@kurzer: I've started ray tracing on the Amiga in the 80's too, but was more interested in coding one, as I lack any artistic skills.

@pf shadoko: That's me on a good day, you should see a current picture. :wink:

@DK_Peter: I thought about that, but I didn't know how much I would need, so I'll just put links in the first post, when it becomes necessary.


It takes me crazy long to write a single one of those programs, because I want to make them as clear as possible + my health sucks.
So my original plan of getting out 1 per day (what I thought was very slow), won't work.

I'll just see what I can get done, without any schedule.
User avatar
Hades
Enthusiast
Enthusiast
Posts: 188
Joined: Tue May 17, 2005 8:39 pm

Re: ray tracing tutorial

Post by Hades »

And now reflections.

The lack of specular highlight and ambient light are rather obvious, but the usual way to do this for simple ray tracers are actually cheats and doing the real deal would probably to much for this tutorial series.
I'll hopefully squeeze in a part with a bunch of those cheats at some point, but I wanted to get the most important 'real' stuff done first.

Code: Select all

ScreenWidth = 600 : ScreenHeight = 400

Structure xyz
  x.f
  y.f
  z.f
EndStructure

Structure sphere
  radius.f
  x.f
  y.f
  z.f
EndStructure
Global NewList Sphere.sphere()

Global LightVec.xyz

Procedure Normalize(*Vector.xyz)
  Protected VectorLength.f
  VectorLength = Sqr(*Vector\x * *Vector\x + *Vector\y * *Vector\y + *Vector\z * *Vector\z)
  *Vector\x = *Vector\x / VectorLength
  *Vector\y = *Vector\y / VectorLength
  *Vector\z = *Vector\z / VectorLength
EndProcedure

Procedure.f IntersectSphere(*RayOrigin.xyz, *RayVec.xyz, *Sphere.sphere)
  Protected RelPos.xyz, b.f, c.f, d.f, DistanceToIntersection.f
  RelPos\x = *RayOrigin\x - *Sphere\x
  RelPos\y = *RayOrigin\y - *Sphere\y
  RelPos\z = *RayOrigin\z - *Sphere\z
  b = *RayVec\x * RelPos\x + *RayVec\y * RelPos\y + *RayVec\z * RelPos\z
  c = (RelPos\x * RelPos\x + RelPos\y * RelPos\y + RelPos\z * RelPos\z) - *Sphere\radius * *Sphere\radius
  d = b * b - c
  If d > 0.0
    d = Sqr(d)
    DistanceToIntersection = -b - d
    If DistanceToIntersection > 0.0
      ProcedureReturn DistanceToIntersection
    EndIf
  EndIf    
  ProcedureReturn -1.0 ; no hit
EndProcedure  

Procedure AddSphere(radius.f, x.f, y.f, z.f)
  AddElement(Sphere())
  Sphere()\radius = radius
  Sphere()\x = x
  Sphere()\y = y
  Sphere()\z = z
EndProcedure  

; As with reflection, a ray hitting something can spawn one or more new rays that need to be traced through the scene, too. 
; Doing this with recursion is the easiest way, so let's put everything into a procedure that can call itself.
Procedure.f TraceRay(*RayOrigin.xyz, *RayVec.xyz, RecursionDepth.i)
  Protected ClosestIntersection.f, SphereHit.i, Brightness.f, A.f, Intersection.xyz, SurfaceNormal.xyz, ReflectedRayVec.xyz
  ClosestIntersection = 1000000.0
  SphereHit = -1
  ForEach Sphere()
    DistanceToIntersection.f = IntersectSphere(*RayOrigin, *RayVec, Sphere())
    If DistanceToIntersection > 0.0 And DistanceToIntersection < ClosestIntersection
      ClosestIntersection = DistanceToIntersection
      SphereHit = ListIndex(Sphere())
    EndIf  
  Next
  
  If SphereHit >= 0
    SelectElement(Sphere(), SphereHit)
    
    Intersection\x = *RayOrigin\x + *RayVec\x * ClosestIntersection
    Intersection\y = *RayOrigin\y + *RayVec\y * ClosestIntersection
    Intersection\z = *RayOrigin\z + *RayVec\z * ClosestIntersection
    
    SurfaceNormal\x = Intersection\x - Sphere()\x
    SurfaceNormal\y = Intersection\y - Sphere()\y
    SurfaceNormal\z = Intersection\z - Sphere()\z
    Normalize(SurfaceNormal)
    
    Brightness = SurfaceNormal\x * LightVec\x + SurfaceNormal\y * LightVec\y + SurfaceNormal\z * LightVec\z
    If Brightness > 0.0
      ForEach Sphere()
        If ListIndex(Sphere()) <> SphereHit
          If IntersectSphere(Intersection, LightVec, Sphere()) > 0.0
            Brightness = 0.0 ; Shadow
            Break
          EndIf  
        EndIf
      Next 
    Else 
      Brightness = 0.0 ; We don't want 'negative brightness' (when light hits the surface from behind)
    EndIf
    
    ; Let's put a checkerboard pattern on the bottom sphere to make this less visually boring (just a quick hack, can be ignored)
    If SphereHit = 1 And ((Int((1000 + Intersection\x) * 0.01) + Int(1000 + Intersection\z * 0.01)) & 1)
      Brightness * 0.4
    EndIf
    
    ; Reflection:
    If RecursionDepth < 10 ; To prevent stack overflow due to too many recursions (just in case you start experimenting with the code)
      If SphereHit = 0 ; first sphere in list is reflective
        
        ; Compute the reflected ray by projecting the incoming ray onto the surface normal  \| -> |/ 
        A = 2.0 * (SurfaceNormal\x * *RayVec\x + SurfaceNormal\y * *RayVec\y + SurfaceNormal\z * *RayVec\z) ; 2 * dot product
        ReflectedRayVec\x = *RayVec\x - A * SurfaceNormal\x
        ReflectedRayVec\y = *RayVec\y - A * SurfaceNormal\y
        ReflectedRayVec\z = *RayVec\z - A * SurfaceNormal\z
        
        ; trace the reflected ray from the point of intersection through the scene
        Brightness * 0.3 + 0.7 * TraceRay(Intersection, ReflectedRayVec, RecursionDepth + 1) ; 30% diffuse + 70% reflective
      EndIf
    EndIf
  EndIf
  ProcedureReturn Brightness
EndProcedure  

If OpenWindow(0, 0, 0, ScreenWidth, ScreenHeight, "Ray Tracing Tutorial 4: Reflection", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, ScreenWidth, ScreenHeight)
    If StartDrawing(ImageOutput(0))
      
      ScreenZ = ScreenWidth
      
      AddSphere(ScreenHeight / 2, 0, 0, ScreenWidth * 1.2)
      AddSphere(ScreenHeight * 50, 0, -ScreenHeight * 50.5, ScreenWidth * 1.2)
      AddSphere(ScreenHeight / 10, -ScreenHeight / 4, ScreenHeight / 4, ScreenWidth * 1.2 - ScreenHeight / 2)
      
      LightVec\x = 1.0
      LightVec\y = 1.0
      LightVec\z = -1.0
      Normalize(LightVec)
      
      For ScreenY = 0 To ScreenHeight - 1
        For ScreenX = 0 To ScreenWidth - 1
          
          Define RayOrigin.xyz, RayVec.xyz
          RayOrigin\x = 0
          RayOrigin\y = 0
          RayOrigin\z = 0
          RayVec\x = ScreenX - ScreenWidth / 2
          RayVec\y = ScreenHeight / 2 - ScreenY
          RayVec\z = ScreenZ
          Normalize(RayVec)
          
          Brightness.f = TraceRay(RayOrigin, RayVec, 1)
          
          Plot(ScreenX, ScreenY, RGB(Brightness * 200, 0 ,0))
        Next
      Next
      StopDrawing()
    EndIf
  EndIf
  ImageGadget(0, 0, 0, 0, 0, ImageID(0))
  
  Repeat
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow
  
EndIf

End
User avatar
pf shadoko
Enthusiast
Enthusiast
Posts: 285
Joined: Thu Jul 09, 2015 9:07 am

Re: ray tracing tutorial

Post by pf shadoko »

such a beautiful result in so little line...
you could use vector operators
like this one

Code: Select all

Macro vec3d(v,vx,vy,vz)
  v\x=vx
  v\y=vy
  v\z=vz
EndMacro

Macro sub3D(p,p1,p2)
  p\x=p1\x-p2\x
  p\y=p1\y-p2\y
  p\z=p1\z-p2\z
EndMacro

Macro add3d(p,p1,p2)
  p\x=p1\x+p2\x
  p\y=p1\y+p2\y
  p\z=p1\z+p2\z
EndMacro

Macro div3d(p1,v)
  p1\x/v
  p1\y/v
  p1\z/v
EndMacro

Macro mul3d(p1,v)
  p1\x*v
  p1\y*v
  p1\z*v
EndMacro
Post Reply