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

    Feb 25 2011 | 4:55 am
    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:
    glclearcolor 0. 0. 0. 1.
    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

    • Feb 28 2011 | 6:00 pm
      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.
    • Mar 01 2011 | 7:29 am
      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.
    • Jun 07 2011 | 5:24 am
      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]
      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]
      Then after all the cylinders, before the frame is rendered:
      I have created a simple test situation, with points at
      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.
      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.
    • Jun 07 2011 | 2:36 pm
      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.
    • Aug 15 2011 | 1:01 am
      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
    • Aug 15 2011 | 11:57 pm
      never mind, mostly figured out, I'll post my patch shortly
    • Aug 18 2011 | 12:58 am
      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?
    • Aug 21 2011 | 9:48 pm
      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 , but it wasn't working)
      DISCLAIMER I'm not a math guy, I'm just figuring this out as I go along
    • Sep 02 2011 | 3:12 am
      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:
      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.
    • Sep 09 2011 | 5:42 pm
      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
    • Sep 11 2011 | 5:08 pm
      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);
    • Sep 13 2011 | 1:22 pm
      FYI the math above doesn't handle 360 degrees of rotation freedom, see more here
      I wish there was a way to transform a gl object with the raw 3X3 matrix instead of converting everything to euler
      is there?
    • Oct 01 2011 | 1:29 am
      did some math to (with the help of my dad a retired math teacher)
      will post some pdf info about it soon
    • Oct 28 2011 | 4:26 pm
      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)
    • Oct 28 2011 | 10:29 pm
      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 4x4 world-matrix transform of that object.
      any ways these objects can be made more useful to specific tasks, i'm open to hearing!
    • Nov 20 2011 | 11:04 pm
      Hi, Robert. I would love to be able to throw a full 4x4 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
    • Nov 20 2011 | 11:43 pm
      hi diablodale. i agree this would be useful. look for it to be in the 6.0.2 version of jit.anim.node.