3D coordinate transformations
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
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:
https://cycling74.com/forums/index.php?t=msg&goto=588 78&r id=0&S=3b17a358a3f407404debd6245a7af9dc&srch=3D+coor dinate+T ransforms#msg_58878
wes
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
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
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]];
}
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_
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
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
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
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
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
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
>
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
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
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
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
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