Auteur Sujet: Pourquoi faut-il inverser la matrice cam-to-world le long de l'axe z en OpenGL4  (Lu 2204 fois)

0 Membres et 1 Invité sur ce sujet

Bonjour,

Je change le point de vue sur la scene 3D en OpenGL4 en utilisant une succession de transformations (la matrice est construite dans le vertex shader, c'est un exercice):
  • rotation en y
  • rotation en x
  • translation en x/y (pan)
  • translation en z (zoom)

Cela me donne la matrice suivante (cam-to-world):

cam_to_world = rotatey(roty) * rotatex(rotx) * translate(vec3(tx, ty, 0)) * translate(vec3(0, 0, zoom));


Cela ne marche pas cependant. Si j'ai une sphere centre sur l'origine (0,0,0) et que me camera est "translatee" le long de l'axe z par 5 unites par exemple, je ne vois pas la sphere. Pour la voir, il faut que je scale la matrice world-to-cam par -1 le long de l'axe z, ce qui revient a tourner la camera atour de l'axe y de 180 degrés (voir l'image ci-dessous). Le code que j'utilise est le suivant:

mat4 scale_z = mat4(1);
scale_z[2][2] = -1;
cam_to_world = scale_z * rotatey(roty) * rotatex(rotx) * translate(vec3(tx, ty, 0)) * translate(vec3(0, 0, zoom));


Je ne comprends pas vraiment pourquoi cela est nécessaire ? Est-ce que quelqu'un pourrait m'expliquer svp. Pour que vous compreniez ce que je fais, je vous mets tout le code (en somme je construis toutes les matrices dans le vertex shader. Je sais que ce n'est pas efficace. Je le fais juste comme un exercice et tout ce que je veux c'est que quelqu'un m'explique "pourquoi le scale en z" et rien d'autre ;-).

Merci bien.



mat4 rotatex(float theta)
{
    mat4 rot = mat4(1);

    rot[0] = vec4(1, 0, 0, 0);
    rot[1] = vec4(0, cos(theta), sin(theta), 0);
    rot[2] = vec4(0, -sin(theta), cos(theta), 0);

    return rot;
}

mat4 rotatey(float theta)
{
    mat4 rot = mat4(1);

    rot[0] = vec4(cos(theta), 0, -sin(theta), 0);
    rot[1] = vec4(0, 1, 0, 0);
    rot[2] = vec4(sin(theta), 0, cos(theta), 0);

    return rot;
}

mat4 trans(vec3 tr)
{
    mat4 rot = mat4(1);

    rot[3] = vec4(tr, 1);

    return rot;
}

mat4 persp()
{
    #define M_PI 3.14159265
    float fov = 70;
    float near = 0.1;
    float far = 100;
    float image_aspect_ratio = 1.0;
    float angle = tan(fov * 0.5 / 180.0 * M_PI);
    float right = angle * near * image_aspect_ratio;
    float left = -right;
    float top = angle * near;
    float bottom = -top;

    mat4 persp = mat4(1);

    persp[0] = vec4(2 * near / (right - left), 0, 0, 0);
    persp[1] = vec4(0, 2 * near / (top - bottom), 0, 0);
    persp[2] = vec4((left + right) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1);
    persp[3] = vec4(0, 0, -2 * far * near / (far - near), 0);

    return persp;
}

void main()
{
    mat4 P; //<! the perspective matrix
    mat4 V; //<! the camera-to-world matrix
    mat4 M; //<! the object-to-world matrix

    /*
    // This order gives you Maya-like control
    // rotate the camera around the y axis
    // rotate the camera around the x axos
    // move the camera x & y
    // move away from the origin (zoom)
    */
    mat4 scale_z = mat4(1);
    scale_z[2][2] = -1;
    V = scale_z * rotatey(roty) * rotatex(rotx) * trans(vec3(tx, ty, 0)) * trans(vec3(0, 0, zoom));

    P = persp();

    M = mat4(1); // use the idendity matrix in this example

    /*
    // we need to take the inverse cam-to-world matrix because what we need here
    // is to express points in world space into camera space. Thus we need to apply
    // the world-to-cam matrix to the vertices in world space. After this transformation
    // we can apply the perspective transformation matrix.
    */
    gl_Position =  P * inverse(V) * M * vec4(vp, 1); // our final obj-to-world * world-to-cam * persp vertex transform
}

Alors, je n'ai pas l'explication parfaite, mais une matrice de transformation, pour moi, représente un changement de repère.
Tu as en général 3 matrices de transformations :
- Model qui correspond aux transformations de l'objet par rapport au monde
- View qui correspond aux transformations de la caméra par rapport au monde
- Projection qui sert à passer d'un repère 3D à un repère 2D (l'écran)

Bref, comme ta matrice View représente un changement de repère pour lequel le monde a ta caméra pour origine, avec les axes alignés selon l'orientation de cette caméra, tu dois effectivement appliquer l'inverse de cette transformation à ton objet, pour avoir le résultat dans le repère monde.

Je ne suis pas certain d'être très clair, enfin bref tout ça c'est juste une histoire de changements de repères :)

mast6as

  • Invité
En fait, (et toutes mes excuses a la communauté), la matrice n'a pas besoin du scale en -z... il se trouve que je fais quelque chose de stupide dans le vertex shader qui était d'assigne aux vertex une couleur en utilisant les coordonnées de mon objet (cube) mais au lieu de prendre les coordonnées dans le repère de la camera, je les prenais dans le repere monde... arg...

code que j'ai bien sur retire de mon exemple mais en gros avant je faisait ca:

shad_col = vec3(max(0, vp[0]), max(0, vp[1]), max(0, vp[2]));

en fait il faut que je fasse:

vec4 vp_cam = inverse(V) * vp;
shad_col = vec3(max(0, vp_cam[0]), max(0, vp_cam[1]), max(0, vp_cam[2]));

Et la ca marche nickel, et pas besoin de -1 en z, que je n'arrivais pas a m'expliquer ;-))))

Merci Flure pour ta réponse.

En fait non, ce n'est pas la réponse...

La réponse c'est tout simplement que j'ai fait quelque chose de stupide ;-) Je dessinais les back faces avant les front faces. Je n'ai just pas fait attention a l'ordre dans lequel je declare les vertex. Desole tout le monde, pour cette question qui n'en est finalement pas une ;-)