Computer Graphics
Marco Tarini
Università dell’Insubria Corso di Laurea in Informatica Anno Accademico 2014/15
Trasformazioni 3D con three.js
Matrici in GLSL
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a
mat4 m , mA , mB ; vec4 v , u;
m = mA * mB ; // prodotto matrice matrice // (riga per colonna)
m *= mB ; // come dire: m = m * mB (non mB * m !) u = m * v ; // prodotto matrice-vettore
u = m[ 0 ] ; // prendi la 1ma colonna di m m[ 3 ] = u ; // setta la 4ta colonna di m
m = mat4( v ) ; // matrice diagonale
m = mat4( 1.0 ) ; // 1 nella diagonale (cioè l’ide)
Matrici in GLSL
mat4 m , mA , mB ; vec4 v , u;
m = transpose( m ); // non oneroso m = inverse( m ); // molto più oneroso!
float k = determinant( m );
m = mA * 5; // moltipilca tutti gli elementi
m = mA + mB; // somma fra matici
mat3 submat = mat3( m ); // sottomatrice 3x3 m = mat4( submat ); // borda con 0, e 1 sulla diago
Vertex shader con transformazione 3D
• Trasformazioni 4x4 = matrici 4x4 (uniforms)
attribute vec3 vertexPos ; attribute vec3 colAttribute ; varying vec3 colVarying;
uniform mat4 mvp ;
void main(void) {
gl_Position = mvp * vec4( vertexPos , 1.0);
colVarying = colAttribute ; }
VE R TE X SH AD ER (G LS L)
X Y Z
(coord W
affine)
Model-View- Projection
(da spazio-oggetto a
spazio-clip in un sol colpo)
Setting the uniforms: caso matrici
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a
G PU
...
uniform mat4 mvp;
...
var mvp_loc = gl.getUniformLocation(
myProg , “mvp"
);
...
gl.uniformMatrix4fv ( mvp_loc , false, xxx );
...
reneder(...); // sends the primitives
C PU
«dammi un vettore (non i valori)»
un Float32Array (16 el)
«column major order»
Serializzare le matrici
Row-major Order
(per riga) : Column-Major Order
(per colonna) :
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a
p o n m
l k j i
h g f e
d c b a
p l h d
o k g c
n j f b
m i e a
trasposta di
« trascrivere come serie di numeri » (in memoria, su disco, etc)
a b c d e f g h i j k l m n o p standard più
Settare la matrice di MVP
• Come una matrice di scalatura?
// da invocare nella draw, prima di mandare le primitive function setUniforms(){
gl.uniformMatrix4fv( mvp_loc, false, new Float32Array( [
0.5, 0, 0, 0, // first column!!!! (not row) 0, 0.5, 0, 0,
0, 0, 0.5, 0, 0, 0, 0, 1, ] )
);
...
}
Settare la matrice di MVP
• Come una matrice di rot di 45° sull’asse Z?
// da invocare nella draw, prima di mandare le primitive function setUniforms(){
gl.uniformMatrix4fv( mvp_loc, false, new Float32Array( [
+0.707, -0.707, 0, 0, // first column!!!! (not row) +0.707, +0.707, 0, 0,
0, 0, 1, 0, 0, 0, 0, 1, ] )
);
...
}
nota: sin(45°) = cos(45°) = 0.707…
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a
Rotazione attorno all'asse x , y , o z
=
1 0 0 0
0 1 0 0
0 0 cos sin
0 0 sin - cos )
( θ θ
θ θ
Z
θ R
=
1 0 0 0
0 cos sin 0
0 sin - cos 0
0 0 0 1 )
( θ θ
θ θ
X
θ R
=
1 0 0 0
0 cos 0 sin -
0 0 1 0
0 sin 0 cos )
( θ θ
θ θ
Y
θ R
Ci serve una libreria JavaScript per matrici, vettori, etc
• three.js
– http://threejs.org
• GLGE
– http://www.glge.org
• SpiderGL
– http://spidergl.org
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a
adottiamo questa
three.js quick start
• download it ( http://threejs.org )
• dal package prendere i builds – three.js
– three.min.js (versione minimale, ci basta per ora)
• metterli a dispozisione della pagina html – (es dentro una cartella “ js/ ”)
• inlcuderli:
<html>
<head>
<script src="js/three.min.js"></script>
<script type="text/javascript">
…
</script>
</head>
he ad
(come tutte le librerie JavaScript)
Matrici in three.js
var
m = new
THREE.Matrix4(); // m = identità/* costruzioni di matrici utili, comprese quelle che abbiamo visto: */
m.makeTranslation( dx, dy, dz );
m.makeScale( sx, sx, sz );
m.makeRotationX( radiants );
m.makeRotationY( radiants );
m.makeRotationZ( radiants );
m.makeAxis( axisX, axisY, axisZ ); // dai tre vettori asse m.makePerspective( fov, aspect, nearZ, farZ );
/* accesso agli elementi */
m.elements(); // un Float32Array con i 16 elementi
Matrici in three.js
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a var
m = new
THREE.Matrix4();var
b = new
THREE.Matrix4();/* moltipilcazione riga colonna: */
m.multiply( b ); // a destra! m *= b;
// cioè m = m*b;
// (equivale a fare prima b, poi m)
/* inversioni etc */
var
det
= m.determinant(); // un floatm.transpose(); // “in place”, cioe’ m = transposta di m ; m.getInverse( b ); // m = inversa di b
/* e molto altro, per es: */
// costruisce una matr. vista (vedi esercizio di trasformazione) m.lookAt ( eyePos, targetPos, upVec );
Un modo per definire la matrice di vista una semplice “Trackball”:
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a
phi theta
z -x
y
var
trackball = {
phi: 0.0, // degrees theta: 0.0, dist: 5.0};
Soluz (traccia):
• Se la camera fosse un oggetto qualsiasi, per portarla nella pos giusta:
– ricetta:
• partenza: camera nello 0, puntata verso –Z, etc.
• prima la sposto sulla Z di dist
• poi lo ruoto attorno alla X di theta
• poi lo ruoto attorno alla Y di phi
Soluz (traccia):
• Allora la matrice di vista V si ottiene invertendo (sia ciascuna op che il loro ordine) :
– ricetta:
• partenza: spazio mondo
• prima lo ruoto attorno alla Y di −phi
• poi lo ruoto attorno alla X di −theta
• poi la sposto sulla Z di −dist
• arrivo: spazio vista
M1 M0 M2
V = M2*M1*M0
Setting della view matrix
• In Javascript (con three.js ) :
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a var
view = new
THREE.Matrix4();var
m0 = new
THREE.Matrix4();var
m1 = new
THREE.Matrix4();var
m2 = new
THREE.Matrix4();m2.makeTranslation( 0,0, -trackball.dist );
view.multiply( m2 );
m1.makeRotationX( -trackball.theta / 180.0 * 3.1415 );
view.multiply( m1 );
m0.makeRotationY( -trackball.phi / 180.0 * 3.1415 );
view.multiply( m0 );
conversione da degree a rad (ma meglio usare Math.PI)
Setting della projection matrix
• In Javascript (con three.js ) :
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a var
view = ...;
var projection = new
THREE.Matrix4();projection.makePerspective( 60, 1.0, 0.5, 100.0 );
var
mvp = new
THREE.Matrix4();mvp.multiply( projection );
mvp.multiply( view );
gl.uniformMatrix4fv( mvp_loc, false, mvp.elements
);
convenientemente, un Float32Array mandiamo la matrice di MVP
allo shader come uniform precedentemente trovato (dopo la costruz. dello shader)
Field of View
(degrees) Aspect Ratio del viewPort
Distanze del Near e Far Clipping Plane
(in spazio vista!)
Proiezione prospettica
−
=
0 / 1 0 0
0 1 0 0
0 0 1 0
0 0 0 1
d P
=
d z
z y x z
y x
/ 1
P
1 / /
d d z
y d z
x
divisione per 4ta comp
matrice di trasformazione per la proiezione prospettica
Paradigmi di interazione 3D
• World in Hand (or Object in Hand)
– mi immagino la camera fissa,
manipolo l’oggetto davanti alla camera – es: un visualizzatore di oggetti 3D
• Camera in Hand
– mi immagino un oggetto / il mondo fermo, muovo la camera intorno
– es: un game 1st person shooter
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a
Depth test, in OpenGL
• Abilitarlo:
gl.enable(gl.DEPTH_TEST);
primitivequipixels tutto il pipeline
(proiezione, setup, rasterizzazione...) stato di OpenGL manipolazioni di stato (es. settare la matrice)
Determinare la condizione per passare il test:
gl.DepthFunc( GL_LESS ) gl.NEVER
gl.EQUAL gl.LEQUAL gl.GREATER gl.NOTEQUAL gl.LESS gl.GEQUAL gl.ALWAYS
(dafault)
M a r c o T a r i n i ‧ C o m p u t e r G r a p h i c s ‧ 2 0 1 4 / 1 5 ‧ U n i v e r s i t à d e l l ’ I n s u b r i a