# 3D Bouncing Balls adapted from 2D bouncing balls complete! (Slight troubleshooting)

Heya folks! So doing some crash course code lessons and decided to see if I can get Geekmoms pattern shifted over from 2D to 3D and I did! Here is the adapted code. Um, I should probably fix the comments since they’re off now.

``````/* Very simple pattern of three circles, one red, one green, and one blue that
* float around the screen by oscillating with different frequencies in x and y.
* Where they overlap their colors mix.
*
* Debra Ansell (GeekMomProjects)
*/

function randomSpeed(min, range) {
return min + random(range)
}

speed = 5                         // Change this value to make the pattern move faster/slower
txr = randomSpeed(.1, .5)/speed   // Time values for the x/y motion of the red, green, blue circles
tyr = randomSpeed(.1, .5)/speed
tzr = randomSpeed(.1, .5)/speed
txg = randomSpeed(.1, .5)/speed
tyg = randomSpeed(.1, .5)/speed
tzg = randomSpeed(.1, .5)/speed
txb = randomSpeed(.1, .5)/speed
tyb = randomSpeed(.1, .5)/speed
tzb = randomSpeed(.1, .5)/speed

export function beforeRender(delta) {
rad_r = 0.3 + 0.2*wave(time(.33))  // Make the radii of the balls vary with time
xr = wave(time(txr))              // Compute the x,y positions of the balls over time
yr = wave(time(tyr))
zr = wave(time(tzr))
xg = wave(time(txg))
yg = wave(time(tyg))
zg = wave(time(tzg))
xb = wave(time(txb))
yb = wave(time(tyb))
zb = wave(time(tzb))
}

export function render(index) {
render3D(index, index/pixelCount, 0.5)
}

export function render3D(index, x, y, z) {
r = 0                           // r,g,b compontnets of pixel color depend on distance from center of ball
g = 0
b = 0
hr = hypot3(x - xr, y - yr, z - zr)     // Distance from center of red ball
if (hr < rad_r) {              // Red value brightest at center, then falls off
}
hg = hypot3(x - xg, y - yg, z - zg)    // Distance from center of blue ball
if (hg < rad_g) {             // Blue value brightest at center than falls off
}
hb = hypot3(x - xb, y - yb, z - zb)  // Distance from center of green ball
if (hb < rad_b) {             // Green value brightest at center then falls off
}
rgb(r, g, b)
}
``````

So I tested this out on the 8x8x8 cube and success! Works like a charm! Super happy I was able to mostly figure this out (save for a errant capital letter I needed a friend to find. Coding is hard)!

The issue I’m running in to is on the 16x16x16. It is not acting as a whole. it’s bouncing around as if it’s 4 separate PIxelblazes and is disjointed. I double checked to make sure the mapper wasn’t going screwy but rest of the patterns are just fine! I also went way back and used @zranger1 Bouncer 3D to make sure it’s not just a me problem with my code adjustments and its giving me the same effect. Anyone have some ideas as to why both of these are having the same issue when I use multiple PBs?

Heres a video that (hopefully) shows whats going on.

1 Like

So I tested out 3D spotlights and it’s also having this disjointed effect and I’ve also noticed this has only started happening with the update to all the PBs.

All the rest of the 3D patterns are working fine. Honeycomb 3D, Spiral 3D that Ben made me, Sinupulse 3D, etc. they seem to be working fine and in sync.

So 3D Spotlights and the 2 bouncing ball patterns are working fine on a single PB (on the 8x8x8) but introducing a multiple PBs has them out of wack. I’ll revert them to a previous version to check if it’s a update thing tomorrow, but in the meantime, anyone have any ideas?

More later, but my guess is that the other patterns rely on local state instead of time() calls. Multi pb sync only synchronizes the animation timers, stuff like random or an accumulator will run independently.

1 Like

Ok that had actually crossed my mind a few times last nighf because i remembered from previous conversations that firestorm gets wonky with time calls instead of Delta (or vice versa, ill go look up that thread). I hadnt seen it in person yet so was unsure but that makes sense. Ill tinker with it today to see if i can figure out how to swap it from one to the other.

Here’s a version of my old bouncer3D pattern that uses prng() instead of random() and time() instead of frame delta. Give it a try when you can and see if it works better! (You may need to adjust size and speed sliders for your display.)

Bouncer3D v2 for multi-Pixelblaze displays
``````/*
Bouncer 2D/3D v2

Bounces (up to 20) objects - spheres or square "tiles" - around a 2D or 3D display.
Use sliders to set object count, size and speed.

Requires a 2D or 3D LED array and appropriate pixel mapper.

2021-2023 ZRanger1

*/

// Global Variables
var maxBalls = 20;
export var numBalls = 4;
export var ballSize = 0.06;
export var speed = 25;
export var ballSize3D = ballSize * 4 ;
var t1;

var ballShape = 0;  // 0 - round, 1 = square

// array of ball vectors
var balls = array(maxBalls);

// UI
export function sliderBalls(v) {
numBalls = floor(1 + (v * (maxBalls - 1)));
}

export function sliderSize(v) {
ballSize = 0.2 * v;
ballSize3D = ballSize * 4;
}

export function sliderSpeed(v) {
speed = 100 * v;
initBalls();
}

export function sliderShape(v) {
ballShape = (v > 0.5);
}

// allocate memory for ball vectors
function createBalls() {
for (var i = 0; i < maxBalls; i++) {
balls[i] = array(7);
}
}

// create ball vector with a random position, direction, speed, color
function initBalls() {
var hue = prng(1);
for (var i = 0; i < numBalls; i++) {
var b = balls[i];

b[0] = prng(1);     // x pos
b[1] = prng(1);     // y pos
b[2] = prng(1);     // z pos

b[3] = prng(speed); // x vec
b[4] = prng(speed); // y vec
b[5] = prng(speed); // z vec

b[6] = hue;
hue += 0.619033
}
}

// move balls and bounce them off "walls"
function bounce(delta) {
for (var i = 0; i < numBalls; i++) {
var b = balls[i];

// move ball
b[0] += b[3] * delta;
b[1] += b[4] * delta;
b[2] += b[5] * delta;

// bounce off walls by flipping vector element sign when we hit.
// If we do hit a wall, we exit early, trading precision
// in corners for speed.  We'll catch it in a frame or two anyway
if (b[0] < 0) { b[0] = 0; b[3] = -b[3]; continue; }
if (b[1] < 0) { b[1] = 0; b[4] = -b[4]; continue; }
if (b[2] < 0) { b[2] = 0; b[5] = -b[5]; continue; }

if (b[0] > 1) { b[0] = 1; b[3] = -b[3]; continue; }
if (b[1] > 1) { b[1] = 1; b[4] = -b[4]; continue; }
if (b[2] > 1) { b[2] = 1; b[5] = -b[5]; continue; }
}
}

prngSeed(PI2);
createBalls();
initBalls();

var lastTime = 0;
export function beforeRender(delta) {
t1 = time(54.93) * 100
delta = t1 - lastTime;
lastTime = t1;
bounce(delta);
}

export function render2D(index,x,y) {
var dx,dy;
var s = 1;
var v = 0;

for (var i = 0; i < numBalls; i++) {
if ((dx = abs(balls[i][0] - x)) > ballSize) continue;
if ((dy = abs(balls[i][1] - y)) <= ballSize) {
if (ballShape) {
v = 1;
}
else {
v = hypot(dx,dy) / ballSize;  v = v * v;
s = v * 6;
v = 1-v;
}
h = balls[i][6];
break;
}
}

hsv(h, s, v*v*v)
}

export function render3D(index,x,y,z) {
var dx,dy,dz;
var s = 1;
var v = 0;

for (var i = 0; i < numBalls; i++) {
if ((dx = abs(balls[i][0] - x)) > ballSize3D) continue;
if ((dy = abs(balls[i][1] - y)) > ballSize3D) continue;
if ((dz = abs(balls[i][2] - z)) <= ballSize3D) {
if (ballShape) {
v = 1;
}
else {
v = (dx + dy + dz) / ballSize3D;  v = v * v;
s = v * 4;
v = 1-v;
}
h = balls[i][6];
break;
}
}

hsv(h, s, v)
}

``````
2 Likes

So that worked and confirms what was suspected that it was indeed a time issue! That sounds like a good code exercise to figure out how to get the other 2 converted over! Gonna give it a shot!

2nd edit Nevermind! It is working properly. I was thrown off by the amount of balls on display and thought seeing 2 of the same color threw me off when one would disappear.

3 Likes