Author Topic: Ray Trace a translation from SpecBAS  (Read 8534 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Ray Trace a translation from SpecBAS
« on: February 26, 2022, 02:39:54 pm »
by Paul Dunn here was the original SpecBAS code:
Code: [Select]
10 PAPER 0: INK 15: CLS:
 palette 16,255,255,255:
 palette 32,0,192,255:
 palette 255,0,0,192:
 rainbow 16 to 32:
 rainbow 32 to 255
20 read spheres:t=msecs:
 DIM c(spheres,3),r(spheres),q(spheres),cl(4):
 w=scrw/2,h=scrh/2,s=0:
 cl(1)=6,cl(2)=1,
 cl(3)=cl(1)+8,cl(4)=cl(2)+8
30 FOR k=1 TO spheres:
    READ c(k,1),c(k,2),c(k,3),r:
    r(k)=r,q(k)=r*r:
 NEXT k
40 data 6:
 DATA -0.3,-0.8,3,0.6
50 DATA 0.9,-1.4,3.5,0.35:
 data 0.7,-0.45,2.5,0.4:
 data -0.5,-0.3,1.5,0.15:
 DATA 1.0,-0.2,1.5,0.1:
 DATA -0.1,-0.2,1.25,0.2
60 FOR i=1 TO scrh:
    FOR j=0 TO scrw-1
70       x=0.3,y=-0.5,z=0,ba=3:
       dx=j-w,dy=h-i,dz=(scrh/480)*600,
       dd=dx*dx+dy*dy+dz*dz
80       n=-(y>=0 OR dy<=0):
       IF n=0 THEN
          s=-y/dy
90       FOR k=1 TO spheres:
          px=c(k,1)-x,py=c(k,2)-y,pz=c(k,3)-z,
          pp=px*px+py*py+pz*pz,
          sc=px*dx+py*dy+pz*dz:
          IF sc<=0 THEN
             GO TO 120
100          bb=sc*sc/dd,
          aa=q(k)-pp+bb:
          IF aa<=0 THEN
             GO TO 120
110          sc=(SQR bb-SQR aa)/SQR dd:
          IF sc<s OR n<0 THEN
             n=k,s=sc
120       NEXT k
130       IF n<0 THEN
          plot ink 16+(dy*dy/dd)*240;j,scrh-i:
          go to 200
140       dx=dx*s,dy=dy*s,dz=dz*s,dd=dd*s*s,
       x+=dx,y+=dy,z+=dz:
       IF n<>0 THEN
           nx=x-c(n,1),ny=y-c(n,2),nz=z-c(n,3),
          nn=nx*nx+ny*ny+nz*nz,
          l=2*(dx*nx+dy*ny+dz*nz)/nn,
          dx=dx-nx*l,dy=dy-ny*l,dz=dz-nz*l:
          GO TO 80
160       FOR k=1 TO spheres:
          u=c(k,1)-x,
          v=c(k,3)-z:
          IF u*u+v*v<=q(k) THEN
             ba=1:
             go to 180
170       NEXT k
180       IF (x-INT x>.5)=(z-INT z>.5) THEN
          ik=cl(ba)
       else
          ik=cl(ba+1)
190       plot ink ik;j,scrh-i       
200    NEXT j:
 NEXT i
210 print at 0,0;transparent 1;ink 0;"Time: ";(msecs-t)/1000;" secs":
 pause 0:

Thanks to Rod at Just Basic for getting ball rolling for JB version, pretty easy from there to QB64
Code: QB64: [Select]
  1. _Title "RayTrace" 'b+ trans from JB to QB64 2022-02-26
  2. Const scrw = 1024, scrh = 680
  3. Screen _NewImage(scrw, scrh, 32)
  4. _ScreenMove 150, 40
  5. Read spheres
  6. Dim c(spheres, 3), r(spheres), q(spheres), cl(4) As _Unsigned Long
  7. w = scrw / 2
  8. h = scrh / 2
  9. s = 0
  10. cl(1) = _RGB32(120, 65, 45) ' shaddow
  11. cl(2) = _RGB32(0, 0, 100)
  12. cl(3) = _RGB32(255, 255, 0)
  13. cl(4) = _RGB32(0, 0, 200)
  14. For k = 1 To spheres
  15.     Read a, b, c, d
  16.     c(k, 1) = a
  17.     c(k, 2) = b
  18.     c(k, 3) = c
  19.     r = d
  20.     r(k) = r
  21.     q(k) = r * r
  22.  
  23. For i = 1 To scrh
  24.     For j = 0 To scrw - 1
  25.         x = 0.3: y = -0.5: z = 0: ba = 3
  26.         dx = j - w: dy = h - i: dz = (scrh / 480) * 600
  27.         dd = dx * dx + dy * dy + dz * dz
  28.         recursion:
  29.         n = (y >= 0 Or dy <= 0) '* -1   <<< Makes $1000 for knowing where to tap the hammer
  30.         If n = 0 Then s = (y / dy) * -1
  31.         For k = 1 To spheres
  32.             px = c(k, 1) - x: py = c(k, 2) - y: pz = c(k, 3) - z
  33.             pp = px * px + py * py + pz * pz
  34.             sc = px * dx + py * dy + pz * dz
  35.             If sc <= 0 Then GoTo donek
  36.             bb = sc * sc / dd
  37.             aa = q(k) - pp + bb
  38.             If aa <= 0 Then GoTo donek
  39.             sc = (Sqr(bb) - Sqr(aa)) / Sqr(dd)
  40.             If sc < s Or n < 0 Then n = k: s = sc
  41.             donek:
  42.         Next k
  43.         If n < 0 Then
  44.             PSet (j, scrh - i), _RGB32(128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 200 + 55 * (dy * dy / dd))
  45.             GoTo donej
  46.         End If
  47.         dx = dx * s: dy = dy * s: dz = dz * s: dd = dd * s * s
  48.         x = x + dx: y = y + dy: z = z + dz
  49.         If n <> 0 Then
  50.             nx = x - c(n, 1): ny = y - c(n, 2): nz = z - c(n, 3)
  51.             nn = nx * nx + ny * ny + nz * nz
  52.             l = 2 * (dx * nx + dy * ny + dz * nz) / nn
  53.             dx = dx - nx * l: dy = dy - ny * l: dz = dz - nz * l
  54.             GoTo recursion
  55.         End If
  56.         For k = 1 To spheres
  57.             u = c(k, 1) - x
  58.             v = c(k, 3) - z
  59.             If u * u + v * v <= q(k) Then ba = 1: Exit For
  60.         Next k
  61.         If (x - Int(x) > .5) = (z - Int(z) > .5) Then
  62.             PSet (j, scrh - i), cl(ba)
  63.         Else
  64.             PSet (j, scrh - i), cl(ba + 1)
  65.         End If
  66.         donej:
  67.     Next j
  68.  
  69. Data -0.3,-0.8,3,0.6
  70. Data 0.9,-1.4,3.5,0.35
  71. Data 0.7,-0.45,2.5,0.4
  72. Data -0.5,-0.3,1.5,0.15
  73. Data 1.0,-0.2,1.5,0.1
  74. Data -0.1,-0.2,1.25,0.2
  75.  
  76.  

 
Ray Trace for QB64.PNG

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #1 on: February 26, 2022, 03:19:44 pm »
Oh balls!

or... Oh balls, there's a bunch of GOTO statements in the translation. Hmmm, let's see. How about...

Code: QB64: [Select]
  1. _TITLE "RayTrace" 'b+ trans from JB to QB64 2022-02-26
  2. CONST scrw = 1024, scrh = 680
  3. SCREEN _NEWIMAGE(scrw, scrh, 32)
  4. _SCREENMOVE 150, 40
  5. READ spheres
  6. DIM c(spheres, 3), r(spheres), q(spheres), cl(4) AS _UNSIGNED LONG
  7. w = scrw / 2
  8. h = scrh / 2
  9. s = 0
  10. cl(1) = _RGB32(120, 65, 45) ' shaddow
  11. cl(2) = _RGB32(0, 0, 100)
  12. cl(3) = _RGB32(255, 255, 0)
  13. cl(4) = _RGB32(0, 0, 200)
  14. FOR k = 1 TO spheres
  15.     READ a, b, c, d
  16.     c(k, 1) = a
  17.     c(k, 2) = b
  18.     c(k, 3) = c
  19.     r = d
  20.     r(k) = r
  21.     q(k) = r * r
  22.  
  23. FOR i = 1 TO scrh
  24.     FOR j = 0 TO scrw - 1
  25.         x = 0.3: y = -0.5: z = 0: ba = 3
  26.         dx = j - w: dy = h - i: dz = (scrh / 480) * 600
  27.         dd = dx * dx + dy * dy + dz * dz
  28.         DO
  29.             n = (y >= 0 OR dy <= 0) '* -1   <<< Makes $1000 for knowing where to tap the hammer
  30.             IF n = 0 THEN s = (y / dy) * -1
  31.             FOR k = 1 TO spheres
  32.                 px = c(k, 1) - x: py = c(k, 2) - y: pz = c(k, 3) - z
  33.                 pp = px * px + py * py + pz * pz
  34.                 sc = px * dx + py * dy + pz * dz
  35.                 IF sc > 0 THEN
  36.                     bb = sc * sc / dd
  37.                     aa = q(k) - pp + bb
  38.                     IF aa > 0 THEN
  39.                         sc = (SQR(bb) - SQR(aa)) / SQR(dd)
  40.                         IF sc < s OR n < 0 THEN n = k: s = sc
  41.                     END IF
  42.                 END IF
  43.             NEXT k
  44.             IF n < 0 THEN
  45.                 PSET (j, scrh - i), _RGB32(128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 200 + 55 * (dy * dy / dd))
  46.                 EXIT DO
  47.             ELSE
  48.                 dx = dx * s: dy = dy * s: dz = dz * s: dd = dd * s * s
  49.                 x = x + dx: y = y + dy: z = z + dz
  50.                 IF n <> 0 THEN
  51.                     nx = x - c(n, 1): ny = y - c(n, 2): nz = z - c(n, 3)
  52.                     nn = nx * nx + ny * ny + nz * nz
  53.                     l = 2 * (dx * nx + dy * ny + dz * nz) / nn
  54.                     dx = dx - nx * l: dy = dy - ny * l: dz = dz - nz * l
  55.                 ELSE
  56.                     FOR k = 1 TO spheres
  57.                         u = c(k, 1) - x
  58.                         v = c(k, 3) - z
  59.                         IF u * u + v * v <= q(k) THEN ba = 1: EXIT FOR
  60.                     NEXT k
  61.                     IF (x - INT(x) > .5) = (z - INT(z) > .5) THEN
  62.                         PSET (j, scrh - i), cl(ba)
  63.                     ELSE
  64.                         PSET (j, scrh - i), cl(ba + 1)
  65.                     END IF
  66.                     EXIT DO
  67.                 END IF
  68.             END IF
  69.         LOOP
  70.     NEXT j
  71.  
  72. DATA -0.3,-0.8,3,0.6
  73. DATA 0.9,-1.4,3.5,0.35
  74. DATA 0.7,-0.45,2.5,0.4
  75. DATA -0.5,-0.3,1.5,0.15
  76. DATA 1.0,-0.2,1.5,0.1
  77. DATA -0.1,-0.2,1.25,0.2
  78.  

Looks cool though. Thanks for the heavy lifting!

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #2 on: February 26, 2022, 05:43:41 pm »
Awesome stuff guys! You got me thinking of a rotating Earth globe, so I found B+'s and saved that one too. :D

Here is the link to that: https://qb64forum.alephc.xyz/index.php?topic=4547.0

Offline Phlashlite

  • Newbie
  • Posts: 50
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #3 on: February 27, 2022, 04:19:38 am »
AWESOME!

FellippeHeitor

  • Guest
Re: Ray Trace a translation from SpecBAS
« Reply #4 on: February 27, 2022, 07:35:53 am »
It's mind-blowing. I can't wrap my head around it. Real cool.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #5 on: February 27, 2022, 08:12:34 am »
I "sort of" recognize certain equations in this, from using a simple, single ray algorithm to check for line of sight occlusions in a 3D environment. Of course rendering these sorts of light and reflective views is what it's really good for. It's stuff that I wish I understood better.

It's amazing how much this is doing, for such a small amount of code. Nicely done.

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #6 on: February 27, 2022, 10:05:18 am »
Very nice code.  I don’t understand it, but it is amazing.  I wonder if it’s possible to modify it to render several pages in advance, with the spheres moving a little, them play back the pages like an animation.

- Dav
« Last Edit: February 27, 2022, 10:43:58 am by Dav »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #7 on: February 27, 2022, 11:56:17 am »
Yeah, Paul Dunn is like Master Gy both genius and both hard as heck to follow ;-))

Also they both prefer to write code horizontally : allot : tersely: for module length blocks : or at least sub length : )
(I am sure the code I showed from original SpecBAS was edited for public consumption who like me tend to prefer vertical script.)

@Pete is better without GoTo's
« Last Edit: February 27, 2022, 12:09:21 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #8 on: February 27, 2022, 12:13:12 pm »
Very nice code.  I don’t understand it, but it is amazing.  I wonder if it’s possible to modify it to render several pages in advance, with the spheres moving a little, them play back the pages like an animation.

- Dav

Dang! Dave that's an idea but can't be pre-drawn because when they move the reflections will be different but an awesome idea! QB64 might be able to render fast enough, guess we will have to check ;-))

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #9 on: February 27, 2022, 01:44:26 pm »
Update tsh73 had breakthrough with the coloring "Rainbow" part, now the thumbnail matches original SpecBas image.
 
image_2022-02-27_134422.png

Translation later when I have time to study it.

Offline MasterGy

  • Seasoned Forum Regular
  • Posts: 327
  • people lie, math never lies
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #10 on: February 27, 2022, 02:46:43 pm »
This is huge! I don’t understand how it works, but it’s unbelievable that there are a few lines throughout. Fantastic! Congratulations !!!!

Offline MasterGy

  • Seasoned Forum Regular
  • Posts: 327
  • people lie, math never lies
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #11 on: February 27, 2022, 02:48:16 pm »
It would be interesting if you could speed up and create a simple animation!

Offline MasterGy

  • Seasoned Forum Regular
  • Posts: 327
  • people lie, math never lies
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #12 on: February 27, 2022, 03:28:47 pm »
I added. WASD can be used to move forward, backward, left, right, and "-" and "+" keys are used for height.

One sphere circles around the other.
This makes the animation easy to understand.
I still don't understand how it works.
Congratulations to the creator!

Code: QB64: [Select]
  1. _TITLE "RayTrace" 'b+ trans from JB to QB64 2022-02-26
  2. scrw = 400
  3.  
  4.  
  5. SCREEN _NEWIMAGE(scrw, scrh, 32)
  6. READ spheres
  7. DIM c(spheres, 3), r(spheres), q(spheres), cl(4) AS _UNSIGNED LONG
  8. w = scrw / 2
  9. h = scrh / 4
  10. s = 0
  11. cl(1) = _RGB32(120, 65, 45) ' shaddow
  12. cl(2) = _RGB32(0, 0, 100)
  13. cl(3) = _RGB32(255, 255, 0)
  14. cl(4) = _RGB32(0, 0, 200)
  15. FOR k = 1 TO spheres
  16.     READ a, b, c, d
  17.     c(k, 1) = a
  18.     c(k, 2) = b
  19.     c(k, 3) = c
  20.     r = d
  21.     r(k) = r
  22.     q(k) = r * r
  23.  
  24. start_x = 0.3: start_y = -0.2: start_z = -3: start_x = c(1, 1)
  25. dz_temp = (scrh / 480) * 600
  26.  
  27.  
  28.     ang2 = ang2 + .1: rad = 1
  29.     c(2, 1) = c(1, 1) + SIN(ang2) * rad
  30.     c(2, 3) = c(1, 3) + COS(ang2) * rad
  31.  
  32.  
  33.     start_x = start_x + (_KEYDOWN(ASC("a")) - _KEYDOWN(ASC("d"))) * .1
  34.     start_z = start_z + (_KEYDOWN(ASC("s")) - _KEYDOWN(ASC("w"))) * .1
  35.     start_y = start_y + (_KEYDOWN(ASC("+")) - _KEYDOWN(ASC("-"))) * .02
  36.  
  37.  
  38.  
  39.  
  40.     FOR i = 1 TO scrh STEP 1
  41.         FOR j = 0 TO scrw - 1
  42.             x = start_x: y = start_y: z = start_z: ba = 3
  43.             dx = j - w: dy = h - i: dz = dz_temp
  44.             dd = dx * dx + dy * dy + dz * dz
  45.             DO
  46.                 n = (y >= 0 OR dy <= 0) '* -1   <<< Makes $1000 for knowing where to tap the hammer
  47.                 IF n = 0 THEN s = (y / dy) * -1
  48.                 dd_temp = 1 / SQR(dd)
  49.                 FOR k = 1 TO spheres
  50.                     px = c(k, 1) - x: py = c(k, 2) - y: pz = c(k, 3) - z
  51.                     pp = px * px + py * py + pz * pz
  52.                     sc = px * dx + py * dy + pz * dz
  53.                     IF sc > 0 THEN
  54.                         bb = sc * sc / dd
  55.                         aa = q(k) - pp + bb
  56.                         IF aa > 0 THEN
  57.                             sc = (SQR(bb) - SQR(aa)) * dd_temp
  58.                             IF sc < s OR n < 0 THEN n = k: s = sc
  59.                         END IF
  60.                     END IF
  61.                 NEXT k
  62.                 IF n < 0 THEN
  63.                     PSET (j, scrh - i), _RGB32(128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 200 + 55 * (dy * dy / dd))
  64.                     EXIT DO
  65.                 ELSE
  66.                     dx = dx * s: dy = dy * s: dz = dz * s: dd = dd * s * s
  67.                     x = x + dx: y = y + dy: z = z + dz
  68.                     IF n <> 0 THEN
  69.                         nx = x - c(n, 1): ny = y - c(n, 2): nz = z - c(n, 3)
  70.                         nn = nx * nx + ny * ny + nz * nz
  71.                         l = 2 * (dx * nx + dy * ny + dz * nz) / nn
  72.                         dx = dx - nx * l: dy = dy - ny * l: dz = dz - nz * l
  73.                     ELSE
  74.                         FOR k = 1 TO spheres
  75.                             u = c(k, 1) - x
  76.                             v = c(k, 3) - z
  77.                             IF u * u + v * v <= q(k) THEN ba = 1: EXIT FOR
  78.                         NEXT k
  79.                         IF (x - INT(x) > .5) = (z - INT(z) > .5) THEN 'x,y pepita size
  80.                             PSET (j, scrh - i), cl(ba)
  81.                         ELSE
  82.                             PSET (j, scrh - i), cl(ba + 1)
  83.                         END IF
  84.                         EXIT DO
  85.                     END IF
  86.                 END IF
  87.             LOOP
  88.         NEXT j
  89.     NEXT i
  90.     _DISPLAY: CLS
  91.  
  92.  
  93. DATA -0.3,-0.8,3,0.6
  94. DATA 0.9,-1.4,3.5,0.35
  95.  
  96. DATA 0.7,-0.45,2.5,0.4
  97. DATA -0.5,-0.3,1.5,0.15
  98. DATA 1.0,-0.2,1.5,0.1
  99. DATA -0.1,-0.2,1.25,0.2
  100.  
« Last Edit: February 27, 2022, 03:40:24 pm by MasterGy »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #13 on: February 27, 2022, 04:12:22 pm »
Well dang! @MasterGy you understood good enough I'd say, nice! Wow!

Now make the spheres bounce around like inside a box, LOL

Offline MasterGy

  • Seasoned Forum Regular
  • Posts: 327
  • people lie, math never lies
    • View Profile
Re: Ray Trace a translation from SpecBAS
« Reply #14 on: February 27, 2022, 04:52:40 pm »
so you think that ? :)

Code: QB64: [Select]
  1. _TITLE "RayTrace" 'b+ trans from JB to QB64 2022-02-26
  2. scrw = 400
  3.  
  4.  
  5. SCREEN _NEWIMAGE(scrw, scrh, 32)
  6. READ spheres
  7. DIM c(spheres, 9), r(spheres), q(spheres), cl(4) AS _UNSIGNED LONG
  8. w = scrw / 2
  9. h = scrh / 4
  10. s = 0
  11. cl(1) = _RGB32(120, 65, 45) ' shaddow
  12. cl(2) = _RGB32(0, 0, 100)
  13. cl(3) = _RGB32(255, 255, 0)
  14. cl(4) = _RGB32(0, 0, 200)
  15. FOR k = 1 TO spheres
  16.     READ a, b, c, d
  17.     c(k, 1) = a
  18.     c(k, 2) = -(d + .3 + 2 * RND(1))
  19.     c(k, 3) = c
  20.     c(k, 4) = .1
  21.     r = d
  22.     r(k) = r
  23.     q(k) = r * r
  24.  
  25. start_x = 0.3: start_y = -0.2: start_z = -3: start_x = c(1, 1)
  26. dz_temp = (scrh / 480) * 600
  27.  
  28.     'bouncing
  29.     FOR k = 1 TO spheres
  30.         c(k, 4) = c(k, 4) + .01
  31.         ck = c(k, 2) + c(k, 4)
  32.         IF -ck < r(k) THEN c(k, 4) = -.2: ck = -r(k)
  33.         c(k, 2) = ck
  34.     NEXT k
  35.  
  36.     start_x = start_x + (_KEYDOWN(ASC("a")) - _KEYDOWN(ASC("d"))) * .1
  37.     start_z = start_z + (_KEYDOWN(ASC("s")) - _KEYDOWN(ASC("w"))) * .1
  38.     start_y = start_y + (_KEYDOWN(ASC("+")) - _KEYDOWN(ASC("-"))) * .02
  39.  
  40.  
  41.  
  42.  
  43.     FOR i = 1 TO scrh STEP 1
  44.         FOR j = 0 TO scrw - 1
  45.             x = start_x: y = start_y: z = start_z: ba = 3
  46.             dx = j - w: dy = h - i: dz = dz_temp
  47.             dd = dx * dx + dy * dy + dz * dz
  48.             DO
  49.                 n = (y >= 0 OR dy <= 0) '* -1   <<< Makes $1000 for knowing where to tap the hammer
  50.                 IF n = 0 THEN s = (y / dy) * -1
  51.                 dd_temp = 1 / SQR(dd)
  52.                 FOR k = 1 TO spheres
  53.                     px = c(k, 1) - x: py = c(k, 2) - y: pz = c(k, 3) - z
  54.                     pp = px * px + py * py + pz * pz
  55.                     sc = px * dx + py * dy + pz * dz
  56.                     IF sc > 0 THEN
  57.                         bb = sc * sc / dd
  58.                         aa = q(k) - pp + bb
  59.                         IF aa > 0 THEN
  60.                             sc = (SQR(bb) - SQR(aa)) * dd_temp
  61.                             IF sc < s OR n < 0 THEN n = k: s = sc
  62.                         END IF
  63.                     END IF
  64.                 NEXT k
  65.                 IF n < 0 THEN
  66.                     PSET (j, scrh - i), _RGB32(128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 128 * (scrh - i) / scrh + 128 * (dy * dy / dd), 200 + 55 * (dy * dy / dd))
  67.                     EXIT DO
  68.                 ELSE
  69.                     dx = dx * s: dy = dy * s: dz = dz * s: dd = dd * s * s
  70.                     x = x + dx: y = y + dy: z = z + dz
  71.                     IF n <> 0 THEN
  72.                         nx = x - c(n, 1): ny = y - c(n, 2): nz = z - c(n, 3)
  73.                         nn = nx * nx + ny * ny + nz * nz
  74.                         l = 2 * (dx * nx + dy * ny + dz * nz) / nn
  75.                         dx = dx - nx * l: dy = dy - ny * l: dz = dz - nz * l
  76.                     ELSE
  77.                         FOR k = 1 TO spheres
  78.                             u = c(k, 1) - x
  79.                             v = c(k, 3) - z
  80.                             IF u * u + v * v <= q(k) THEN ba = 1: EXIT FOR
  81.                         NEXT k
  82.                         IF (x - INT(x) > .5) = (z - INT(z) > .5) THEN 'x,y pepita size
  83.                             PSET (j, scrh - i), cl(ba)
  84.                         ELSE
  85.                             PSET (j, scrh - i), cl(ba + 1)
  86.                         END IF
  87.                         EXIT DO
  88.                     END IF
  89.                 END IF
  90.             LOOP
  91.         NEXT j
  92.     NEXT i
  93.     _DISPLAY: CLS
  94.  
  95.  
  96. DATA -0.3,-0.8,3,0.6
  97. DATA 0.9,-1.4,3.5,0.35
  98.  
  99. DATA 0.7,-0.45,2.5,0.4
  100. DATA -0.5,-0.3,1.5,0.25
  101. DATA 1.0,-0.2,1.5,0.2
  102. DATA -0.1,-0.2,1.25,0.2
  103.