Ray Tracing in NetLogo
Model was written in NetLogo 6.1.1
•
Viewed 109 times
•
Downloaded 10 times
•
Run 0 times
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
Comments and Questions
Please start the discussion about this model!
(You'll first need to log in.)
Click to Run Model
globals [ cam-x cam-y cam-z cam-yaw cam-pitch cam-fov ] patches-own [ patch-xcor patch-ycor patch-zcor patch-xvel patch-yvel patch-zvel patch-hits patch-is-done ] turtles-own [ world-xcor world-ycor world-zcor world-size ] ;;; CAMERA ;;; to reset-camera set cam-x 0 set cam-y 0 set cam-z 0 set cam-yaw 0 set cam-pitch 0 reset-patches end to move-camera [ dist ] set cam-x (cam-x + dist * (sin cam-yaw) * (cos cam-pitch)) set cam-y (cam-y + dist * (sin cam-pitch)) set cam-z (cam-z + dist * (cos cam-yaw) * (cos cam-pitch)) reset-patches end to move-camera-up [ dist ] set cam-y (cam-y + dist) reset-patches end to move-camera-sideways [ dist ] set cam-x (cam-x + dist * (sin (cam-yaw + 90))) set cam-z (cam-z + dist * (cos (cam-yaw + 90))) reset-patches end to-report loop-angle [ ang ] let looped-ang (((ang mod 360) + 3600) mod 360) if (looped-ang > 180) [ set looped-ang (looped-ang - 360) ] report looped-ang end to turn-camera-yaw [ ang ] set cam-yaw (loop-angle (cam-yaw + ang)) reset-patches end to turn-camera-pitch [ ang ] set cam-pitch (loop-angle (cam-pitch + ang)) reset-patches end ;;; PATCHES ;;; to reset-patches ; camera must be above ground set cam-y (abs cam-y) ; direction camera is facing let start-xvel ((sin cam-yaw) * (cos cam-pitch)) let start-yvel (sin cam-pitch) let start-zvel ((cos cam-yaw) * (cos cam-pitch)) ; amount that the camera must turn due to fov let delt (tan (cam-fov / 2)) ; amount that each of the axis ; will turn due to change in yaw let yaw-xdelt (delt * (sin (90 + cam-yaw))) let yaw-ydelt (0) let yaw-zdelt (delt * (cos (90 + cam-yaw))) ; amount that each of the axis ; will turn due to change in pitch let pitch-xdelt (delt * (0 - sin cam-yaw) * (sin cam-pitch)) let pitch-ydelt (delt * (cos cam-pitch)) let pitch-zdelt (delt * (0 - cos cam-yaw) * (sin cam-pitch)) ; amount that the patches scale themself too let div-cor ((max-pxcor + max-pycor) / 2) ask patches [ ; move ray to camera set patch-xcor (cam-x) set patch-ycor (cam-y) set patch-zcor (cam-z) ; add yaw and pitch to ray set patch-xvel (start-xvel + (yaw-xdelt * pxcor + pitch-xdelt * pycor) / div-cor) set patch-yvel (start-yvel + (yaw-ydelt * pxcor + pitch-ydelt * pycor) / div-cor) set patch-zvel (start-zvel + (yaw-zdelt * pxcor + pitch-zdelt * pycor) / div-cor) ; reset hits set patch-hits (0) ; activate-patch set patch-is-done false ; render really quickly move-patch update-patch-color ] end to-report distance-xyz [ x y z ] ; report pythagorean theorem report sqrt (x * x + y * y + z * z) end to-report patch-distancexyz [ x y z ] ; take distance of each axis let xdist (x - patch-xcor) let ydist (y - patch-ycor) let zdist (z - patch-zcor) ; report relative distance report (distance-xyz xdist ydist zdist) end to-report turtle-distancexyz [ x y z ] ; take distance of each axis let xdist (x - world-xcor) let ydist (y - world-ycor) let zdist (z - world-zcor) ; report relative distance report (distance-xyz xdist ydist zdist) end to-report is-touching-turtle [ x y z ] ; take distance of each axis let xdist (x - world-xcor) let ydist (y - world-ycor) let zdist (z - world-zcor) ; test if two are touching without sqrt report ((xdist * xdist + ydist * ydist + zdist * zdist) <= (world-size * world-size)) end to-report max-step-size [ x y z xv yv zv ] ; take distance of each axis let xoc (x - world-xcor) let yoc (y - world-ycor) let zoc (z - world-zcor) ; calculate roots let a (xv * xv + yv * yv + zv * zv) let b (2 * (xoc * xv + yoc * yv + zoc * zv)) let c ((xoc * xoc + yoc * yoc + zoc * zoc) - (world-size * world-size)) ; get square root part of equation let step-size (b * b - 4 * a * c) ; if root is negative return big number if (step-size < 0) [ report 65536 ] ; get entire equation set step-size ((0 - (b + (sqrt step-size))) / (2 * a)) ; if answer is negative return really big number if (step-size < 0) [ report 65536 ] ; return answer report step-size end to normalize-patch ; get distance of velocity let mag (distance-xyz patch-xvel patch-yvel patch-zvel) ; scale velocity down set patch-xvel (patch-xvel / mag) set patch-yvel (patch-yvel / mag) set patch-zvel (patch-zvel / mag) end to move-patch if (not patch-is-done) [ ; normalize the velocitys normalize-patch ; push data into local memory let local-xcor (patch-xcor) let local-ycor (patch-ycor) let local-zcor (patch-zcor) let local-xvel (patch-xvel) let local-yvel (patch-yvel) let local-zvel (patch-zvel) let local-hits (patch-hits) let local-is-done (false) ; get largest steps size possible let floor-distance (65535) ; if patch is moving down, limit step size if (local-yvel < 0) [ set patch-is-done false let scaled-ycor (abs (local-ycor / local-yvel)) set floor-distance scaled-ycor ] ; calculate the closest turtle to the ray let closest-turtle (min-one-of turtles [ max-step-size local-xcor local-ycor local-zcor local-xvel local-yvel local-zvel ]) ; do reflection calculation on closest turtle ask closest-turtle [ ; get the distance from the ray to the turtle let dist (max-step-size local-xcor local-ycor local-zcor local-xvel local-yvel local-zvel) ; check which is closer, the turtle or floor ifelse(dist < floor-distance) [ ; move the ray to the surface of the circle set local-xcor (local-xcor + local-xvel * dist) set local-ycor (local-ycor + local-yvel * dist) set local-zcor (local-zcor + local-zvel * dist) ; calculate dot product of the let normal-dist (turtle-distancexyz local-xcor local-ycor local-zcor) let normal-x ((local-xcor - world-xcor) / normal-dist) let normal-y ((local-ycor - world-ycor) / normal-dist) let normal-z ((local-zcor - world-zcor) / normal-dist) let dot (normal-x * local-xvel + normal-y * local-yvel + normal-z * local-zvel) ; reflect the ray off the turtle set local-xvel (local-xvel - 2 * dot * normal-x) set local-yvel (local-yvel - 2 * dot * normal-y) set local-zvel (local-zvel - 2 * dot * normal-z) ; increase the amount of hits set local-hits (local-hits + 1) ] [ ; only bounce off floor when moving down ifelse (local-yvel < 0) [ ; move ray to the floor set local-xcor (local-xcor + local-xvel * floor-distance) set local-ycor (local-ycor + local-yvel * floor-distance) set local-zcor (local-zcor + local-zvel * floor-distance) ; bounce the ray off the floor set local-ycor (abs local-ycor) set local-yvel (abs local-yvel) ; floor patch settings let square-size 20 let floor-hits 2.5 let square-diff 0.5 ; calculate if it is a bright or dark square if-else ( ((local-xcor mod square-size) <= (square-size / 2)) != ((local-zcor mod square-size) <= (square-size / 2))) [ set local-hits (local-hits + floor-hits - square-diff) ] [ set local-hits (local-hits + floor-hits + square-diff) ] ] [ ; if everything is done, tell ray that it is done set local-is-done (true) ] ] ] ; push data into patch memory set patch-xcor (local-xcor) set patch-ycor (local-ycor) set patch-zcor (local-zcor) set patch-xvel (local-xvel) set patch-yvel (local-yvel) set patch-zvel (local-zvel) set patch-hits (local-hits) set patch-is-done (local-is-done) ] end to-report cap-rgb [ val ] ; cap value from 0 - 255 if (val < 000) [ report 000 ] if (val > 255) [ report 255 ] report val end to update-patch-color ; copy amount of hits into local memory let local-hits (patch-hits) ; if patch is traveling down, simulate hit if (patch-yvel < 0) [ set local-hits (local-hits + 3) ] ; get angle of the ray for rainbow color let angle 270 if (rainbow and ((patch-xvel != 0) or (patch-zvel != 0))) [ set angle ((atan patch-xvel patch-zvel) * (2)) ] ; get pitch of the ray let xz-mag (sqrt (patch-xvel * patch-xvel + patch-zvel * patch-zvel)) let hit-scale (0.618 ^ local-hits) let sky-scale (0.25 + 1.6 * (cos (atan xz-mag (abs patch-yvel)))) ; turn angles into rainbow and shadows let r (128 + 128 * (sin (angle + 000))) let g (128 + 128 * (sin (angle + 120))) let b (128 + 128 * (sin (angle + 240))) ; darken colors due to sky set r (r * sky-scale) set g (g * sky-scale) set b (b * sky-scale) ; average color with hits set r (r * hit-scale + circle-r * (1 - hit-scale)) set g (g * hit-scale + circle-g * (1 - hit-scale)) set b (b * hit-scale + circle-b * (1 - hit-scale)) ; set color to the calculated color set pcolor (list (cap-rgb r) (cap-rgb g) (cap-rgb b)) end to update-progress set render-progress (round (1000 * (count patches with [ patch-is-done ]) / (count patches)) / 10) end to turtle-init [ x y z in-size] set hidden? true set world-xcor x set world-ycor y set world-zcor z set world-size in-size end ;;; TEST ;;; to setup ca ; create the spheres cro 1 [ turtle-init 0 12 10 3 ] cro 1 [ turtle-init -48 12 10 3 ] cro 1 [ turtle-init -24 40 10 3 ] cro 1 [ turtle-init -24 16 16 6 ] cro 1 [ turtle-init 0 24 50 25 ] cro 1 [ turtle-init -48 24 50 24 ] cro 1 [ turtle-init 0 50 150 36 ] cro 1 [ turtle-init -72 50 150 36 ] reset-camera ; setup camera set cam-x -30 set cam-y 42 set cam-z -40 set cam-pitch -15 set cam-yaw 7 set cam-fov 90 set fov cam-fov reset-patches end to go ; if fov changes, draw new image if (fov != cam-fov) [ set cam-fov (fov) reset-patches ] ; cycle through update groups ask patches [ move-patch update-patch-color ] ; update progress bar update-progress display end
There is only one version of this model, created about 4 years ago by Sam Belliveau.
Attached files
File | Type | Description | Last updated | |
---|---|---|---|---|
Ray Tracing in NetLogo.png | preview | Preview for 'Ray Tracing in NetLogo' | about 4 years ago, by Sam Belliveau | Download |
This model does not have any ancestors.
This model does not have any descendants.