

[AGAL] Est il possible de travailler avec une matrice3D depuis le GPU ? ✔
#1
Posté 05 June 2012 - 03:02 AM
Je sais comment déclarer une matrix3D comme constante en vue de l'appliquer par le GPU, mais est il possible de manipuler cette matrix avant de l'appliquer (toujours avec le GPU).
Par exemple, est il possible de faire l'équivalent d'un Matrix3D.appendTranslation ou Matrix3D.appendRotation en AGAL ?
Merci d'avance !
#2
Posté 05 June 2012 - 15:51 PM

Oui c'est possible !

En fait, quand on définit une matrix comme constante d'un shader, on définit implicitement 4 constantes sous formes de Vector.<Number> décrivant les 4x4 entrée d'une matrix 3D.
Autrement dit
matrix.identity();
matrix.appendRotation(angle++, Vector3D.Z_AXIS);
matrix.appendTranslation(0, 0, 5);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, matrix, true);
matrix.identity();
matrix.appendRotation(angle++, Vector3D.Z_AXIS);
matrix.appendTranslation(0, 0, 5);
var v:Vector.<Number> = matrix.rawData;
matrix0[0] = v[0];
matrix0[1] = v[1];
matrix0[2] = v[2];
matrix0[3] = v[3];
matrix1[0] = v[4];
matrix1[1] = v[5];
matrix1[2] = v[6];
matrix1[3] = v[7];
matrix2[0] = v[8];
matrix2[1] = v[9];
matrix2[2] = v[10];
matrix2[3] = v[11];
matrix3[0] = v[12];
matrix3[1] = v[13];
matrix3[2] = v[14];
matrix3[3] = v[15];
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, matrix0);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 1, matrix1);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 2, matrix2);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 3, matrix3);
Les deux écriture décrivent ici les même donnée, à ceci prés que l'on doit appliquer calculer manuellement le résultat de la matrix3D dans le GPU, et si on peut le calculer dans le GPU, on peut donc le faire varier depuis le GPU (1 matrix3D par triangle plutot que 1 matrix3D pour un ensemble de triangle !!!).
Coté GPU, le calcul n'est pas monstrueux
"m44 vt0, va0,vc0 \n" +
"mov op,vt0";
"mov vt1, va0 \n" +
"dp4 vt1.x, va0,vc0 \n"+
"dp4 vt1.y, va0,vc1 \n" +
"dp4 vt1.z, va0,vc2 \n" +
"dp4 vt1.w, va0,vc3 \n"+
"mov op, vt1";
++
#3
Posté 05 June 2012 - 15:55 PM

#4
Posté 05 June 2012 - 18:56 PM
tlecoz, le 05 June 2012 - 15:55 PM, dit :

Si je ne me trompe pas, rawData correspond à une lecture de colonne en colonne, par exemple rawData[4] = ligne 1, colonne 2.
Pour la translation et l'échelle, c'est simple, mais pour une rotation, il y a des cos et sin à effectuer aux bons endroits.
S'il y a plusieurs transformations, j'imagine qu'il doit falloir faire des produits de matrice.
Avec une petite recherche, on doit vite pouvoir trouver les opérations exactes.

#5
Posté 05 June 2012 - 19:24 PM
J'y travaille !
#6
Posté 05 June 2012 - 23:30 PM
En fait, tout allait bien jusqu'à ce que je vois le code qui se cache derrière Matrix3D.append(matrix3D)...
Il ressemble à ça
n11 = m.n11 * o11 + m.n12 * o21 + m.n13 * o31 + m.n14 * o41;
n12 = m.n11 * o12 + m.n12 * o22 + m.n13 * o32 + m.n14 * o42;
n13 = m.n11 * o13 + m.n12 * o23 + m.n13 * o33 + m.n14 * o43;
n14 = m.n11 * o14 + m.n12 * o24 + m.n13 * o34 + m.n14 * o44;
n21 = m.n21 * o11 + m.n22 * o21 + m.n23 * o31 + m.n24 * o41;
n22 = m.n21 * o12 + m.n22 * o22 + m.n23 * o32 + m.n24 * o42;
n23 = m.n21 * o13 + m.n22 * o23 + m.n23 * o33 + m.n24 * o43;
n24 = m.n21 * o14 + m.n22 * o24 + m.n23 * o34 + m.n24 * o44;
n31 = m.n31 * o11 + m.n32 * o21 + m.n33 * o31 + m.n34 * o41;
n32 = m.n31 * o12 + m.n32 * o22 + m.n33 * o32 + m.n34 * o42;
n33 = m.n31 * o13 + m.n32 * o23 + m.n33 * o33 + m.n34 * o43;
n34 = m.n31 * o14 + m.n32 * o24 + m.n33 * o34 + m.n34 * o44;
n41 = m.n41 * o11 + m.n42 * o21 + m.n43 * o31 + m.n44 * o41;
n42 = m.n41 * o12 + m.n42 * o22 + m.n43 * o32 + m.n44 * o42;
n43 = m.n41 * o13 + m.n42 * o23 + m.n43 * o33 + m.n44 * o43;
n44 = m.n41 * o14 + m.n42 * o24 + m.n43 * o34 + m.n44 * o44;

Sachant qu'un code AGAL ne peut pas être plus long que 200 lignes, qu'on ne peut pas écrire plus d'un calcul par ligne, que chaque ligne de ce pavé contient 4 multiplication et 3 additions (soit 7 calculs) et qu'il y a 16 ligne, on obtient un minimum de 112 lignes d'AGAL pour convertir de bout de code.
Ce bout de code à lui seul ne sert a rien, il faut compter aussi le(s) code(s) qui décrit la (les) autres objets matrix, bref on peut dans le meilleur des cas appliquer une seule rotation avec un shader ultra bourrin de presque 200 lignes... Je ne suis pas certain que ma carte graphique intégré le vive bien quand je l'appliquerai sur des centaines de milliers de triangles ^^
#7
Posté 06 June 2012 - 01:00 AM
#8
Posté 07 June 2012 - 17:43 PM
Ensuite il suffit de
- soustraire les vertex X/Y au vertex X/Y pour les remettre à 0; (pas necessaire, mais c'est pour tout faire avec une seul variable)
- ajouter l'angle du vertex au radian qui s'incremente
- calculer le sinus et le cosinus du nouvel angle calculé au dessus
- vertex.x = cosinus * distance
- vertex.y = sinus * distance
Bref un truc tout simple en fait ^^
#9
Posté 07 June 2012 - 17:45 PM
Tant que tu y es tu voudrais pas faire un tuto directement ?
Je me suis pas encore mis à Stage3D et à l'AGAL mais ça m'intéresserai de m'y coller juste pour voir.
Vu que tu pose les questions et y apporte rapidement les réponses, je me dis que la même chose sous forme de tuto avec quelques exemples pourrait être bien utile.

Tutoriels Javascript >> Pong - Taquin - Memory - Tic Tac Toe - Pendu - Snake - Proximity - Cascade - Démineur - Bejeweled - Tetris - Collisions -
#10
Posté 07 June 2012 - 19:52 PM
C'est plus facile pour moi de poster une réponse détaillé (ou une suite de réponse) que de prendre le temps de rediger un tuto.
Par ailleurs, quand je cherche un truc je lis rarement les tutos (ou alors vraiment en dernier), je préfère chercher une accumulation de post sur plein de forum autour du même sujet (ce qui ne m'incite pas vraiment à rédiger des tutos).
Mais si tu veux te mettre à Stage3D, ouvre un post sur le forum et je me ferais un plaisir de te répondre (si je peux)

#11
Posté 07 June 2012 - 21:53 PM

Dommage, mais je retient la proposition, pour l'instant je n'ai pas vraiment le temps mais si je m'y colle j'hésiterai pas à t'embêter.
Tutoriels Javascript >> Pong - Taquin - Memory - Tic Tac Toe - Pendu - Snake - Proximity - Cascade - Démineur - Bejeweled - Tetris - Collisions -
#12
Posté 08 June 2012 - 08:49 AM
Citation
Citation
des gens qui se comprenne c'est beau


a+
#13
Posté 08 June 2012 - 09:08 AM

#14
Posté 08 June 2012 - 09:31 AM

Tutoriels Javascript >> Pong - Taquin - Memory - Tic Tac Toe - Pendu - Snake - Proximity - Cascade - Démineur - Bejeweled - Tetris - Collisions -
#15
Posté 19 June 2012 - 22:28 PM
tlecoz, le 05 June 2012 - 15:51 PM, dit :
"m44 vt0, va0,vc0 \n" +
"mov op,vt0";
"mov vt1, va0 \n" +
"dp4 vt1.x, va0,vc0 \n"+
"dp4 vt1.y, va0,vc1 \n" +
"dp4 vt1.z, va0,vc2 \n" +
"dp4 vt1.w, va0,vc3 \n"+
"mov op, vt1";
Si ça se trouve il y a encore plus simple, puisqu'une matrice 4x4 est, dit la doc je ne sais plus où, simplement stockée dans 4 registres successifs. Je ne sais pas si c'est colonne par colonne, ou;ligne par ligne. Comme ça je dirais: colonne par colonne.
Donc si tu uploade correctement des 4 colonnes vers 4 registres, tu peux je pense faire directement le m44 en lui passant le 1er registre des 4 comme paramètre.
Pour ce qui est des append(), effectivement ça revient à multiplier des matrices. J'expliquais ça ici: http://forums.mediab...x/6-composition
Si tu fais cette multiplication selon la formule case par case effectivement c'est long. Mais tu dois pouvoir le faire colonne par colonne, du genre:
Une matrice A dans vc0,vc1,vc2,vc3
Une matrice B dans vt0,vt1,vt2,vt3
m44 vt5, vt1, vc0
m44 vt6, vt2, vc0
m44 vt7, vt3, vc0
Et il y a de fortes chances que tu aies alors la matrice correspondant à A*B, cad B.append(A) dans les registres vt4..vt7, et que tu puisses l'utiliser pour transformer le point va0 en faisant par exemple:
Je n'ai pas testé mais je me sens à peu près sûr de mon coup (je prends des risques là!!!). Je me suis peut-être planté dans l'ordre des choses, mais ça doit être possible.
#16
Posté 19 June 2012 - 22:54 PM
Mais j'ai trouvé une autre technique pour faire ça

Pour faire de la gestion de point en 3D par le GPU, je me suis demandé comment faisait en...AS1
Transform3DPointsTo2DPoints = function(points, axisRotations){
var TransformedPointsArray = [];
var sx = Math.sin(axisRotations.x);
var cx = Math.cos(axisRotations.x);
var sy = Math.sin(axisRotations.y);
var cy = Math.cos(axisRotations.y);
var sz = Math.sin(axisRotations.z);
var cz = Math.cos(axisRotations.z);
var x,y,z, xy,xz, yx,yz, zx,zy, scaleFactor;
var i = points.length;
while (i--){
x = points[i].x;
y = points[i].y;
z = points[i].z;
// rotation around x
xy = cx*y - sx*z;
xz = sx*y + cx*z;
// rotation around y
yz = cy*xz - sy*x;
yx = sy*xz + cy*x;
// rotation around z
zx = cz*yx - sz*xy;
zy = sz*yx + cz*xy;
scaleFactor = focalLength/(focalLength + yz);
x = zx*scaleFactor;
y = zy*scaleFactor;
z = yz;
TransformedPointsArray[i] = make2DPoint(x, y, -z, scaleFactor);
}
return TransformedPointsArray;
};
EDIT :
Citation
Donc si tu uploade correctement des 4 colonnes vers 4 registres, tu peux je pense faire directement le m44 en lui passant le 1er registre des 4 comme paramètre.

Mais le fait qu'il faille faire un calcul pour trouver les valeur de l'objet Matrix m'empêche de généraliser son usage pour chaque triangle / groupe de triangle. Je pensais qu'on pouvait reconstruire la matrix3D qui va bien avec des vectors contenant les positions, rotations et scales .... Mais non, c'est plus compliqué que ça, donc inutile dans mon cas.
Le code AS1 par contre me permet de faire exactement ce que je veux , avec aucun calcul monstrueux en plus ^^
#17
Posté 19 June 2012 - 23:30 PM

#18
Posté 29 June 2012 - 21:41 PM
lilive, le 19 June 2012 - 23:30 PM, dit :

Par ce que sur le GPU, une multiplication de matrices c'est 1 instructions dans le meilleur des cas.
Contre éventuellement plusieurs dizaines sur un CPU.
#19
Posté 30 June 2012 - 03:24 AM

L'idée était de pouvoir faire un
matrix3d.appendScale(scaleX,scaleY,scaleZ);
matrix3d.appendRotation(rotaX,Vector3D.X_AXIS);
matrix3d.appendRotation(rotaY,Vector3D.Y_AXIS);
matrix3d.appendRotation(rotaZ,Vector3D.Z_AXIS);
matrix3d.appendTranslation(x,y,z);
avec des valeur modifiable via des constantes ou via des attributs pour x/y/z/rotationX/rotationY/rotationZ/scaleX/scaleY/scaleZ
L'idée étant d'avoir une valeur différente pour chaque triangle, pas une transformation globale sur toute la mesh
#20
Posté 30 June 2012 - 10:03 AM
Le scale c'est un multiplication.
Pour la rotation, il suffit de construire les 2 lignes de la matrices 4x4 correspondante et de faire des dp3.
Si tu prends sur wikipedia la matrice de rotation X ça donne ça :
public function rotationX(vector : SFloat, angle : Number) : SFloat
{
return float4(
vector.x,
dotProduct3(vector.y, float3(0, cos(angle), negate(sin(angle)))),
dotProduct3(vector.z, float3(0, sin(angle), cos(angle))),
vector.w
);
}
Vu que ça me semble intéressant comme fonctions j'ai ajouté rotationX, rotationY et rotationZ à la classe ShaderPart dans minko.
Ca sera dispos dans les prochains commits si tu veux voir le détail

Pour les translations c'est encore plus simple, c'est juste une addition.
Pour le scale, c'est un multiplication terme à terme, donc une multiplication.
Au final, seules les rotations nécessitent un peu de code.
1 utilisateur(s) li(sen)t ce sujet
0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)