TL;DR:
Has someone else already done supersampling in a way I can steal that makes animating motion in a direction relatively easy? Because I think I have it kind of sort of working and feel satisfied that my issue now is mostly math-related* and I could probably get mine to actually work so I don’t want to reinvent the wheel. And I’m pretty much at my limit for figuring out the math for getting motion to work. All of the weird choices I’ve made are because I think they’re necessary to avoid going over the entire supersampling array each beforeRender. If each LED was always sampling the same supersampled pixel, it would make the render function simpler, but I didn’t think that would be possible without going over the whole thing. So I figured just constantly overwriting it at some set speed, and making sure to always move in complete rows/columns, and then having the array mapped to the pixels and “wrapping” based on some line that was always moving at the same speed as the updates to the supersampling array would work.
I think my question is… does my end-goal make sense? Does my method make sense? Does any of my code make sense? Is there a 100x easier way to do this that I’m missing? Has someone else already done this, but correctly?
Here’s my code:
// ▼ Array Size Things ▼
xmax = 8
ymax = 8
ss = 8 //number of samples
arrayLen = (xmax*ss)*(ymax*ss) //total size of ssarray
hueArray = array(arrayLen) //create an array big enough to store supersampled hues
valArray = array(arrayLen) //for values
// ▼ SS Array Rendering Things ▼
speed = 0.1 //grids per second
lastRendered = 15 //the last pixel that the beforeRender function rendered
lastUsed = 7 //the last pixel that was used for rendering
min = ymax*ss //this should be based on speed
export function beforeRender(delta){
delt = delta
t1 = time(0.015/speed)
rowTime = 1000/(arrayLen/ymax) //how often a row should be rendered in ms
colTime = 1000/(arrayLen/xmax)
if(delta > rowTime){
for(i=0; i<min; i++){ //I have no idea where +9 comes from
xss = i % ymax*ss
yss = i % xmax*ss
hueArray[i] = 1/xss + t1
valArray[i] = 1
}
}
}
// export function beforeRender(delta) {
// t1 = time(0.1)
// diff = abs(lastRendered - lastUsed) //distance between lastRendered and lastUsed.
// if(diff < min || diff > arrayLen-min){ //check if lastUsed is too close or too far from lastRendered
// nextPix = lastRendered + 1 % arrayLen
// for(i = nextPix; i <= nextPix+2*min; i++){
// x = i % ymax*ss
// y = i % xmax*ss
// hueArray[i] = t1
// valArray[i] = 0
// lastRendered = i
// }
// }
// }
export function render2D(index, x, y) {
lastUsed = t1*min*speed //min gives us the width of the ss array, speed is how many we need per second, and t1 loops every second.
x2 = round(x*ss) //finding the x-coordinate of the nearest ss pixel
y2 = round(y*ss) //finding the y-coordinate of the nearest ss pixel
h = hueArray[y2*ymax+x2]
s = 1
v = valArray[x2*xmax+y2]
hsv(h, s, v)
}
I honestly don’t even know if it’s working, but the color changes one column at a time and moves left to right, which to me implies it is working. But looking at the code I have no idea why it would be working yet. There are clearly some math issues because the first column should actually be the last column, and the bottom and right row aren’t updated.
Long Version:
In my last pattern I ended up thinking a lot about the trade-offs between the on-the-fly, scale-independent, mapped 2d rendering of the pixelblaze, and more traditional ways of animating pixel grids.
My biggest issue was the fact that anything that changes over time, changes across the whole pixel space at once (if there’s a built-in way to deal with this automatically and I missed it, uh… please tell me), and if I want the image on the screen to persist once it has been displayed, and only update based on some directional “scrolling”, but without losing the fine, fast adjustment of each pixel that you get when computing things based on a time() function, I’d basically need supersampling.
Attempting that would be way, way above my skill level and I had no idea if it is even possible to implement in the way that I was imagining on a pixelblaze. So, I decided to begin, and step 1 was googling “how to declare 2d arrays in javascript”, because that’s how lost I was. I remembered the “intro to pixelblaze” pattern, there was something about using beforeRender() to create a buffer of pixels that render() would use, and to look at the KITT pattern. So I believed it was possible, but didn’t want to look at the KITT pattern.
Instead of a 2D array, I’m using a 1D array and just doing the math to figure out the X and Y coordinates when I need them.
Instead of one huge array of arrays for HSV values, I made two arrays, one for H, one for V, and I tell myself I don’t want to animate saturation but I can’t anyway because that would require too much RAM. I do this because when I tried to loop through the array to make arrays of size 2 inside it the pixelblaze got mad at me. I have no idea if this is dumb or not.
I tried some code with a variable for the last pixel cached, and the last one used by the render function, and having some moving dividing line along the array that determined which was the “end” and “beginning” for where to display on the pixel grid, so I could just overwrite the array as I went, but I started thinking about how to make that work with motion and decided to try again.
And that’s where I am now, after “starting again” and trying the method of whole rows and columns being updated.