Forums Développement Multimédia

Aller au contenu

[AGAL] Est il possible de travailler avec une matrice3D depuis le GPU ? ✔

CODE Actionscript

19 réponses à ce sujet

#1 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 05 June 2012 - 03:02 AM

Hello !

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 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 05 June 2012 - 15:51 PM

Je me répond à moi-même :)

Oui c'est possible ! :D

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);
 
peut également être écrit comme ça

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";
 
devient

"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 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 05 June 2012 - 15:55 PM

Ceci dit, n'étant pas un dieu en calcul matriciel, si quelqu'un peut me dire quelle valeur je dois faire varier dans le rawData de la matrix pour appliquer un appendTranslation/Rotation/Scale , cela m'aiderait beaucoup :)

#4 Nelchaël

  • Members
  • PipPipPipPipPipPipPipPip
  • 1900 messages

Posté 05 June 2012 - 18:56 PM

Voir le messagetlecoz, le 05 June 2012 - 15:55 PM, dit :

Ceci dit, n'étant pas un dieu en calcul matriciel, si quelqu'un peut me dire quelle valeur je dois faire varier dans le rawData de la matrix pour appliquer un appendTranslation/Rotation/Scale , cela m'aiderait beaucoup :)
A la page d'aide sur Matrix3D, il y a le schéma de la matrice.
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. ;)
nelchael.fr freelance flash CS6

#5 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 05 June 2012 - 19:24 PM

Merci Nelchael !
J'y travaille !

#6 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 05 June 2012 - 23:30 PM

J'y travaille, j'y travaille, mais plus j'avance plus je pense que l'approche est mauvaise.
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;
 
ce code n'est pas de l'agal, il fait peur mais c'est de l'AS3 :D

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 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 06 June 2012 - 01:00 AM

En fait, je me rend compte qu'il est trés simple d'ajouter une rotationX et/ou une rotationY depuis le GPU (en multipliant le vertex par un sinus/cosinus), mais bizarrement je n'y arrive pas avec une rotationZ (que je pensais être le plus simple à trouver)

#8 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 07 June 2012 - 17:43 PM

pour le rotationZ, en fait ce n'est pas si compliqué , mais il faut prévoir des infos supplementaire dans le vertexData : la distance de chaque vertex par rapport au centre du triangle, et l'angle de chaque vertex par rapport au centre. En constante, j'ai un radian qui s'inscremente.


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 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7017 messages

Posté 07 June 2012 - 17:45 PM

Yop,

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.

;-)

#10 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 07 June 2012 - 19:52 PM

Je ne suis pas contre mais j'ai beaucoup de mal à trouver au même moment le temps et la motivation de le faire (quand je n'ai pas le temps, j'ai envie de le faire et quand j'ai le temps, je préfère faire autre chose...Je ne suis pas ravi de cette situation, mais je commence à me rendre compte que je marche comme ca...).

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 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7017 messages

Posté 07 June 2012 - 21:53 PM

Ouaip je vois bien le principe :smile:
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.

#12 paodao

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 7081 messages

Posté 08 June 2012 - 08:49 AM

Citation

quand je n'ai pas le temps, j'ai envie de le faire et quand j'ai le temps, je préfère faire autre chose

Citation

pour l'instant je n'ai pas vraiment le temps

des gens qui se comprenne c'est beau :Hola:
:smile:
a+

#13 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 08 June 2012 - 09:08 AM

J'ai pensé plus ou moins la même chose en lisant le message de spi :)

#14 Monsieur Spi

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 7017 messages

Posté 08 June 2012 - 09:31 AM

On en est tous là :smile:

#15 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 19 June 2012 - 22:28 PM

Un peu d'eau au moulin en passant:

Voir le messagetlecoz, le 05 June 2012 - 15:51 PM, dit :

Coté GPU, le calcul n'est pas monstrueux

"m44 vt0, va0,vc0 \n" +
"mov op,vt0";
 
devient

"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 vt4, vt0, vc0
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:

m44 op, va0, vt4

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 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 19 June 2012 - 22:54 PM

Interessant !
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

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.
Cela fonctionne , j'ai déjà essayé :)
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 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 19 June 2012 - 23:30 PM

C'est vrai, pourquoi s'embêter avec des multiplications de matrices si on peut faire plus simple? Bien vu le retour aux sources ;)

#18 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 29 June 2012 - 21:41 PM

Voir le messagelilive, le 19 June 2012 - 23:30 PM, dit :

C'est vrai, pourquoi s'embêter avec des multiplications de matrices si on peut faire plus simple? Bien vu le retour aux sources ;)

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 tlecoz

  • Honoris
  • PipPipPipPipPipPipPipPip
  • 3486 messages

Posté 30 June 2012 - 03:24 AM

l'idée etait de le faire coté GPU en fait :)

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 Jean-Marc Le Roux

    Ceinture Noire

  • Minko
  • PipPipPipPipPipPipPip
  • 210 messages

Posté 30 June 2012 - 10:03 AM

La translation c'est une addition.
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)