# 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:

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?

**all**of the following text. Then, in Max, select

*New 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/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?

did some math to (with the help of my dad a retired math teacher)

will post some pdf info about it soon

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!