conditional jitter matrix operations on a matrix level (a bit like numpy)

Memo Akten's icon

I want to implement a 'bounce' like behavior for a number of objects moving in space and bouncing off walls. I can do this in javascript, or using a million patches iterating each cell, but I'm wondering if it's possible to do without iterating the cells, and just use smart jit operator and expressions.

i have one dimensional (1 cell per object), 3 plane (xyz) matrices
- pos
- vel
- dir // think of this as a 'bounce' property for each plane (component). either +1 or -1. This is what I flip when an object hits a wall. (I don't want to flip the sign of the vel matrix on bounce, because it's being written into by external processes. So I want to store the 'flippedness' in a separate matrix).

pos = vel * dir + pos

this is easy with jit.+ and jit.*

but I also want to bounce (i.e. flip the sign of dir) of any individual cell plane, when the current cell plane value goes beyond a threshold. And the threshold is dependent on the plane.
i.e. my world boundary is [xmin ymin zmin] -> [xmax ymax zmax]

for each cell i:
if(pos[i].x < xmin) { pos[i].x = xmin; dir[i].x *= -1; }
else if(pos[i].x > xmax) { pos[i].x = xmax; dir[i].x *= -1; }
if(pos[i].y < ymin) { pos[i].y = ymin; dir[i].y *= -1; }
else if(pos[i].y > ymax) { pos[i].y = ymax; dir[i].y *= -1; }
if(pos[i].z < zmin) { pos[i].z = zmin; dir[i].z *= -1; }
else if(pos[i].z > zmax) { pos[i].z = zmax; dir[i].z *= -1; }

Is it possible to do the above on a matrix level (i.e. not cell level)? e.g. in numpy (python matrix lib) there'd be syntax something like

dir[pos < worldmin] *= -1
pos[pos
Max Patch
Copy patch and select New From Clipboard in Max.

------
update: here's a toy example

Jesse's icon

I believe there's a typo in your code -- all of the "else if" statements appear to be testing if > max value, not min value.

Assuming I understand correctly, there's a fairly simple answer, but it requires two separate jit.op driven streams to accomplish what you want.

Max Patch
Copy patch and select New From Clipboard in Max.

jit.min and jit.max can be used to constrain the pos values.
jit.> and jit.< can be used to create a multiplication mask to flip the dir values.

Memo Akten's icon

Hi Jesse, yes apologies there was a typo in my code. I've fixed that now.

Max Patch
Copy patch and select New From Clipboard in Max.

thanks for the sample, I've learnt a lot from it. though the conditional multiplication mask for dir matrix has lots of zeros in it. That would zero out the dir matrix. Wouldn't they need to be 1, not 0?. What's a good way of doing that? Based on what you've done I've attempted to do this by jit.== against a freshly initted jit.matrix (full of zeros) and then add to your conditional mask (which is 0s, and -1s) to give the multiplication matrix (1s and -1s), which I can multiply my dir matrix with. Or is there a quicker way?

Memo Akten's icon
Max Patch
Copy patch and select New From Clipboard in Max.

I've put it all together. It still seems like an awful lot of nodes for something so simple. I'm wondering if I'd rather just do it in javascript and iterate!
Is there a way of doing it in a jit.expr?

Rob Ramirez's icon

i would do it with jit.gen.

Max Patch
Copy patch and select New From Clipboard in Max.

here's a bit of your patch converted to get you started:

Memo Akten's icon

Wow, thanks for sending me on the delicious rabbit hole that is gen! I'd never seen it before, I wish I knew about it a year ago.

I'd love to be able to do this whole thing in jit.gen / codebox, I was hoping I could do it in 3 lines of code! But i was wrong. I'm still getting stuck on flipping only some components of dir, not all simultaneously. I've attached my patch, and just the codebox code (most of it is for readability, the actual code is just 3 lines. ). is it possible to do the bounce in codebox?

Max Patch
Copy patch and select New From Clipboard in Max.
    Param mins(-1., -2., -3.);
    Param maxs(1., 2., 3.);

    pos = in1;
    vel = in2;
    dir = in3;

    // advect
    pos += vel * dir;

    // bounce
    //dir[posmaxs)] *= -1; // this is what I really want to do
    if(pos=maxs) dir*= -1; // this only checks the first component of the vector, and flips the entire dir vector
    out2 = dir;

    // clamp
    pos = clamp(pos, mins, maxs);
    out1 = pos;

Jesse's icon

I'm sure there's a more elegant way to do this, but this appears to work:

Param mins(-1., -2., -3.);
Param maxs(1., 2., 3.);

pos = in1;
vel = in2;
dir = in3;

// advect
pos += vel * dir;

// bounce
//dir[posmaxs)] *= -1; // this is what I really want to do

dir_x = dir.x;
dir_y = dir.y;
dir_z = dir.z;

if(pos.x=maxs.x) dir_x *= -1;
if(pos.y=maxs.y) dir_y *= -1;
if(pos.z=maxs.z) dir_z *= -1;

dir = vec( dir_x, dir_y, dir_z );

out2 = dir;

// clamp
pos = clamp(pos, mins, maxs);
out1 = pos;

Memo Akten's icon

cool thx, that does the trick.