### Draw a cylinder between two points (multiple times per frame)

So I’m working with OSCeleton and trying to make a very rough 3d volume of the body. I’m not particularly hot at low-level 3d or maths, which this seems to require in abundance.

So far I have a system that takes two points – say the right hand [A] and right elbow [B]. It finds the mid-point between the two, and sets that as the draw position. I then minus A from B to find the relative distance in cartesian space, then I run a 3dcartopol object on it to extract the azimuth, elevation and distance. I feed all those numbers to a sketch object in the hope it will draw a cylinder at that position and orientation, using these gl commands:

```
reset
glclearcolor 0. 0. 0. 1.
glclear
glrotate $6 1 0 0
glrotate $7 0 1 0
moveto $1 $2 $3
cylinder $4 $4 $5
glcolor 0.5 0.5 0.5 1.
//glbindtexture $9
```

I see a cylinder that acts roughly right, but often does strange things like flipping around its axis all of a sudden, or (as the user moves right to left) starting at the right of the screen, tracking them to the center, then returning to the right.

Trying to use multiple cylinders results in a spastically twitching, flickering heap. I’m way, way, way over my head already (and frankly surpised theres anything on screen). So I thought I’d ask if there was anything wrong with the basic concept or openGL before getting into the specifics of the patch.

I’ve read the relavent redbook sections, but nothing seems to be helping (the current gl commands are just one configuration of many I’ve tried that all draw, but dont achieve the result). I’ve pushed and popped matrices but it didn’t seem to achieve much so I removed those lines.

For anyone curious, the 3dcartopol object I used was http://www.maxobjects.com/?v=objects&id_objet=776&PHPSESSID=ad2a22436728f65b8dc4b138b589fdde . before that I was using my own system with a series of Max’s own cartopol objects, but it got my head in a mess trying to figure out how the 3 values cancelled each other out into only 2 rotations and 1 distance.

I’m also currently playing with cosm.nav but I can’t seem to get anything out of it yet (it requiring yet another mathematical process to get 4(?) rotational values). http://www.allosphere.ucsb.edu/cosm/index.html

i would start with simple spheres at the joint positions, and a simple line connecting the joints.

if that looks as expected, you can move on to more complicated geometry.

Thanks for the suggestion, but that was a step I passed through on the way to this patch (using circles rather than spheres).

Unfortunately lines are far simpler to define; using a start-point and end-point, I guess since the ‘roll’ axis doesn’t matter on whats essentially a 2d object. Adding the full number of axes of rotation is whats causing the brainial short-circuit.

I’ve come back to this problem months later, and have the rotation a bit more figured out, but I’m still stuck getting the right things on-screen.

At the moment the main issue seems to be the translation (although my test situation is simple enough that it could be hiding underlying rotation problems)

For each cylinder, the following runs:

glmatrixmode modelview [doesn't seem to make any difference]

glpushmatrix

gltranslate $1 $2 $3 [mid-point between 2 coordinates]

glcolor 0.7 0.7 0.7 1.

glrotate $4 0 1 0 [Y-axis rotation from polar coordinates]

glrotate $5 1 0 0 [X-axis rotation from polar coordinates]

cylinder $7 $7 $6 [radius of each end and length from polar distance]

glpopmatrix

Then after all the cylinders, before the frame is rendered:

glclear

reset

I have created a simple test situation, with points at

0,0,1

0,1,0

1,0,0

0,0,0,

I join them into 4 pairs, and find the polar coordinates. This should result in a neatly-aligned right-angle triangle on the positive XY plane at 0, and a line stretching down the Z axis to 1.

Instead I see:

http://i.imgur.com/hQirD.jpg

Now the rotation I suspect I can fix later by flipping some numbers/coordinates, but I can’t figure out whats happening with the points where the cylinders intersect.

I think there might be some ‘drift’ coming from each translation, but I don’t know how. Theres a command I think is Max MSP only (moveto) I can use instead of translate, but it results in a similar situation (only with everything closer together).

The ‘z’ axis cylinder appears to be in a weird spot that is level with the midpoint of the hypoteneuse.

Thats essentially a summary of the problem, but I’ll include some more information for anyone who’s curious:

The coordinates are as follows:

01 = 0.000 0.100 0.000

02 = 0.000 0.000 0.000

03 = 0.100 0.000 0.000

04 = 0.000 0.000 0.100

paired by this list (the intial 0s on each are just because they’re stored in a 2d matrix)

0 1 0 2,

0 2 0 3,

0 2 0 4,

0 1 0 3

Run through a cartesian to polar coordinates object (output example):

90. -0. 0.1 [azimuth, elevation, distance]

which is fed into the gl commands above.

Never mind – I found I had connected a vexpr wrong so it was running before it received its righthand input, causing the slight misalignment.

Now I’m on the next issue, which is how to keep a texture on a cylinder facing forwards, when I cant really see how to lock the rotation along the axis of the cylinder. As it is, when nearly vertical the rotation slides around a lot (invisibly, unless there is a texture on it to watch).

Edit: after some sketching I’ve realised there’s no ‘correct’rotation when you’re joining two points as theres no information included about the orientation of the object between them. There will always be one axis where things get a bit crazy when the cylinder is paralell to it. I’m now thinking how to choose that axis (at the moment its Y, but I’d prefer Z)

Final edit: I flipped the coordinates system on its back just before running it through the polar coordinates, opengl translation etc. x = x , y = -z, and z = y. Then at the end of the sketch commands (after the last popmatrix) I flip the world back up again with a glrotate -90 1 0 0. This means the crazy rotation will happen when the cylinders are close to pointing at the camera, minimizing the visual effect.

Hey Bferns,

I’m dealing with a similar patch right now and surprised at my inability to successfully solve this seemingly simple problem,

any chance you could share your patch we can all(me) learn from?

greatly appreciated

Jeremy

never mind, mostly figured out, I’ll post my patch shortly

hmmm so I thought I figured it all out but I’m unable to get the angle working right when z values are between -1.0 and 1.0

any ideas?

-- Pasted Max Patch, click to expand. --Copyallof the following text. Then, in Max, selectNew From Clipboard.----------begin_max5_patcher---------- 4006.3oc6cssbahjF9ZmmhtTkK1CNZoOwgs1ZqMY18hb2V0T0bSlToPRsjYB BzBX63L07NsOC6S1B8eiDXKfFAB21ipjx1.RvW+0+m5e5t++02b0rEweSjNC 8WQeBc0U+5at5J4oJNwUpiuZ1V+usLzOU9wlsLd6VQT1rqgqkI9Vl77+63fn LzGJOezsaChBEYxuDVcx0wQYoAeWHOGYt0gOa7sYke3xytKQjl+f7yBhi9Rh XYFfRFml+EQtVE+r7GnOW4ID4uU9Dl89j.+vR.syOa4MAQapbq3Lbw2Gicj+ hKuajp2tfUxaT7he4cX7rhy8au4ME+35Qgsd+3wV8pgi4NUZ31rVa2VmR6dq HM0ei3Is6h9zri1pI8oUWRQvoxdXm.ZXylcZRBDNufC3VtE+hBri6wID2SgO hD2m+ceJcfV3Gs4n7g0yIePAkL6hmWtFWaxGjQjNRalNN+JELYuNwS1ZUGzj NwH1l24+UDdNhLGQmiXyQ74H64GkBreV0Pb7j7BlBVNZ0Vo8XJTH91tDze3s qI+42tF+G+Kj4lm4ClGHtXK4HOu13Ft2uu3FphNzhab9cF2XIMvRbrzfarGS +vaBWFGFmfvHq7VEZa7chrXzawn2RPukdMJc2MhDQQnU7CWkgdKG8V6Gc0vf HwWtOXU1M4FwfCSEaJh5Y+8a+WsDGEenkw2FkUsKvfBG.htjQAeAtPTAjF5X 3inP6uDjMeS37a7iVEJPqii02YHdN2iiccNJCQZjgt9zkdoRAVaHJR2V8XRF SM6cn7K79nMghg6mj1DwrNL1OqfcdzebZbksEEzzAE91cexX0tShDEEo3n7G cPn3NQRZ9HipHNb0rpAy.xrLHNNFHO6V4Aly8aBiW9UwpJQLc0rUh086tDuS Dc3aTaTY0FZF7IChpNrtG+j8uML6KGuaq90W6uTz3W9ncJWMaSRvp3nBPT6a Vb5xGWwHifgBVE2xOQj+ti7kyhiCW3mbWPZvhPQs9hbIa+nfs9Yhr..ODq8e ufs6RB.qe6OmHxO+dbS5xj3vvZ2J3J2cjqrRbWvRgz3q7dcfspMt9JxN0z4p c91z8pq+884IYwqpdoiYc5o5fGfWilv6vL9SU79IQxJ+H+pf4XFzskizmYym S7XNTu7+VJfh8pzS+3A5A1rtpztE7GWO974eOe..MxljlXSxoxlRAups4Fxz B0FTFnjipO2pMvF8YT6dl+SdcyfMDs74uOHUDlCRDdb6GHs0O.i08wR2M0Yv sA4U5H1YPbg6oLAPbxi8I0P34iTmQ8PSq2a7N7DpOnox.DcNgMl7ODyDgePY nZVmZXH.u9MHcpLI11QSyJ7oRR94SPt2jHwg2OwQxu2rMeBTpxpMWOKrzoJj i+D5cSpJd8wNchJ4Vxf3HtxeQocRlSk4x+1DSlC2dYobI3Tix6zyu6XRk4BC 4s19O9gSVad+P3kp0Cj5fnkvVp2XTWTGy6B0URcvaRBawzi53VWntx2XaoTm tTG9B0URcpWmqkslJr1WnNE0AI9VeScNWXtxXUb5Gy4NQgpfcstOwe2Dl6tt h7SuD3w3RCeLOq8IvCNSaIviwtvpsKk5xOAVkbgU6XbJvTkvi1CVkNprJzxz h4N5LmoQ0PF3DUYQiW9yFaUVUwP4jgq3puDZsTORuZsD2WzsVXp8neq0YJZs mZT.Vm6n.z0ukCj4G5gD.0lY.BaBS.jq0Ij0h5Syfmi7.wfIqIyld7Ym3S3T 9Dwo+EDcNlg4dzWxzJUFzuc2zp8E87JtJr5mdNdxzyeoplSgQeVpli6TdjbQ MuGzp1p4zKp4OIFIsUystnl2Ik5zK0br6E07dPq5pli8tnlWYXtRu46cp2kZ Nleg7drCF8IuKwQVcNUa2Oxaplv.2Fsye4WQVyg+OtDLUKBtgIh8IS0vPyo1 tGl95sR0i5PykLVir33k+xit5FjsXGld44gMEo444jNrk5ZNT8nC9qc5f1K5 v9UNcfor9PGzW6zA7VzUKiktyQ7qb5voWrA1jSXtYLCgvJRTy4pAldg5J0Ls sApSyob.lbg5JotRoNcotQM4s02hPpG08OgGWJ0ZHzDDnLQMSLb6jklpbe8N zKtoxL1CTVoX8VuBdWnxls6Q6EU5dgJaNV29QkNSkYveLFs1OA8QzM92IP9n zGRyDaQY23mgx7+pHEkceLZWwdpTJ5cnT+Gxul.kDr4lLTwZoG8o2+YTwugS IBWDeO5Se3yy+4neNB8wLz5fnUoxuz1fUuSdmPKDY2KDQxyle+uVdCRy6LfG rO74Wk3ee9iNMnXAioteEWHJ+NEcaJ58n0IwaQe.kEKeJ.xDg9YA4skUAoY9 QKEnfHzR+jLQZfeDJcm+Rw0vc4injaixayzUEWOdWbHJm6KVOLwQnfrhaaNM k3mehh6r+2C1da1MWm2FE2IWDaRXW9bpRu01DF7LG+LbK0dLC3hwClDpEBkM NLCuoRR76iahurF3xZlnVQL6ySXGSxL5TwSOXT7jZctnOOwtjR5JiICxmOr5 q5NkzzKuLjmLpL8IO2KjWkwkw5G4MUgIWrms04aBgZdaCFkDJAV8evrXn045 8TMFN5+rL5lIb5dGlGTzHvovxkl4c3Es2JkNYIO3alkOXrcu7AyNZrJG1Udj 6yXGeCtQ9zKt9wIvz3aSVVJCnxh30n5.YkHMKHZ+lTzm16Z6wevaBVsp9lBj rOJXELZD3Ki9rVc48F2XcwsmYgaht310nvMQW4DBwrvst7MyrvMSW4aLynvM 2QSbysMKby0E2NlEts00dRwGDaNx2d5x2lkeGtqt7sYImnOeaV9czE1GINlm SXqqTB1r75nqw6iD80yIr00FH2rfMm7xz1MW2XSLLWkVZBayxBn1AlX8xzgi YM9LlaOjsMnvob5grsAAa6dHjXPvlo6fgMqAmwz0gCwrbTxz0xMyvvstv1rr AR00zMyrb4Pc6CtMGyITsyYhYMZAJuO7Mwbvs1lAML4acoayJ0ZDccxSLqT8 PzV71r7xSz0sC0rDuI5NrRhg8pQzM5DhYMdXseyHlErwZmRPyRLAqcliMKu7 XsSJng8lV01siYk5XrttcHlkadrttcvNlGtw5faCjuI5faCalanqamwz7s5j 43GJtXo92IV8EXxj+E+rrjfE2lAyolJ3e1Qq2VaBiW3GpJOY6mIP6q0VmqZ3 UKWpoxG1aNvBiZAas9+MuB1JGJpjTWcJXqzSp77Ua5kNfx0KoyZvWsoSZOqR gpI6Hre3zdM9lPd0RCkU7AsnA5qWZf3nOMvFyJ99O7+9uOSE1ZGnZlp1QnHz Vqr0NiYa9COasY6x1rqFsY2wrM+9ms1LGJQ250l8d0ph6.KeLEMztJts0qVZ vEJUHZQCb2WszfMThs0iFXuZoAUMrVMI76Po30KKP0mE3udiH10SaVfMlEc9 mVk4uwemHNIPVq34xpDu80n80ld0Jr5ZzxGxGa8JQR9AXYUmu3O3uPJl7LKX m3zC7Nq9UCES9SJx6r3MMUKzw8qIVsxx0x9yiMT42IsJ5fIioriTvOGL4ROy ztKt91v5YtetjarkNbfeVs7Ydj8RvQJgDHQ5x2s91vvzkIBQzQ4Gqmc9Qsd9 U7iW6xN7Z2HQxSRJUPn3NQRpJcY6KH5Uh+AFuqkJXX0FfasB69hMgwK+pX0i yBUutIE0D9CeAqpUG35kHX4mLHpZ8EtwzecjEj2fycVQYr+HkvdY0sW839DB jgw0ZgxOQj+ti7kyhiCW3mbWPZvhPQsdhbQY+nfs9Yhr..ODq8eufs6RB.C1 V0qx82bjpbObk6NxUVItKXo39fUY2HuWGXq7GeSKOvguxJ+WoKycbgd+O9Ce 7ineHdkn+qzxN2gnGzVnAH2Zqx0AqqspImWB0mFUla3NyIbiYuGrsR+7AKxG bZ0isBngsGhO3BDKrBwAxVk6P2112Kml0I9WEOn0N8X+XRVWUa2qO1uFCFlp 1766r.ANskZ6501oQRdcZJ31JCeEhsvF7bqkI0wjVqEFdeL70uh8bisZOkkw N2+BsmrUVu1KLyWjq1D6WjSzZ9Kx4yI4UvKB2546EgacFdQ3+RP176ChVEeO ZcbL5erRrK6lE2tdsHAg0OGXsNHzFSD1S7WbZCF0St0BUtGR1znQsGwQqmfR DE4x5KK7W7fgNTcNTKdfcBdWbqoI8jdCJEhNq2kt41fysbx.jQTaZbPE4P89 D4MvBiZttJ9iaSDnhAdirY4+2PS4kp9nZI4FHwlMkwKmQMSxKyQXhOxs3eFJ 2.BLL3cx531J2XeF3FRw+LTtARLAC1k2amabOoLhmC+Ehj8TSRP5ReH+TVy8 NyVbTiPbHuyRPShowqrDSrL72X.uRaoqWX.cD8y9e1JxRhQDqysNvPlMR.4. UhmNhAgLluxfLzBTtQhTAZwH4.l1UfZxG2Pm8VpDvaoCewmMtg5tIbd5WE4X Bh1MrXmjt.dP1oO+Q7NfHYTQxYWtq60gZn83ybPLuELmgOv.PDSMt.Wd6DUs IKm7iTO4I.u83gDqXu12ubZbuxoVRGd5ffe7.fI1r4xTgQfP581eDLJ3mzKq KZwxkFHtC751OzlGQ.unjrQka87.zkGMPvRzfZqujA6FqSAjnlGjHFGjLu9M twgH6IEQ35Ka3lrkMoXxkpk4Um9AJGoAKNL0por8GLPv5XeN.qKX7mTErjQ. rryAXwVXI.gormBsT2AiVasTfmVMXaKMvjbGxfMcXRGqJEbIWeHw7bjN1cfB Lii29il.vx85WeZIXsTI4xd+QS.XY0VXim8N6GwMsH.NgXxUWLwmNL4nKlvS Glr0ESSmAMN+rLVFkCLlrxTUNVlhiFJbY5RgzoiBsNGdUskTG2hWwoJLeFGF X00YQO7ewXJmEvB3vFOm34445pN0DfXdOI2RDCdLXVtikGCttdLvm.Xki01l aM2wxxBSTmZfH9QnoAIBqI0nzi7opyV+7zfoNkCm1Q3xzUYtGFCodfx.jpaJ iNGmKsYYqN0DfXdOc1ThXKoESJFu+nI.rL1IBVPYFS1ez.AKUq.dlTwS54Hz BFFFHuCqZnEEGMzjy3bNf6PAk1p3FFl318yIWwj2PoIHW6U38GMEnUpESOAz xfpJuybq7HdbrUmZnPlpamdeHXWdoc8Bqj4CRdeTDigxCU2nzNAHCF1KVXri jgcsPqTlfcBnEjIr4GhBdLjIH5JSLci6WKLw85WmNkVsSm6ZOZc5Dc6z4m.Z YvTOit+nglXdsFWdOcFUrJQJh5PsX4pbzPQK6LfVBgclPq7kdz43KHl3ahg3 7LfJ7XiJ3sGqlvlPxMjGLXzp2K3fOwbndABylXTYoMpvSHpzATCgoxO32dy+ GuGIQnA -----------end_max5_patcher-----------

FYI I finally made some progress… I got orientation to work on the elbow joint

I used the rotation matrix values out of OSCeleton (just one actually Z1) with the equation thetaY = asin(Z1) (oscelton gives you a rotation matrix X1 X2 X3, Y1 Y2 Y3, Z1 Z2 Z3)

and then 2d cartesian trig i’ve used before (atan2((y2-y1)(x2-x1)) for the missing axis… the x axis is fixed/set to 90 degrees. (the final product of those 2 equations also have to be converted from radians to degrees, use n*180 /3.14)

so shapeorient X,Y,Z

becomes…. shapeorient 90, (atan2((y2-y1)(x2-x1))*180/31.4), (asin(Z1)*180/31.4)

anyway this works for my arm test case right now, I’ll update as I get the rest of the body online.

– technically the matrix should work without my point trig above (using some other math I found here < https://groups.google.com/group/openni-dev/browse_frm/thread/ccb8e62acd17b95b/e61fd527cf1394e3?lnk=gst&q=orientation#e61fd527cf1394e3>, but it wasn’t working)

DISCLAIMER I’m not a math guy, I’m just figuring this out as I go along

Hi Jeremy,

Sorry I couldn’t help initially – I only just figured out you can get email notifications on threads here. In the first patch you posted you had the third outlet of 3dcartopol hooked up as a rotation on the z axis, whereas it actually outputs the distance between the points – this might have cause some of the issues.

You started with the same problem I did with the shapes flipping when crossing one axis, due to only having 2 axes of rotation info. I stopped there because I’ve been working on an AR project since, but I did start looking into cross products and dot products, which seemed like they could handle some of the mathematical heavy lifting (I have no background in maths, so most info I found on the web was of no use to me). Heres some of the clearer ones I found:

http://stackoverflow.com/questions/1516296/find-the-normal-angle-of-the-face-of-a-triangle-in-3d-given-the-co-ordinated-of

http://stackoverflow.com/questions/5173707/detecting-an-objects-rotation-in-3d

My next step was going to be either to lock one axis of rotation to a world axis (which I suspected could look odd) or involve a third point (hence looking at the above links). I couldn’t figure out how to break it back down into a 4 value rotation in the time I had though.

Also I think the new OSCeleton mentioned something about outputting joint angles – I don’t know if thats global rotation, or local (either would be pretty cool), but it might help optimize your patch.

Hey Bferns,

no worries,

I actually made some more progress since then and have nearly full degree of movement by doing some math on the rotation matrix (joint rotation data osceleton can now put out) – I’ll post an easy to use patch once it’s perfected.

right now I’m dealing with a small issue of having the middles of all the joints not line up, but I’m sure it’s something simple I’m overlooking.

as a side note I finally bought a bunch of trig/geometry textbooks, if I’m not good with 3D math today I’ll try and be an expert tomorrow,

almost there! -jeremy

Finally some progress! http://www.youtube.com/watch?v=FU-KqZ1U3VM

just used drawobject on a @name gridshape to get the rotation origin working

rotation calculated using the rotation matrix OSCeleton puts out and rotate shape with shapeorient in jit.gl.sketch

here’s the math…

given the rotation matrix:

X axis = (elements[0], elements[3], elements[6])

Y axis = (elements[1], elements[4], elements[7])

Z axis = (elements[2], elements[5], elements[8])

calculate angles with:

thetaY = asin(Z1);

thetaX = atan2(-Z2,Z2);

thetaZ = atan2(-rY1,X1);

FYI the math above doesn’t handle 360 degrees of rotation freedom,

see more here < http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm>

I wish there was a way to transform a gl object with the raw 3X3 matrix instead of converting everything to euler

is there?

I don’t think you can feed a raw matrix to a gl object. I’m having the same problem. However, you can convert the rotation matrix to a quaternion to avoid gimbal locks and singularities that occur with Euler angles and to gain full 360° freedom. Quaternions can be easily translated to Gl rotate format (ie. using the LFO.qn2rot object)

conversion: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm

also make sure you check out the new max 6 quaternion objects:

jit.quat

jit.quat2euler

jit.euler2quat

jit.quat2axis

jit.axis2quat

as well as the jit.anim.node object, which has a gettable attribute called worldtransform, which is the 4×4 world-matrix transform of that object.

any ways these objects can be made more useful to specific tasks, i’m open to hearing!

Hi, Robert. I would love to be able to throw a full 4×4 Gl transform matrix into a jit.anim.node and let it transform children. The intention is to have a max message way to do a glmultmatrix transform

hi diablodale.

i agree this would be useful. look for it to be in the 6.0.2 version of jit.anim.node.

thanks!

Forums > Jitter