Set your presentation theme:
Black (default) -
White -
League -
Sky -
Beige -
Simple
Serif -
Blood -
Night -
Moon -
Solarized
H:
Jean Pierre Charalambos
Universidad Nacional de Colombia
Presentation best seen online
See also the source code
H:
- Intro
- Active vs pasive transformations
- Composition
- Main spaces
- Modelling and view
- Matrix handling in the p5.treegl framework
- References
H:
Active Transformation (standard basis) vs Passive Transformation (change of basis)
- Check the p5 transformations tutorial first
- Check also the affine transformations presentation
N:
- Standard = Canonical
V:
Consider the following sequence of transformations:
$P_1=M_1P,$
$P_2=M_1M_2P_1,$
$...,$
$P_n=M_n^*P$
where $M_n^*=M_1M_2...M_n$
Observation: The above composed transform may be implemented either with low-level matrix multiplication (applyMatrix(matrix)) or with mid-level functions such as: translate(), rotate(), scale().
H:
Consider the function axes() which draws the X (horizontal) and Y vertical) axes:
function axes() {
push();
// X-Axis
strokeWeight(4);
stroke(255, 0, 0);
fill(255, 0, 0);
line(0, 0, 100, 0);//horizontal red X-axis line
text("X", 100 + 5, 0);
// Y-Axis
stroke(0, 0, 255);
fill(0, 0, 255);
line(0, 0, 0, 100);//vertical blue Y-axis line
text("Y", 0, 100 + 15);
pop();
}V:
let's first call the axes() function to see what it does:
function draw() {
background(50);
axes();
}V:
now let's call it again, but pre-translating it first:
function draw() {
background(50);
axes();
translate(300, 180);//translation
axes();//2nd call
}V:
let's add a rotation to the second axes() call:
function draw() {
background(50);
axes();
translate(300, 180);
rotate(QUARTER_PI / 2);//rotation after translation
axes();//2nd call
}V:
let's do something similar with a third axes() call:
function draw() {
background(50);
axes();
translate(300, 180);
rotate(QUARTER_PI/2);
axes();
translate(260, -180);
rotate(-QUARTER_PI);
scale(1.5);//even scaling it
axes();//3rd call
}V:
see the result when we animate only the first rotation;
function draw() {
background(50);
axes();
translate(300, 180);
rotate(QUARTER_PI/2 * frameCount);//animation line
axes();
translate(260, -180);
rotate(-QUARTER_PI);
scale(1.5);
axes();
}V:
and now see the result when we animate only the second rotation;
function draw() {
background(50);
axes();
translate(300, 180);
rotate(QUARTER_PI/2);
axes();
translate(260, -180);
rotate(-QUARTER_PI * frameCount);//animation line
scale(1.5);
axes();
}V:
Modelling and view: Scene-graph
A scene-graph is a directed acyclic graph (DAG) of nodes which root is the world coordinate system
V:
World
^
|
L1
^
|\
L2 L3Scenegraphs are simply and elegantly implemented by means of affine transformations using a matrix stack. See push() and pop()
V:
World
^
|
L1
^
|\
L2 L3function drawModel() {
// define a local node L1 (respect to the world)
push(); // saves current matrix transform (I)
affineTransform1(); // resulting in: I * affineTransform1()
drawL1();
// define a local node L2 respect to L1
push(); // saves current matrix transform (I * affineTransform1())
affineTransform2(); // resulting in: I * affineTransform1() * affineTransform2()
drawL2();
// "return" to L1
pop(); // removes the top of the stack, restoring I * affineTransform1()
// define a local coordinate system L3 respect to L1
push(); // saves current matrix transform (I * affineTransform1())
affineTransform3(); // resulting in: I * affineTransform1() * affineTransform3()
drawL3();
// return to L1
pop(); // removes the top of the stack, restoring I * affineTransform1()
// return to World
pop(); // removes the top of the stack, restoring I
}V:
V:
World
^
|\
... Eye
^
|\
... ...Let the eye node transform be defined, like it is with any other node, as:
$M_{eye}^*$
The eye transform is therefore:
$\left.M_{eye}^{*}\right.^{-1}$
For example, for an eye node transform:
$M_{eye}^*=T(x,y,z)R(\beta)S(s)$
The eye transform would be:
$\left.M_{eye}^{*}\right.^{-1}=S(1/s)R(-\beta)T(-x,-y,-z)$
N:
$M_{eye}^*$ would position (orient, scale, ...) the eye node
in the world, but want it to be the other way around (i.e., draw the scene from the eye point-of-view)
V:
World
^
|\
L1 Eye
^
|\
L2 L3function draw() {
// the following sequence would position (orient, scale, ...) the eye node in the world:
// translate(eyePosition.x, eyePosition.y);
// rotate(eyeOrientation);
// scale(eyeScaling)
// drawEye();
scale(1/eyeScaling);
rotate(-eyeOrientation);
translate(-eyePosition.x, -eyePosition.y);
drawModel();
}V:
H:
Matrix handling in p5.treegl
- The model matrix (
$M$) maps from (object) node space to world space - The view matrix (
$V$) maps from world space to eye space - The projection (
$P$) matrix maps from eye space to clip space
Composing all three, i.e.,
$P * V * M$, would thus map from object space to clip space
V:
Matrix handling in p5.treegl
- When the bottom of the matrix stack is filled with the identity matrix (
$I$), its top is referred to as the model matrix - When the bottom of the matrix stack is filled with the view matrix (
$V$), its top is referred to as the modelview matrix
V:
Matrix handling in p5.treegl
iMatrix(): Returns the identity matrix.tMatrix(matrix): Returns the tranpose ofmatrix.invMatrix(matrix): Returns the inverse ofmatrix.axbMatrix(a, b): Returns the product of theaandbmatrices.lMatrix(from, to): Returns the 4x4 matrix that transforms locations (points) from matrixfromto matrixto.dMatrix(from, to): Returns the 3x3 matrix that transforms displacements (vectors) from matrixfromto matrixto. ThenMatrixbelow is a special case of this one.
Observation: All returned matrices are instances of p5.Matrix.
V:
Matrix handling in p5.treegl
treeLocation(vector, [{[from = SCREEN], [to = WORLD], [pMatrix], [vMatrix], [eMatrix], [pvMatrix], [pvInvMatrix]}]): transforms locations (points) from matrixfromto matrixto.treeDisplacement(vector, [{[from = EYE], [to = WORLD], [vMatrix], [eMatrix], [pMatrix]}]): transforms displacements (vectors) from matrixfromto matrixto.
Observations
- Returned transformed vectors are instances of p5.Vector.
fromandtomay also be specified as either:'WORLD','EYE','SCREEN'or'NDC'.- When no matrix params are passed the renderer current values are used instead.
V:
Matrix handling in p5.treegl
pMatrix(): Returns the current projection matrix.mvMatrix([{[vMatrix], [mMatrix]}]): Returns the modelview matrix.mMatrix([{[eMatrix], [mvMatrix]}]): Returns the model matrix.eMatrix(): Returns the current eye matrix (the inverse ofvMatrix()). In addition top5and p5.RendererGL instances, this method is also available to p5.Camera objects.vMatrix(): Returns the view matrix (the inverse ofeMatrix()). In addition top5and p5.RendererGL instances, this method is also available to p5.Camera objects.pvMatrix([{[pMatrix], [vMatrix]}]): Returns the projection times view matrix.pvInvMatrix([{[pMatrix], [vMatrix], [pvMatrix]}]): Returns thepvMatrixinverse.nMatrix([{[vMatrix], [mMatrix], [mvMatrix]}]): Returns the normal matrix.
Observations
- All returned matrices are instances of p5.Matrix.
- When no matrix params are passed the renderer current values are used instead.
V:
Matrix handling in p5.treegl
lPlane([pMatrix]): Returns the left clipping plane.rPlane([pMatrix]): Returns the right clipping plane.bPlane([pMatrix]): Returns the bottom clipping plane.tPlane([pMatrix]): Returns the top clipping plane.nPlane([pMatrix]): Returns the near clipping plane.fPlane([pMatrix]): Returns the far clipping plane.fov([pMatrix]): Returns the vertical field-of-view (fov) in radians.hfov([pMatrix]): Returns the horizontal field-of-view (hfov) in radians.
Observation: when no projection (pMatrix) matrix is passed the renderer current value is used instead.
H: