Well, we’re still waiting for the grant money to arrive. In the meantime I learned about render2D, and there’s a chance we don’t need to add another ring of LEDs to get this sunset animation going.
I tried starting with something simple, mixing a hue of yellow to red across the “sky” and then trailing it with a mix to fade out pixel value. I think it turned out OK, and since it isn’t lowering a lot of pixels at once, and is dimming in red and not yellow, there’s not very much stuttering at low light levels!
Here’s a 10x sped up video of it. The colors aren’t captured very well, but you can get an idea of the fading across the planetarium dome toward the west.
I tried adding multiple “modes” to the same script, so that I can work toward having them blend nicely when changing from “color bands” to “sunset” and the like. Here’s what I have so far:
/*
*==============================================================================
* Global Variables
*==============================================================================
*/
running = 0 // Is sequence running? Running 0 -> Sunset frozen!
sec = 0 // Seconds
ms = 0 // Milliseconds
export var v_clamp = 0.0
duration_fade = 5.0
duration_sunset = 90.0
SUNSET_BEGIN_H = 0.05
// Variables to control the pixels
ph = array(pixelCount) // Current Pixel Hue
ps = array(pixelCount) // Current Pixel Saturation
pv = array(pixelCount) // Current Pixel Value
/*
*==============================================================================
* Utility Functions
*==============================================================================
*/
function calcVaccum() {
v_accum = 0
for (i = pixelCount - 1; i > 0; i-=10) {
v_accum += pv[i]
}
}
function resetTime() {
sec = 0
ms = 0
}
function fade_in() {
if (v_clamp < 1.0) {
v_clamp = clamp( (sec+(ms/1000)) / 4.0, 0, 1)
}
}
/*
*==============================================================================
* State Machine
*==============================================================================
*/
STATE_OFF = 0
STATE_STEADY = 1
STATE_PROJECTORS = 2
STATE_SUNSET = 3
currentState = STATE_OFF
state = array(4)
/*
*==============================================================================
* UI Functions
*==============================================================================
*/
export function togglePaused(input) {
running = !input
}
export function triggerSunsetInit() {
resetTime()
// Initialize array of indexes and array of values
for (i = pixelCount - 1; i >= 0; i--)
{
ph[i] = SUNSET_BEGIN_H
ps[i] = 1.00
pv[i] = 1.00
}
currentState = STATE_STEADY
}
export function triggerBeginSunset(){
resetTime()
currentState = STATE_SUNSET
}
export function triggerRed() {
resetTime()
for (i = pixelCount - 1; i >= 0; i--)
{
ph[i] = 0.001
ps[i] = 1.0
pv[i] = 1.0
}
currentState = STATE_STEADY
}
export function triggerProjectors() {
resetTime()
currentState = STATE_PROJECTORS
}
export function triggerSteady() {
resetTime()
currentState = STATE_STEADY
}
export function triggerOff() {
resetTime()
currentState = STATE_OFF
}
/*
*==============================================================================
* Render Functions
*==============================================================================
*/
export function beforeRender(delta) {
ms += delta
while (ms > 1000) {
ms -= 1000
sec += 1
}
//progress = ( (seconds / duration) + ((delta_acc/1000)/duration) )
t1 = time(.25)
t2 = time(.15)
}
state[STATE_OFF] = (index, x, y) => {
if (v_clamp > 0.0) {
v_clamp = 1 - clamp( ((sec*1000)+ms) / 2000, 0, 1)
} else {
pv[index] = 0
}
}
state[STATE_STEADY] = (index, x, y) => {
fade_in()
}
state[STATE_PROJECTORS] = (index, x, y) => {
fade_in()
h = index / (pixelCount / 2) // Notice how each hue appears twice
// Create the areas where white is mixed in. Start with a wave.
s = wave(-index / 3 + t1)
// A little desaturation goes a long way, so it's typical to start from 1
// (saturated) and sharply dip to 0 to make white areas.
s = 1 - s * s * s * s
// Create the slowly moving dark regions
v = wave(index / 2 + t2) * wave(index / 5 - t2) + wave(index / 7 + t2)
if ((index < 510 && index > 410) || (index < 300 && index > 200) || (index < 60 || index > 600)) {
v = 0.05
} else {
v = v * v * v * v
}
ph[index] = h
ps[index] = s
pv[index] = v
}
state[STATE_SUNSET] = (index, x, y) => {
t = (sec+(ms/1000))
d_half = (duration_sunset/2)
d_third = (duration_sunset/3)
if (t > duration_sunset+1) {
v_clamp = 0
triggerOff()
}
ph[index] = mix(0.00, SUNSET_BEGIN_H, clamp(y+((-t+d_half)/d_half), 0, 1) )
ratio_v = 1.0
if (t > d_third) {
// ratio_v = 1.0 - clamp( ((t - d_third) / duration_sunset), 0, 1)
ratio_v = mix(0.00, 1.0, clamp( y+ (( -(t-d_third)+d_third) / d_third), 0, 1) )
}
pv[index] = pow(ratio_v, 2)
ps[index] = 1.0
}
// export function render(index) {
// state[currentState](index);
// // Clamp for fading in/out
// v = clamp(pv[index], 0, v_clamp * v_clamp)
// // Set this pixel's Value
// hsv(ph[index], ps[index], v)
// }
export function render2D(index, x, y) {
state[currentState](index, x, y);
// Clamp for fading in/out
v = clamp(pv[index], 0, v_clamp * v_clamp)
// Set this pixel's Value
hsv(ph[index], ps[index], v)
}