3D coordinate transformations


    Jan 27 2006 | 8:11 pm
    I want to align an object to the local coordinate system of another object,
    so that If I rotate or move object1, object2 moves along and keeps it's
    relative position to object1. I read through chapter 3 of the redbook and
    searched around on the internet before trying to get it right in max. After
    a long time of patching with just "expr" objects and a lot of trial and
    error I got halfway and then I lost track. It seems I really can't figure it
    out on my own and it's driving me nuts. From what I understand now, I need
    to combine their 4x4 matixes, somehow. (?)
    In the first place I want to use this to align objects to the view space
    coordinates, like you're driving a car and the outside world is moving but
    the steering wheel stays in front of you. It seems a pretty common thing in
    3d applications, so I'm hoping someone can explain how to do this in jitter.
    My patch uses several ogl externals, so I can't do everything within one
    gl.sketch
    I think I need to know:
    - how to translate the camera/lookat messages to a 4x4matrix
    - how to apply that matrix to the rotate/position parameters of another ogl
    object.
    I'd really appreciate any help on this.
    Thijs

    • Jan 28 2006 | 6:00 pm
      Hi Thijs,
      A few months back, I posted a JS file and a demo patch as to how to do
      3d coordinate transforms. Here's the link:
      http://www.cycling74.com/forums/index.php?t=msg&goto=588 78&r id=0&S=3b17a358a3f407404debd6245a7af9dc&srch=3D+coor dinate+T ransforms#msg_58878
      wes
    • Jan 28 2006 | 6:15 pm
      This is something GEM (on PureData and Max) handles really nicely.
      they have separate rotateXYZ and transformXYZ objects you can link
      serially in a render chain, which lets you do fairly complex
      movements really easily. This is however due to the way GEM render-
      chains work (afaict).
      does anyone from c74 know if this could be implemented in jitter
      (without having to deal with transformation matrices implicitly ?)
      if it wouldnt be too hard to have a jit.gl.rotate and a
      jit.gl.translate that could be attached to chained objects somehow,
      it could make easier to play with potentially. However im guessing
      that since most ways of working with a jit.gl context is without
      patch cords (automatic 1), making a 'serial' implementation would be
      difficult.
      thoughts?
      am I way off base?
      v a d e //
      www.vade.info
      abstrakt.vade.info
    • Jan 28 2006 | 7:36 pm
      Thanks for the replies. I can't use GEM because I'm on windows. And Wesley,
      I already knew your patch, but when I first looked at it, I didn't really
      understand what it was for. I remembered it and checked it out a second
      time...and still I didn't see how it was related to what I wanted to do.
      Maybe I should check it again and look even closer this time;-)
      I'll give it another try soon, but I guess it would be really nice to have
      some jitter objects dealing with these things like vade mentioned.
      Best, Thijs
    • Jan 28 2006 | 10:04 pm
      Well,
      If that example patc h didn't make sense, maybe this will...download
      the jitter boids ditribution from this page:
      http://www.mat.ucsb.edu/~whsmith/boids.html . In it is the source
      code and the object of interest here is called xray.jit.boidsrender.
      If you look at the planecount=9 case, this section handles 3d
      coordinate transforms. It might be of use to you. Basically, it puts
      every quad into a Y-axis aligned coodinate space and uses
      transformation matrices to move between the original coordinate system
      and the Y-aligned coordinate system.
      Also, after looking at what you want to do, this JS might be more
      instructive. Specifically, look at the Jelly.prototype.orient
      function. It take a vector orientation as an argument and calculates
      the approproate rotatexyz angles for sending to jit.gl.mesh. Here it
      is:
      outlets = 5;
      this.autowatch = 1;
      var userPosition = [0, 0, 0];
      var r2d = 180/Math.PI;
      var numJellies = 14;
      var posMatrix = new JitterMatrix(3, "float32", numJellies,1);
      posMatrix.name = "jelly-pos";
      posMatrix.planecount = 3;
      posMatrix.type = "float32";
      posMatrix.dim = [numJellies, 1];
      // Jelly Constructor
      function Jelly(id)
      {
      this.id = id;
      this.speed = 3.27;
      this.orientation = [0, 0, 1];
      this.angle = [0.0, 0, 0];
      this.position = [0, 0, 0];
      this.line = 0;
      this.group = Math.round(Math.random());
      var snd = Math.random();
      if(snd < 0.33) {
      this.sound = 1;
      this.pitch = [1.5, 1.4];
      }
      else if(snd < 0.66) {
      this.sound = 2;
      this.pitch = [1.0, 1.0];
      }
      else {
      this.sound = 3;
      this.pitch = [1.0, 1.0];
      }
      this.delay = 0;
      outlet(4, "target", id+1);
      outlet(4, "sound", this.sound);
      outlet(4, "pitch", this.pitch);
      outlet(4, "delay", this.delay);
      }
      // Jelly Variables:
      Jelly.prototype.id = 0;
      Jelly.prototype.speed = 3.27;
      Jelly.prototype.orientation = [0, 0, 1];
      Jelly.prototype.angle = [0.0, 0, 0];
      Jelly.prototype.position = [0, 0, 0];
      Jelly.prototype.line = 0;
      Jelly.prototype.group = 0;
      Jelly.prototype.sound = 1;
      Jelly.prototype.pitch = [1.5, 1.4];
      Jelly.prototype.delay = 0;
      // static variables
      var maxline = 45;
      var linescale = 9.5/((maxline-1)*2.7);
      // Jelly Methods:
      Jelly.prototype.dump = function(n)
      {
      post("dumping ",this.id,"with method argument",1,"n");
      }
      //speed*e^(pos/decay)
      Jelly.prototype.swim = function()
      {
      //amount to move
      var distance = Math.exp(-this.line*linescale)/this.speed;
      //vectorize distance by orientation and add to position
      this.position = [this.position[0] + distance*this.orientation[0],
      this.position[1] + distance*this.orientation[1],
      this.position[2] + distance*this.orientation[2]];
      }
      Jelly.prototype.orient = function()
      {
      //Note: OpenGL rotates counter-clockwise
      //theta (atan2(y, x)
      this.angle[2] = r2d*Math.atan2(-this.orientation[1], -this.orientation[0]);
      //phi atan2( hypot(x, y), z)
      this.angle[1] =
      r2d*Math.atan2(Math.sqrt(this.orientation[0]*this.orientatio n[0] +
      this.orientation[1]*this.orientation[1]), -this.orientation[2]);
      }
      //Create Jellies
      var jellies = new Array(numJellies);
      for(var i=0; i < jellies.length; i++) {
      jellies[i] = new Jelly(i);
      }
      function reset()
      {
      for(var i=0; i < jellies.length; i++) {
      jellies[i].position = [0, 0, 0];
      }
      }
      function dump()
      {
      for(var i=0; i < jellies.length; i++) {
      jellies[i].dump(i*2);
      }
      }
      function startSwim()
      {
      for(var i=0; i < jellies.length; i++) {
      jellies[i].line = 0;
      if(Math.random() < 0.2)
      jellies[i].group = 1-jellies[i].group;
      }
      }
      var distance;
      var distVect = new Array();
      var nearOffset;
      var currentPitch;
      var del;
      function bang()
      {
      for(var i=0; i < jellies.length; i++) {
      if(jellies[i].line < maxline) {
      jellies[i].line++;
      jellies[i].swim();
      Jitter3DUtils.vsub(jellies[i].position, userPosition, distVect);
      distance = Jitter3DUtils.vlength(distVect);
      posMatrix.setcell(i, 0, "val", jellies[i].position);
      if(distance < 5)
      nearOffset = 0.2;
      else
      nearOffset = 0;
      // currentPitch = [jellies[i].pitch[0]+Math.random()*0.025-0.0125,
      jellies[i].pitch[1]+Math.random()*0.25-0.0125];
      outlet(2*jellies[i].group+1, jellies[i].position);
      outlet(2*jellies[i].group, "rotatexyz", jellies[i].angle);
      outlet(2*jellies[i].group, "draw");
      outlet(4, "target", i);
      outlet(4, "vol", nearOffset+Math.min(2*1/(distance*distance+0.001), 1.5));
      // outlet(4, "pitch", currentPitch);
      del = jellies[i].delay+Math.random()*300;
      //post(jellies[i].delay + "n");
      outlet(4, "delay", del);
      }
      }
      }
      function orientation(vals)
      {
      jellies[arguments[0]].orientation = [arguments[1], arguments[2], arguments[3]];
      jellies[arguments[0]].orient();
      }
      function speed(vals)
      {
      jellies[arguments[0]].speed = arguments[1];
      }
      function position(vals)
      {
      userPosition = [arguments[0], arguments[1], arguments[2]];
      }
    • Jan 29 2006 | 9:54 pm
      Thanks a lot Wesley. To bad I still don't get it. I spend a few hours going
      through you linetrans and jelly code and trying to patch it. I thought I was
      getting there, but I guess there is just too much about this theory that I
      don't get yet. I tried to use code from linetrans to lock an objects
      position to the camera like this: point1 camera position, point2 lookat
      position and then use the calculated pointp to set the objects position.
      For its rotation I used point1's x+y as inputs to the jelly orient function.
      Unless I'm missing something obvious and you can explain it in a few words,
      I guess I'll give up for now, and maybe try again when I'm smarter or have
      more time.
      Best, T_
    • Jan 30 2006 | 4:17 am
      Hi Thijs,
      I know this kind of stuff can get quite hairy. I spend 6 months off
      and on before I was able to tame 3d coordinates through transforms and
      rotations. In the end, it came down to being very methodical and
      breaking down what I wanted to do into small geometric steps.
      If you could exmplain in detail exactly what you want to do, I think
      it would be easier to help you. Also, if you had an example patch
      that could be worked on, that would make things progress much faster.
      The Jelly JS script I posted earier was for rotating and moving these
      jelly fish-like creatures in 3d. Here's the barebones of how I did
      it:
      properties of a Jelly {
      orientation float[3] //xyz orientation vector
      position float[3] //xyz position
      }
      >From the orientation, I can derive the rotatexyz angles. This is that function:
      Jelly.prototype.orient = function()
      {
      //Note: OpenGL rotates counter-clockwise
      //theta (atan2(y, x)
      this.angle[2] = r2d*Math.atan2(-this.orientation[1],
      -this.orientation[0]);
      //phi atan2( hypot(x, y), z)
      this.angle[1] =
      r2d*Math.atan2(Math.sqrt(this.orientation[0]*this.orientatio n[0] +
      this.orientation[1]*this.orientation[1]), -this.orientation[2]);
      }
      For any given frame that was rendered, I would send 2 messages to
      jit.gl.mesh for each jelly I was rendering:
      rotatexyz angle1 angle2 angle3
      position pos1 pos2 pos3
      That's it.
      wes
    • Jan 31 2006 | 12:08 pm
      That's exactly the code I used from the jellyfish. I'll make an example
      patch soon showing what I'm trying to achieve exactly, but I don't have any
      time for this untill the end of this week. Thanks for all the help.
      Best, Thijs
    • Jan 31 2006 | 9:47 pm
      On Jan 27, 2006, at 12:11 PM, Thijs Koerselman wrote:
      > I want to align an object to the local coordinate system of another
      > object, so that If I rotate or move object1, object2 moves along
      > and keeps it's relative position to object1. I read through chapter
      > 3 of the redbook and searched around on the internet before trying
      > to get it right in max. After a long time of patching with just
      > "expr" objects and a lot of trial and error I got halfway and then
      > I lost track. It seems I really can't figure it out on my own and
      > it's driving me nuts. From what I understand now, I need to combine
      > their 4x4 matixes, somehow. (?)
      I would recommend using jit.gl.sketch in conjunction with the
      drawobject message. You can perform any type of
      hierarchical transformation this way, including those exposed by the
      procedural rendering model of GEM (which essentially uses object
      boxes in sequence for the drawing commands of jit.gl.sketch. Anyone
      that is looking for the GEM model in Jitter, should take a look at
      jit.gl.sketch's drawing commands).
      For example, something like the following:
      glmatrixmode modelview,
      glpushmatrix,
      gltranslate ,
      glrotate 1. 0. 0.,
      glrotate 0. 1. 0.,
      glrotate 0. 0. 1.,
      drawobject ,
      glmatrixmode modelview,
      glpushmatrix,
      gltranslate ,
      glrotate 1. 0. 0.,
      glrotate 0. 1. 0.,
      glrotate 0. 0. 1.,
      drawobject ,
      glmatrixmode modelview,
      glpopmatrix,
      glpopmatrix
      Subpatchers or JS functions could be used to simplify building up
      these command lists.
      Of course you can do all the matrix math yourself if you want, but I
      think the above strategy is a little bit easier.
      -Joshua
    • Feb 01 2006 | 12:42 am
      Joshua, Thanks! I had forgotten about the drawobject usage with
      sketch, this makes things much easier, I will have to play with it.
      Thanks for the reminder, this is exactly what I was looking for
      myself (GEM style procedural, etc).
      v a d e //
      www.vade.info
      abstrakt.vade.info
    • Jun 23 2007 | 6:54 pm
      Hi all,
      is this really that hard to do?:
      I want to rotate a jit.gl.model around different origins.
      Obviously there's no easy way to move the origin, right?
      more precisely described the model should rotate slowly all the time but depending on user interaction another spot of it should be in the middle of the scene.
      The next problem I will have is that the final model will consist of multiple models (with different shaders) which I will have to group together somehow. I have no idea how to do this. If there was the possibility to move the origin it would be very simple.
      thanks
      secco
    • Jun 24 2007 | 10:08 pm
      It sounds like you need to get your hands dirty on a bit of low level
      opengl. When I posted the first message to this thread I didn't know much
      about it either, but since then I've been doing a lot of things like that,
      but if you know how to use it you can basically do anything you want,
      changing origins and all you mention. It took me a while to get my head
      around it, the matrix math and all, but its really worth learning. Look into
      the opengl redbook and numerous tutorials online about transformations.
      If you use drawraw() on jitter gl objects instead of the regular draw()/bang
      they get drawn without their transformation and material related attributes
      (just a plain gray shape at the origin). They can inherit all those things
      from the lowlevel gl calls that you do around those drawraw() calls. You can
      even bind and unbind shaders to change them between different objects you're
      drawing. You'll need to use the glPushMatrix, glPopMatrix, glTranslate and
      glRotate to start with.
      There are two options for doing low level gl in Jitter (without writing your
      own externals) which are jit.gl.sketch (+javascript) and jit.gl.lua.
      Personally I much prefer the latter one. One reason is because it can do
      direct opengl calls similar to the original opengl api. In your scripts
      you'll have complete control over how you draw and group things together.
      To answer to your first question: Its not hard to do once you've
      familiarized yourself with that bit of opengl, but it will take some time
      and effort to get comfortable with it. What you get back is ultimate control
      and more efficient drawing routines. Hope this helps.
      Cheers,
      Thijs
      --
      On 6/23/07, secco wrote:
      >
      >
      > Hi all,
      >
      > is this really that hard to do?:
      > I want to rotate a jit.gl.model around different origins.
      > Obviously there's no easy way to move the origin, right?
      > more precisely described the model should rotate slowly all the time but
      > depending on user interaction another spot of it should be in the middle of
      > the scene.
      > The next problem I will have is that the final model will consist of
      > multiple models (with different shaders) which I will have to group together
      > somehow. I have no idea how to do this. If there was the possibility to move
      > the origin it would be very simple.
      >
      > thanks
      > secco
      >
    • Jun 25 2007 | 10:13 am
      Thanks a lot Thijs,
      I'll try that out.
      Is it somehow possible to step out of the processing of the sketch commands to change some parameters?
      I want to achieve this:
      reset,
      glscale 1 1 1,
      glrotate $3 0 1 0,
      gltranslate $1 0 $2,
      drawobject myfirstobject 1,
      gltranslate $4 0 $4,
      glrotate $5 0 1 0,
      glscale $6 $6 $6,
      drawobject my3dtext 1,
      glrotate $7 0 1 0,
      gltranslate $8 0 $8,
      gltranslate $9 0 $9,
      glrotate $5 0 1 0,
      drawobject my3dtext_but_changed 1
      ...
      I want to draw different texts but with the same object because there will be a lot of textobjects in the scene and I don't want to use a new jit.gl.text3d object for each text. so I have to step out somehow and change the text.
      I can't start a new sketch because the whole bunch is turning in a certain way.
      Probably the way I'm doing it is not the best but it all works fine for me now except of this problem with multiple texts.
      Thanks
      secco
    • Jun 25 2007 | 11:46 am
      On 6/25/07, secco wrote:
      >
      >
      > I want to achieve this:
      > reset,
      > glscale 1 1 1,
      > glrotate $3 0 1 0,
      > gltranslate $1 0 $2,
      > drawobject myfirstobject 1,
      > gltranslate $4 0 $4,
      > glrotate $5 0 1 0,
      > glscale $6 $6 $6,
      > drawobject my3dtext 1,
      > glrotate $7 0 1 0,
      > gltranslate $8 0 $8,
      > gltranslate $9 0 $9,
      > glrotate $5 0 1 0,
      > drawobject my3dtext_but_changed 1
      > ...
      >
      > I want to draw different texts but with the same object because there will
      > be a lot of textobjects in the scene and I don't want to use a new
      > jit.gl.text3d object for each text. so I have to step out somehow and
      > change the text.
      > I can't start a new sketch because the whole bunch is turning in a certain
      > way.
      > Probably the way I'm doing it is not the best but it all works fine for me
      > now except of this problem with multiple texts.
      Hi secco,
      No need to use multiple text objects and certainly no need to start a new
      sketch. Use JavaScript or Lua like I suggested (it'll be easier than sending
      messages from max) , and you have full control over your objects, also in
      between drawing commands. Below is a piece of pseudo JS code. I'm probably
      wrong on the exact function names, cause I haven't used JS in a while...
      myfirstobject = jit.new("jit.gl.model", mycontext)
      my3dtext = jit.new("jit.gl.text3d", mycontext)
      mysketch = jit.new("jit.gl.sketch", mycontext)
      (don't forget to set the objects to @automatic 0)
      with(mysketch)
      {
      glscale(...)
      glrotate(...)
      gltranslate(...)
      drawobject(myfirstobject, 1)
      gltranslate(...)
      glrotate(...)
      glscale(...)
      my3dtext.text("some string")
      drawobject(my3dtext, 1)
      glrotate(...)
      gltranslate(...)
      gltranslate(...)
      glrotate(...)
      my3dtext.text("change the text")
      drawobject(my3dtext, 1)
      }
      Like I said you'll have to figure the syntax out for yourself, but I hope
      you get the idea.
      cheers,
      -thijs
    • Jun 25 2007 | 1:39 pm
      Hi Thijs,
      thanks again. I just tried to install lua and get an error when trying to load the demos:
      error: Error 126 loading external jit.gl.lua
      any idea?
      thanks
      secco
    • Jun 25 2007 | 2:22 pm
      On 6/25/07, secco wrote:
      >
      >
      > Hi Thijs,
      >
      > thanks again. I just tried to install lua and get an error when trying to
      > load the demos:
      > error: Error 126 loading external jit.gl.lua
      > any idea?
      >
      >
      > No idea. I've been running the latest beta3 and previous versions on both
      windows and mac without problems. Did you follow all the installation
      instructions? What version of Max/Jitter are you using?
      -thijs
    • Jun 25 2007 | 2:40 pm
      Are there any other error messages? Here's what needs to happen on OSX:
      put Lua.framework in /Library/Frameworks
      put jit.gl.lua in C74/jitter-externals
      on Windows
      put lua51.dll in Max4.6/support
      put jit.gl.lua in C74/eternals/jitter-externals
      What OS are you on?
      wes