(local pxl8 (require :pxl8)) (local SKY_GRADIENT_START 144) (local SKY_GRADIENT_COUNT 16) (local sky-radius 900) (local sky-segments 16) (local sky-rings 16) (local NUM_RANDOM_STARS 300) (local NUM_TINY_STARS 7000) (local NUM_BEACON_STARS 8) (local STAR_SEED 0xDEADBEEF) (local STAR_CYCLE_DAYS 90) (local TAU (* math.pi 2)) (local GLOW_TORCH pxl8.LIGHT_ORANGE) (local GLOW_MAGIC pxl8.LIGHT_PURPLE) (local GLOW_SILVER pxl8.LIGHT_WHITE) (local GLOW_CRIMSON pxl8.LIGHT_RED) (local GLOW_DEEP_BLUE pxl8.LIGHT_BLUE) (local CONSTELLATIONS [{:stars [[-0.09 0.075 240] [-0.12 0.105 200] [-0.075 0.112 190] [-0.06 0.045 255] [-0.022 0.022 220] [0.03 0.0 200] [0.075 -0.018 190] [0.12 -0.009 180] [0.158 0.022 170] [0.18 0.06 160] [0.15 0.075 150]]} {:stars [[0.0 0.0 240] [0.04 0.0 220] [0.08 0.01 200] [0.08 0.05 190] [0.04 0.06 180] [0.0 0.05 200] [-0.02 0.08 170]]} {:stars [[-0.03 0.04 230] [0.03 0.04 230] [0.05 0.0 200] [0.03 -0.04 190] [-0.03 -0.04 190] [-0.05 0.0 200] [0.0 -0.06 170]]} {:stars [[-0.06 0.04 255] [-0.03 0.02 220] [0.0 0.0 240] [0.04 -0.025 200] [0.08 -0.05 180] [0.12 -0.075 160] [-0.02 -0.03 190] [-0.02 0.04 190]]} {:stars [[0.0 0.0 250] [-0.015 0.022 200] [-0.03 0.04 180] [0.015 0.015 190] [0.035 0.03 170] [0.0 -0.022 200] [-0.022 -0.038 180] [0.022 -0.038 180] [0.045 0.0 220] [0.07 0.0 200] [0.09 0.008 180]]} {:stars [[-0.06 0.0 200] [-0.03 0.015 210] [0.0 0.0 230] [0.03 -0.015 210] [0.06 0.0 200] [0.09 0.015 190] [0.12 0.0 180]]} {:stars [[0.0 0.0 250] [0.008 0.03 220] [-0.02 0.05 200] [0.015 0.055 190] [-0.035 0.07 170] [0.03 0.065 180] [0.0 -0.02 200] [-0.015 -0.045 180]]} {:stars [[0.0 0.0 255] [-0.025 0.012 200] [-0.055 0.018 180] [-0.08 0.012 160] [0.02 0.01 190] [0.045 0.018 180] [0.07 0.03 160] [0.0 -0.025 190]]} {:stars [[0.0 0.0 240] [0.03 0.025 220] [0.05 0.05 200] [-0.02 0.03 200] [-0.05 0.045 180] [0.01 -0.03 210] [0.04 -0.05 190] [-0.03 -0.06 170]]} {:stars [[0.0 0.0 230] [0.045 0.01 220] [0.025 0.04 210] [-0.015 0.035 200] [-0.04 0.005 210] [-0.025 -0.03 200] [0.02 -0.04 190]]} {:stars [[0.0 0.0 250] [0.05 0.015 200] [0.035 0.05 190] [-0.02 0.055 180] [-0.055 0.025 200] [-0.045 -0.025 190] [-0.01 -0.05 180] [0.04 -0.04 190]]} {:stars [[0.0 0.0 255] [0.025 0.015 180] [-0.015 0.025 170] [0.02 -0.025 175] [-0.03 -0.01 165]]}]) (var beacon-stars []) (var celestial-directions nil) (var celestial-projected nil) (var constellation-stars []) (var last-gradient-key nil) (var random-stars []) (var sky-mesh nil) (var star-count 0) (var star-directions nil) (var star-glows nil) (var star-projected nil) (var tiny-stars []) (var twinkle-time 0) (fn generate-sky-gradient [zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b] (for [i 0 (- SKY_GRADIENT_COUNT 1)] (let [t (/ i (- SKY_GRADIENT_COUNT 1)) r (math.floor (+ zenith-r (* t (- horizon-r zenith-r)))) g (math.floor (+ zenith-g (* t (- horizon-g zenith-g)))) b (math.floor (+ zenith-b (* t (- horizon-b zenith-b))))] (pxl8.set_palette_rgb (+ SKY_GRADIENT_START i) r g b)))) (fn create-sky-dome [] (let [verts [] indices []] (for [i 0 (- sky-rings 1)] (let [theta0 (* (/ i sky-rings) math.pi 0.5) theta1 (* (/ (+ i 1) sky-rings) math.pi 0.5) sin-t0 (math.sin theta0) cos-t0 (math.cos theta0) sin-t1 (math.sin theta1) cos-t1 (math.cos theta1) y0 (* sky-radius cos-t0) y1 (* sky-radius cos-t1) r0 (* sky-radius sin-t0) r1 (* sky-radius sin-t1) t0 (/ i sky-rings) t1 (/ (+ i 1) sky-rings) c0 (math.floor (+ SKY_GRADIENT_START (* t0 (- SKY_GRADIENT_COUNT 1)) 0.5)) c1 (math.floor (+ SKY_GRADIENT_START (* t1 (- SKY_GRADIENT_COUNT 1)) 0.5))] (for [j 0 (- sky-segments 1)] (let [phi0 (* (/ j sky-segments) math.pi 2) phi1 (* (/ (+ j 1) sky-segments) math.pi 2) cos-p0 (math.cos phi0) sin-p0 (math.sin phi0) cos-p1 (math.cos phi1) sin-p1 (math.sin phi1) x00 (* r0 cos-p0) z00 (* r0 sin-p0) x01 (* r0 cos-p1) z01 (* r0 sin-p1) x10 (* r1 cos-p0) z10 (* r1 sin-p0) x11 (* r1 cos-p1) z11 (* r1 sin-p1) nx00 (- (* sin-t0 cos-p0)) ny00 (- cos-t0) nz00 (- (* sin-t0 sin-p0)) nx01 (- (* sin-t0 cos-p1)) ny01 (- cos-t0) nz01 (- (* sin-t0 sin-p1)) nx10 (- (* sin-t1 cos-p0)) ny10 (- cos-t1) nz10 (- (* sin-t1 sin-p0)) nx11 (- (* sin-t1 cos-p1)) ny11 (- cos-t1) nz11 (- (* sin-t1 sin-p1)) base-idx (# verts)] (if (= i 0) (do (table.insert verts {:x x00 :y y0 :z z00 :nx nx00 :ny ny00 :nz nz00 :color c0 :light 255}) (table.insert verts {:x x11 :y y1 :z z11 :nx nx11 :ny ny11 :nz nz11 :color c1 :light 255}) (table.insert verts {:x x10 :y y1 :z z10 :nx nx10 :ny ny10 :nz nz10 :color c1 :light 255}) (table.insert indices base-idx) (table.insert indices (+ base-idx 2)) (table.insert indices (+ base-idx 1))) (do (table.insert verts {:x x00 :y y0 :z z00 :nx nx00 :ny ny00 :nz nz00 :color c0 :light 255}) (table.insert verts {:x x01 :y y0 :z z01 :nx nx01 :ny ny01 :nz nz01 :color c0 :light 255}) (table.insert verts {:x x11 :y y1 :z z11 :nx nx11 :ny ny11 :nz nz11 :color c1 :light 255}) (table.insert verts {:x x10 :y y1 :z z10 :nx nx10 :ny ny10 :nz nz10 :color c1 :light 255}) (table.insert indices base-idx) (table.insert indices (+ base-idx 3)) (table.insert indices (+ base-idx 2)) (table.insert indices base-idx) (table.insert indices (+ base-idx 2)) (table.insert indices (+ base-idx 1)))))))) (set sky-mesh (pxl8.create_mesh verts indices)))) (fn reset-gradient [] (set last-gradient-key nil)) (fn update-gradient [zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b] (let [key (.. zenith-r "," zenith-g "," zenith-b "," horizon-r "," horizon-g "," horizon-b)] (when (not= key last-gradient-key) (generate-sky-gradient zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b) (set last-gradient-key key)))) (fn galactic-band-factor [dx dy dz] (let [band-len (math.sqrt (+ (* 0.6 0.6) (* 0.3 0.3) (* 0.742 0.742))) bx (/ 0.6 band-len) by (/ 0.3 band-len) bz (/ 0.742 band-len) dist (math.abs (+ (* dx bx) (* dy by) (* dz bz))) in-band (- 1 (math.min (* dist 3) 1))] (* in-band in-band))) (fn compute-right [cx cy cz] (if (> (math.abs cy) 0.99) (values 1 0 0) (let [rx (- cz) rz cx rlen (math.sqrt (+ (* rx rx) (* rz rz)))] (values (/ rx rlen) 0 (/ rz rlen))))) (fn generate-constellation-centers [] (let [centers [] seed (+ STAR_SEED 0xC0057E11) num (# CONSTELLATIONS)] (for [i 0 (- num 1)] (let [h1 (pxl8.hash32 (+ seed (* i 3))) h2 (pxl8.hash32 (+ seed (* i 3) 1)) h1f (/ h1 0xFFFFFFFF) h2f (/ h2 0xFFFFFFFF) base-theta (* (/ i num) TAU) theta-jitter (* (- h1f 0.5) 0.3) theta-offset (if (= i 0) -0.3 (= i 1) 0.4 (= i 4) 0.5 0) theta (+ base-theta theta-jitter theta-offset) phi (if (or (= i 0) (= i 6)) (+ 0.25 (* h2f 0.3)) (= i 9) (+ 0.5 (* h2f 0.3)) (or (= i 1) (= i 4) (= i 7) (= i 10)) (+ 0.65 (* h2f 0.4)) (= i 3) (+ 1.1 (* h2f 0.2)) (+ 0.85 (* h2f 0.4))) sin-phi (math.sin phi) x (* sin-phi (math.cos theta)) y (math.cos phi) z (* sin-phi (math.sin theta)) len (math.sqrt (+ (* x x) (* y y) (* z z)))] (table.insert centers {:x (/ x len) :y (/ y len) :z (/ z len)}))) centers)) (fn generate-constellation-stars-data [] (let [centers (generate-constellation-centers) stars []] (for [i 0 (- (# CONSTELLATIONS) 1)] (let [constellation (. CONSTELLATIONS (+ i 1)) center (. centers (+ i 1)) (rx ry rz) (compute-right center.x center.y center.z) ux (- (* center.y rz) (* center.z ry)) uy (- (* center.z rx) (* center.x rz)) uz (- (* center.x ry) (* center.y rx)) ulen (math.sqrt (+ (* ux ux) (* uy uy) (* uz uz))) ux (/ ux ulen) uy (/ uy ulen) uz (/ uz ulen)] (each [j star-data (ipairs constellation.stars)] (let [ox (. star-data 1) oy (. star-data 2) brightness (. star-data 3) dx (+ center.x (* rx ox) (* ux oy)) dy (+ center.y (* ry ox) (* uy oy)) dz (+ center.z (* rz ox) (* uz oy)) dlen (math.sqrt (+ (* dx dx) (* dy dy) (* dz dz))) star-seed (pxl8.hash32 (+ STAR_SEED (* i 1000) (* (- j 1) 7))) color-type (% star-seed 6) glow (if (< color-type 2) GLOW_MAGIC GLOW_SILVER) is-anchor (and (= (- j 1) 0) (= i 11))] (table.insert stars {:dx (/ dx dlen) :dy (/ dy dlen) :dz (/ dz dlen) :brightness brightness :glow glow :is-anchor is-anchor}))))) stars)) (fn generate-beacon-stars-data [] (let [stars [] seed (+ STAR_SEED 0xBEAC0000)] (for [i 0 (- NUM_BEACON_STARS 1)] (let [h1 (pxl8.hash32 (+ seed (* i 4))) h2 (pxl8.hash32 (+ seed (* i 4) 1)) h3 (pxl8.hash32 (+ seed (* i 4) 2)) theta (* (/ h1 0xFFFFFFFF) TAU) phi (+ 0.3 (* (/ h2 0xFFFFFFFF) 0.9)) sin-phi (math.sin phi) x (* sin-phi (math.cos theta)) y (math.cos phi) z (* sin-phi (math.sin theta)) color-type (% h3 8) glow (if (< color-type 3) GLOW_MAGIC GLOW_SILVER)] (table.insert stars {:dx x :dy y :dz z :brightness 255 :glow glow}))) stars)) (fn generate-random-stars-data [] (let [stars []] (for [i 0 (- NUM_RANDOM_STARS 1)] (let [h1 (pxl8.hash32 (+ STAR_SEED (* i 5))) h2 (pxl8.hash32 (+ STAR_SEED (* i 5) 1)) h3 (pxl8.hash32 (+ STAR_SEED (* i 5) 2)) h4 (pxl8.hash32 (+ STAR_SEED (* i 5) 3)) theta (* (/ h1 0xFFFFFFFF) TAU) phi (math.acos (- 1 (* (/ h2 0xFFFFFFFF) 0.85))) sin-phi (math.sin phi) dx (* sin-phi (math.cos theta)) dy (math.cos phi) dz (* sin-phi (math.sin theta)) brightness-raw (/ (% h3 256) 255) brightness (math.floor (+ 60 (* brightness-raw brightness-raw 140))) color-type (% h4 100) glow (if (< color-type 8) GLOW_TORCH (< color-type 16) GLOW_MAGIC GLOW_SILVER)] (when (> dy 0.05) (table.insert stars {:dx dx :dy dy :dz dz :brightness brightness :glow glow})))) stars)) (fn generate-tiny-stars-data [] (let [stars [] seed (+ STAR_SEED 0xCAFEBABE)] (for [i 0 (- NUM_TINY_STARS 1)] (let [h1 (pxl8.hash32 (+ seed (* i 4))) h2 (pxl8.hash32 (+ seed (* i 4) 1)) h3 (pxl8.hash32 (+ seed (* i 4) 2)) h4 (pxl8.hash32 (+ seed (* i 4) 3)) theta (* (/ h1 0xFFFFFFFF) TAU) phi (math.acos (- 1 (* (/ h2 0xFFFFFFFF) 0.95))) sin-phi (math.sin phi) dx (* sin-phi (math.cos theta)) dy (math.cos phi) dz (* sin-phi (math.sin theta)) band-boost (galactic-band-factor dx dy dz) base-bright (+ 25 (% h3 40)) brightness (+ base-bright (math.floor (* band-boost 35))) color-shift (% h4 100) glow (if (< color-shift 3) GLOW_TORCH (< color-shift 15) GLOW_MAGIC GLOW_SILVER)] (when (> dy -0.05) (table.insert stars {:dx dx :dy dy :dz dz :brightness brightness :glow glow})))) stars)) (fn pack-star-directions [stars idx] (var i idx) (each [_ star (ipairs stars)] (let [dir (. star-directions i)] (set dir.x star.dx) (set dir.y star.dy) (set dir.z star.dz)) (set i (+ i 1))) i) (fn generate-stars [] (set tiny-stars (generate-tiny-stars-data)) (set random-stars (generate-random-stars-data)) (set constellation-stars (generate-constellation-stars-data)) (set beacon-stars (generate-beacon-stars-data)) (set star-count (+ (# tiny-stars) (# random-stars) (# constellation-stars) (# beacon-stars))) (set star-directions (pxl8.create_vec3_array star-count)) (when pxl8.create_glows (set star-glows (pxl8.create_glows 16384))) (set star-projected (pxl8.create_vec3_array star-count)) (set celestial-directions (pxl8.create_vec3_array 2)) (set celestial-projected (pxl8.create_vec3_array 2)) (var idx 0) (set idx (pack-star-directions tiny-stars idx)) (set idx (pack-star-directions random-stars idx)) (set idx (pack-star-directions constellation-stars idx)) (set idx (pack-star-directions beacon-stars idx))) (fn star-brightness [time] (if (< time 0.18) 1.0 (< time 0.26) (let [t (/ (- time 0.18) 0.08) ease (* t t (- 3.0 (* 2.0 t)))] (- 1.0 ease)) (< time 0.74) 0.0 (< time 0.82) (let [t (/ (- time 0.74) 0.08) ease (* t t (- 3.0 (* 2.0 t)))] ease) 1.0)) (fn ease-celestial [t] (let [s (math.sin (* 2 t TAU)) ease (/ (* 0.9 s) (* 2 TAU))] (- t ease))) (fn sun-direction [time] (let [eased (ease-celestial time) angle (* (- eased 0.25) TAU) y (math.sin angle) xz (math.cos angle) sx (* xz 0.7) sz (* xz 0.7) len (math.sqrt (+ (* sx sx) (* y y) (* sz sz)))] (values (/ sx len) (/ y len) (/ sz len)))) (fn moon-direction [time] (let [eased (ease-celestial time) azimuth (* (- eased 0.75) TAU 0.5) elev (math.sin (* 25 (/ math.pi 180))) horiz (math.cos (* 25 (/ math.pi 180))) sx (* (- (math.cos azimuth)) horiz) sz (* (math.sin azimuth) horiz)] (values sx elev sz))) (fn render-stars [cam-x cam-y cam-z time days dt] (set twinkle-time (+ twinkle-time (or dt 0))) (when (and (> star-count 0) star-glows) (let [time-val (or time 0) days-val (or days 0) star-bright (star-brightness time-val) fade-in (* star-bright star-bright) time-factor (/ twinkle-time 60) star-rotation (/ (* (+ days-val time-val) TAU) STAR_CYCLE_DAYS) t (pxl8.mat4_translate cam-x cam-y cam-z) r (pxl8.mat4_rotate_y star-rotation) s (pxl8.mat4_scale sky-radius sky-radius sky-radius) transform (pxl8.mat4_multiply t (pxl8.mat4_multiply r s)) tiny-count (# tiny-stars) random-count (# random-stars) constellation-count (# constellation-stars) beacon-count (# beacon-stars) random-offset tiny-count constellation-offset (+ tiny-count random-count) beacon-offset (+ tiny-count random-count constellation-count)] (star-glows:clear) (pxl8.project_points star-directions star-projected star-count transform) (when (> star-bright 0.02) (for [i 0 (- tiny-count 1)] (let [screen (. star-projected i)] (when (> screen.z 0) (let [star (. tiny-stars (+ i 1)) int (math.floor (* star.brightness fade-in))] (when (> int 8) (star-glows:add (math.floor (+ screen.x 0.5)) (math.floor (+ screen.y 0.5)) 1 int star.glow pxl8.GLOW_CIRCLE)))))) (for [i 0 (- constellation-count 1)] (let [screen (. star-projected (+ constellation-offset i))] (when (> screen.z 0) (let [star (. constellation-stars (+ i 1)) phase (+ (* i 1.618) (* time-val 2.5)) twinkle (+ 0.85 (* 0.15 (math.sin (* phase 6.28)))) int (math.floor (* star.brightness fade-in twinkle 1.5)) sx (math.floor (+ screen.x 0.5)) sy (math.floor (+ screen.y 0.5))] (if star.is-anchor (do (star-glows:add sx sy 4 (* int 2) star.glow pxl8.GLOW_CIRCLE) (star-glows:add sx sy 8 (math.floor (/ int 2)) star.glow pxl8.GLOW_CIRCLE)) (> star.brightness 220) (do (star-glows:add sx sy 3 (math.floor (* int 1.5)) star.glow pxl8.GLOW_DIAMOND) (star-glows:add sx sy 5 (math.floor (/ int 2)) star.glow pxl8.GLOW_CIRCLE)) (> star.brightness 180) (do (star-glows:add sx sy 2 int star.glow pxl8.GLOW_DIAMOND) (star-glows:add sx sy 4 (math.floor (/ int 3)) star.glow pxl8.GLOW_CIRCLE)) (do (star-glows:add sx sy 2 (math.floor (/ (* int 2) 3)) star.glow pxl8.GLOW_DIAMOND) (star-glows:add sx sy 3 (math.floor (/ int 4)) star.glow pxl8.GLOW_CIRCLE))))))) (for [i 0 (- beacon-count 1)] (let [screen (. star-projected (+ beacon-offset i))] (when (> screen.z 0) (let [star (. beacon-stars (+ i 1)) phase (+ (* i 2.718) (* time-val 1.5)) twinkle (+ 0.9 (* 0.1 (math.sin (* phase 6.28)))) int (math.floor (* 400 fade-in twinkle)) sx (math.floor (+ screen.x 0.5)) sy (math.floor (+ screen.y 0.5))] (star-glows:add sx sy 4 int star.glow pxl8.GLOW_CIRCLE) (star-glows:add sx sy 7 (math.floor (/ int 3)) star.glow pxl8.GLOW_CIRCLE))))) (for [i 0 (- random-count 1)] (let [screen (. star-projected (+ random-offset i))] (when (> screen.z 0) (let [star (. random-stars (+ i 1)) phase (+ (* i 2.137) (* time-factor 3.0)) twinkle (+ 0.75 (* 0.25 (math.sin (* phase 6.28)))) int (math.floor (* star.brightness fade-in twinkle)) sx (math.floor (+ screen.x 0.5)) sy (math.floor (+ screen.y 0.5))] (when (> star.brightness 180) (star-glows:add sx sy 2 (math.floor (* int 1.5)) star.glow pxl8.GLOW_CIRCLE)) (when (and (<= star.brightness 180) (> star.brightness 120)) (star-glows:add sx sy 2 int star.glow pxl8.GLOW_CIRCLE))))))) (let [(sun-dx sun-dy sun-dz) (sun-direction time-val)] (when (> sun-dy 0) (let [dir (. celestial-directions 0)] (set dir.x sun-dx) (set dir.y sun-dy) (set dir.z sun-dz)) (let [ct (pxl8.mat4_translate cam-x cam-y cam-z) cs (pxl8.mat4_scale sky-radius sky-radius sky-radius) cel-transform (pxl8.mat4_multiply ct cs)] (pxl8.project_points celestial-directions celestial-projected 1 cel-transform) (let [screen (. celestial-projected 0)] (when (> screen.z 0) (let [sx (math.floor (+ screen.x 0.5)) sy (math.floor (+ screen.y 0.5)) horizon-factor (- 1 sun-dy) size-scale (+ 1 (* horizon-factor 0.6)) r-outer (math.floor (* 50 size-scale)) r-mid (math.floor (* 38 size-scale)) r-inner (math.floor (* 26 size-scale))] (star-glows:add sx sy r-outer 80 GLOW_CRIMSON pxl8.GLOW_CIRCLE 0) (star-glows:add sx sy r-mid 180 GLOW_CRIMSON pxl8.GLOW_CIRCLE 0) (star-glows:add sx sy r-inner 255 GLOW_TORCH pxl8.GLOW_CIRCLE 0))))))) (when (> star-bright 0.02) (let [(moon-dx moon-dy moon-dz) (moon-direction time-val)] (when (> moon-dy 0) (let [dir (. celestial-directions 1)] (set dir.x moon-dx) (set dir.y moon-dy) (set dir.z moon-dz)) (let [ct (pxl8.mat4_translate cam-x cam-y cam-z) cs (pxl8.mat4_scale sky-radius sky-radius sky-radius) cel-transform (pxl8.mat4_multiply ct cs)] (pxl8.project_points celestial-directions celestial-projected 2 cel-transform) (let [screen (. celestial-projected 1)] (when (> screen.z 0) (let [sx (math.floor (+ screen.x 0.5)) sy (math.floor (+ screen.y 0.5))] (star-glows:add sx sy 6 (math.floor (* 500 fade-in)) GLOW_SILVER pxl8.GLOW_DIAMOND) (star-glows:add sx sy 10 (math.floor (* 200 fade-in)) GLOW_SILVER pxl8.GLOW_CIRCLE) (star-glows:add sx sy 16 (math.floor (* 60 fade-in)) GLOW_DEEP_BLUE pxl8.GLOW_CIRCLE)))))))) (when (> (star-glows:count) 0) (star-glows:render))))) (fn render [cam-x cam-y cam-z wireframe] (when (not sky-mesh) (create-sky-dome)) (when sky-mesh (pxl8.draw_mesh sky-mesh {:x cam-x :y cam-y :z cam-z :wireframe wireframe}))) {:render render :render-stars render-stars :generate-stars generate-stars :reset-gradient reset-gradient :update-gradient update-gradient :star-brightness star-brightness :ease-celestial ease-celestial :sun-direction sun-direction :moon-direction moon-direction :SKY_GRADIENT_START SKY_GRADIENT_START :SKY_GRADIENT_COUNT SKY_GRADIENT_COUNT}