3d wave/ripple pattern

I’m part-way into a project using the sensor board and a 3d map (similar to the tabletop edge with backboard outline map I had posted about earlier, also a perimeter with a backboard).
I will have the sensor board mounted underneath in the centre, and read the accelerometer to determine the magnitude and direction of impulses/bumps against the table. I think I have a rough version of this component working OK, including calculating a 3d vector (angle and magnitude) of the force involved.
(I am reading instant forces on the accelerometer, calculating the overall magnitude, and if that is over a threshold it proceeds to determine the delta vector from the baseline and the delta magnitude. If it is below that threshold (most of the noise), it sets the lastX/Y/Z values from which to calculate the deltas. I then calculate the horizontal and vertical angle of these delta accelerations.

My next step is to have a ripple seem to begin from close to where the impact may have originated, moving in the direction of the force. I am trying to sort out a best strategy for this, and am quite new to this, so am hoping to avoid significant missteps.
My initial plan had been to find the intersection of the opposite vector with the map bounding box, and set that as the origin for a sphere. The sphere’s radius would then steadily increase at a given speed, with some decay gradually decreasing the brightness over time until the sphere is no longer active. My plan was to be able to have up to 5 ‘spheres’ (separate waves triggered by different bumps), each decaying until inactive. Once that is working, I could potentially work on wrapping to allow reflections - although I think for my application that won’t contribute much value. For a see-through cube matrix it may be more interesting, though.

So, my question - is the idea of an expanding sphere to represent the wave spreading across a 3d map a good plan? Is there a better one?
My thought was that I would have an array for each sphere - origin, strength (from initial magnitude, radius, and being affected by decay), and probably color. I’d then need to test each index/pixel against this model of the sphere to see what color the pixel should be somehow…

Thanks for bearing with my novice inquiry - I know I’m likely going to be throwing a lot of time into this learning curve, I’m just hoping to be able to have it on the correct path.


FYI, I’ve included the map below - while it is a 3d frame, there really isn’t a lot of depth that would benefit from an overly complex model, so if there is a simpler way of cheating the same effect, it may have some processor benefits.

function (pixelCount) {
  bWidth = 54
  tWidth = 57
  length = 59
  height = 23
   // generate wireframe of tabletop with backboard
  // a 3d adaptation of the 2d line function
  // x, y, z is the starting position
  // dx, dy, dz is how far each step is, 0=no movement, 1=move in positive direction, -1=move in negative direction
  // count is the number of steps

  function line (x, y, z, dx, dy, dz, count) { 
	var line = [];
	for (var i = 0; i < count; i++) {
		line.push([x + dx * i, y + dy * i, z + dz * i]);
	return line;

  var map = []
  // start at 0,0, move 1,0 for each pixel, lengthPixels
  // 1 = first long side of tabletop]
  map = map.concat(line(1, 0, 0, 1, 0, 0, length)) 
  //then moving down, assuming 1 pixel from above counts toward the widthPixels
  // start at lengthPixel,1, move 0,1 for each pixel, widthPixels
  // 2 = short, back side of tabletop
  map = map.concat(line(length+1,1, 0, 0, 1, 0, bWidth)) 
  //then from the bottom right to bottom left
  // 3 = second long side of tabletop
  map = map.concat(line(length, bWidth+1, 0, -1, 0, 0, length))
  // 4 = vertical leg up backboard
  map = map.concat(line(0, bWidth+1, 1, 0, 0, 1, height))
  // 5 = second short side of tabletop, at higher *height
  map = map.concat(line(0, bWidth+1, height+1, 0, -1, 0, tWidth))

  // 6 = vertical leg down backboard
  map = map.concat(line(0, 0, height, 0, 0, -1, height))
  return map;

I feel like I say this too often: Polar coordinates are your friend.

Mapping a wave like that is a vector and at some point you’ll want it in polar (angle doesn’t matter, as you want it expanding in all directions but radius does, distance from point of impact).

Are there any mapping examples which demonstrates Polar coordinates? I’m more or less in the same predicament. I have basically taken the examples from this thread and adapted it using angles, although I would like to experiment some more with other mappings (such as polar).

So polar is pretty simple to convert from XY (and XYZ)…

It’s radius (distance from center), and angle (and in XYZ, second angle which determines up or down)

Google for the formula, I know I’ve posted it here before though.

Convert during your mapping, if you have a good XY map already. It’s usually Radius is sqrt of x squared plus y squared, and angle is arctan(y/x) someone can correct me if I misrecall it.

Added: just saw your 3D mapping and I think you’ve got it. Easiest test: Make a circular sweep pattern from top to bottom, and it should look smooth. Then circular around (running circle pole to pole).

1 Like

Thanks @Scruffynerf
So, while I’ve done some simple work with polar coordinates in the past, I’m wondering if I am over-thinking this.
I understand, then, that I need to re-do my map as polar coordinates… I suppose I can hammer through this.
My next understanding is that in pixelblaze, the origin is understood to be 0.5,0.5(,0.5). Sure.
I haven’t done translations between different polar origins before, but assume that I would then need to do this, given that the origin of the expanding sphere would be from a point close to where the object was touched (opposite the vector detected by the accelerometer). Is this the route you were intending to mean?


After some research, you can do polar vectors but Cartesian vectors are far easier to calculate

See this for the gory details

You could do the math (and I found at least one other example of the math, I can refind it if desired) but you might be better off if you plan on multiple waves from different origins, using an XYZ and then doing the math for the spheres given an XYZ origin point, as opposed to having it a spheric polar map and having to do yet more math to do the vector offsets needed for spheres not starting in the origin, if that makes sense.

@bdm I’ve done one polar project you can see as an example, but it was 2D.

Check the pattern library for one called “StarGen polar 2D”. It has an intro paragraph for 3D spherical (r , θ , φ) as well; just remember that since all mapped coordinates are scaled to 0…1, the azimuth will need to be scaled by 2π; inclination just multiplied by π.

The “origin” in cartesian 2D is always the top-left, with positive Y pointing down (check out the mapping docs).

Because of this, any time I want to render something cartesian where (0,0) is the center of my project, I usually end up transforming coordinates like this:

export function render2D(index, x, y) {
  x -= .5
  y -= .5
  // Rest of the code

Hope this helps!

1 Like

Thanks @jeff and @Scruffynerf
I think I’m going to start with a quick and dirty proof of concept, and then likely run through these implementations (cartesian and 3d spherical).
I appreciate the cited examples and potential pitfalls!

The whole “when to use polar and when not to use it” was a topic I was going to spend time on (for myself) as part of my own education. You just spurred me to dig into it early. :wink:

It turns out your example is one of the cases where it’s actual a disadvantage to start in polar, at least for a simple set of inputs.

Glad to help (and thanks for your help/suggestions)
I’ve finally mounted the lights, and once I finish the spring yardwork (ugh), I’ll be back chipping away at this.