IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement 2D, 3D et Jeux Discussion :

Problème avec une caméra utilisant les quaternions


Sujet :

Développement 2D, 3D et Jeux

  1. #1
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut Problème avec une caméra utilisant les quaternions
    Bonsoir,

    Cela fait près d'une semaine que je me démène avec une classe de camera FPS que j'essaye de créer, en utilisant les quaternions. Je n'ai pas réussi, donc je me permet de vous demander un peu d'aide .

    Pour l'instant, je souhaiterai récupérer les mouvements de la souris, et pouvoir mettre à jour le vecteur view via gluLookAt. J'ai d'abord pris un stylo pour essayer de bien comprendre le fonctionnement de gluLookAt, et après cette longue étude pour le moins très scientifique, j'en ait conclu que les trois premiers paramètres de la fonction définissent la position de la camera, ici le bout de mon stylo le plus près de moi, les trois paramètres suivant définissant le point vers laquelle la camera pointe, et les trois derniers un vecteur qui est orthogonal au second.

    En essayant de comprendre cette fonction, j'ai donc bouger mon stylo, tout en regardant le même point, le vecteur view semble donc changer d'orientation. Pour l'instant, je souhaite juste changer cette orientation, en restant au même point fixe. Je pense que le soucis se situe dans une mauvaise compréhension des quaternions, mais j'avoue ne pas très bien comprendre où. Voici mon petit code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    // This function gets input from mouse and keyboard
    void Camera::UpdateFromInput (const sf::RenderWindow & app_)
    {
    	// Get a reference to the input manager associated to our window, and store it for later use
       const sf::Input& Input = app_.GetInput();
    	bool LeftKeyDown = Input.IsKeyDown(sf::Key::Left);
     
    	// Those variables stores the old position of the mouse
    	static int oldMouseX;
    	static int oldMouseY;
     
       // This function gets the position of the mouse
    	int mouseX = Input.GetMouseX();
    	int mouseY = Input.GetMouseY();
     
    	// If the mouse has moved on the x-axis
    	if ((mouseX - oldMouseX) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated (screenwidth / 2 = 90°)
    		double angle = ((90.0 * std::abs (mouseX - oldMouseX)) / (app_.GetWidth() * 0.5));
     
    		// Build a rotation quaternion
    		Quaterniond rotationX;
    		rotationX.SetRotationAboutXAxis (angle);
     
    		// Concatenate transformation
    		cameraOrientation *= rotationX;
    	}
     
    	// If the mouse has moved on the y-axis
    	if ((mouseY - oldMouseY) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated (screenwidth / 2 = 90°)
    		double angle = ((90.0 * std::abs (mouseY - oldMouseY)) / (app_.GetHeight() * 0.5));
     
    		// Build a rotation quaternion
    		Quaterniond rotationY;
    		rotationY.SetRotationAboutYAxis (angle);
     
    		// Concatenate transformation
    		cameraOrientation *= rotationY;
    	}
     
    	// Update static variables
    	oldMouseX = mouseX;
    	oldMouseY = mouseY;
    }
    Ensuite, je récupère le quaternion et j'envoie le tout à gluLookAt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Quaterniond cam = myCamera.GetView();
    gluLookAt (0.0, 0.0, 100.0, cam.x, cam.y, cam.z, 0.0, 1.0, 0.0);

  2. #2
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Personne ?

  3. #3
    Membre éclairé
    Avatar de N_I_C_S
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 450
    Points : 681
    Points
    681
    Par défaut
    Salut,
    je pense que lorsque tu fais une rotation autour de l'axe X, le VECTEUR (0, 1, 0) n'est plus la verticale de la camera. Tu dois aussi passer ce vecteur par les quaternions.
    Et pour être sûr, ta fonction Camera.getView() renvoie-t-elle bien (cameraPosition + cameraOrientation), en l'occurence (0, 0, 100) + cameraOrientation ?

  4. #4
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Sur GameDev on m'a en fait conseillé de ne pas utiliser gluLookAt car gluLookAt créé justement une orientation, or j'ai déjà une orientation (mon quaternion). Il me sufit donc de créer ma propre matrice. Je vais essayer de voir de ce côté là .

  5. #5
    Membre éclairé
    Avatar de N_I_C_S
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 450
    Points : 681
    Points
    681
    Par défaut
    Oui, tout à fait !
    Dans l'absolu, il vaut mieux gérer soi-même la situation de sa camera (position et angles d'orientation) et puis, bah, il suffit d'appliquer les transformations inverses dans OpenGL (d'ailleurs, juste pour ça, même pas besoin d'une classe quaternion; par contre oui pour gérer un vecteur direction...)

  6. #6
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Le truc c'est que j'ai suivi ce qu'un gars de GameDev m'a dit, mais ça ne fonctionne pas comme je veux.

    Je fais donc, par exemple :

    // Rotation autour de l'axe des X
    Quaternion quatX;
    quatX.SetRotationAboutXAxis (angle);
    cameraOrientation = cameraOrientation * quatX;

    // Création de la matrice
    Matrix4 mat (cameraOrientation);
    mat.SetTranslation (pos.x, pos.y, pos.z);
    mat.Inverse ();

    // On envoit le tout à OpenGL
    glMultMatrix (&mat.m00);

    Je ne comprends pas où est l'erreur dans ce code, j'inverse bien la matrice comme on me l'a dit, je vois pas où peut se trouver l'erreur.

  7. #7
    Membre éclairé
    Avatar de N_I_C_S
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 450
    Points : 681
    Points
    681
    Par défaut
    Pourtant, ça peut marcher,

    Peux-tu poster les fonctions et operateurs des quaternions et des matrices, stp??

  8. #8
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Bien sûr (je remets le bout de code, et en dessous la fonction correspondante) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    // Rotation autour de l'axe des X
    Quaternion quatX;
    quatX.SetRotationAboutXAxis (angle);
     
    template <typename T>
    Quaternion<T> & Quaternion<T>::SetRotationAboutXAxis (const T angle_)
    {
    	// First convert the angle to radians
    	T angle = DegToRad (-angle_ * 0.5);
     
    	// We build the quaternion
    	w = std::cos (angle);
    	x = std::sin (angle);
    	y = z = static_cast<T> (0.0);
     
    	return *this;
    }
     
    cameraOrientation = cameraOrientation * quatX;
     
    	template <typename T>
    	inline Quaternion<T> operator* (const Quaternion<T> & quat1_, const Quaternion<T> & quat2_)
    	{
    		return Quaternion<T> (quat1_.w * quat2_.y + quat1_.y * quat2_.w + quat1_.z * quat2_.x - quat1_.x * quat2_.z,
    									 quat1_.w * quat2_.z + quat1_.z * quat2_.w + quat1_.x * quat2_.y - quat1_.y * quat2_.x,
    									 quat1_.w * quat2_.w - quat1_.x * quat2_.x - quat1_.y * quat2_.y - quat1_.z * quat2_.z,
    									 quat1_.w * quat2_.x + quat1_.x * quat2_.w + quat1_.y * quat2_.z - quat1_.z * quat2_.z);
    	}
     
    // Création de la matrice
    Matrix4 mat (cameraOrientation);
     
    template <typename T>
    Matrix4<T>::Matrix4 (const Quaternion<T> & quat_)
    {
    	// We first calculate some sub-expressions
    	T xx (quat_.x * quat_.x), xy (quat_.x * quat_.y), xz (quat_.x * quat_.z), xw (quat_.x * quat_.w);
    	T yy (quat_.y * quat_.y), yz (quat_.y * quat_.z), yw (quat_.y * quat_.w);
    	T zz (quat_.z * quat_.z), zw (quat_.z * quat_.w);
     
    	// Then, we construct the matrix
    	T one = static_cast<T> (1.0);
    	T two = static_cast<T> (2.0);
     
    	m00 = one - two * (yy + zz);
    	m10 = two * (xy - zw);
    	m20 = two * (xz + yw);
     
    	m01 = two * (xy + zw);
    	m11 = one - two * (xx + zz);
    	m21 = two * (yz - xw);
     
    	m02 = two * (xz - yw);
    	m12 = two * (yz + xw);
    	m22 = one - two * (xx + yy);
     
    	// No translation
    	m30 = m31 = m32 = t03 = t13 = t23 = T();
    	t33 = static_cast<T> (1.0);
    }
     
    mat.SetTranslation (pos.x, pos.y, pos.z);
     
    mat.Inverse ();
     
    template <typename T>
    Matrix4<T> & Matrix4<T>::Inverse ()
    {
    	T det (this->Determinant());
    	assert (std::fabs (det) > 0.00001);
     
    	// Multiplication is supposed to be faster than division
    	T oneOverDet (1.0 / det);
     
    	// First column
    	m00 = (m11 * m22 - m12 * m21) * oneOverDet;
    	m10 = (m12 * m20 - m10 * m22) * oneOverDet;
    	m20 = (m10 * m21 - m11 * m20) * oneOverDet;
     
    	// Second column
    	m01 = (m02 * m21 - m01 * m22) * oneOverDet;
    	m11 = (m00 * m22 - m02 * m20) * oneOverDet;
    	m21 = (m01 * m20 - m00 * m21) * oneOverDet;
     
    	// Third column
    	m02 = (m01 * m12 - m02 * m11) * oneOverDet;
    	m12 = (m02 * m10 - m00 * m12) * oneOverDet;
    	m22 = (m00 * m11 - m01 * m10) * oneOverDet;
     
    	// Fourth column
    	t03 = -(t03 * m00 + t13 * m10 + t23 * m20);
    	t13 = -(t03 * m01 + t13 * m11 + t23 * m21);
    	t23 = -(t03 * m02 + t13 * m12 + t23 * m22);	
     
    	return *this;
    }
     
    // On envoit le tout à OpenGL
    glMultMatrix (&mat.m00);

  9. #9
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    J'ai trouvé la solution sur le net ! Voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Quaterniond quatrot;
    static Quaterniond result;
    Vector3d eye (0.0, 0.0, 100.0);
    quatrot.SetRotationAboutYAxis (angle);
    result = quatrot * result;
     
    Matrix4d viewMatrix (quatrot);
    Vector3d xAxis, yAxis, zAxis;
     
    xAxis.Set(viewMatrix(0,0), viewMatrix(1,0), viewMatrix(2,0));
    yAxis.Set(viewMatrix(0,1), viewMatrix(1,1), viewMatrix(2,1));
    zAxis.Set(viewMatrix(0,2), viewMatrix(1,2), viewMatrix(2,2));
     
    viewMatrix(3,0) = -Dot (xAxis, eye);
    viewMatrix(3,1) = -Dot (yAxis, eye);
    viewMatrix(3,2) = -Dot (zAxis, eye);
    J'avoue ne pas très bien comprendre pourquoi il faut faire ça, mais bon .

  10. #10
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    En fait non, ça ne marche pas comme je veux. Donc j'ai vérifié mes fonctions, et celle de mulitplication de 2 quaternions était fausse (je sais pas comment je m'y suis pris...). Par contre, les codes de conversion quaternion->matrice semblent bons. Donc voilà comment je fais à présent :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    // This function gets input from mouse and keyboard
    void Camera::UpdateFromInput (const sf::RenderWindow & app_)
    {
    	// Get a reference to the input manager associated to our window, and store it for later use
       const sf::Input & Input = app_.GetInput();
    	bool LeftKeyDown = Input.IsKeyDown(sf::Key::Left);
     
    	// Those variables stores the old position of the mouse
    	static int oldMouseX;
    	static int oldMouseY;
     
       // This function gets the position of the mouse
    	int mouseX = Input.GetMouseX();
    	int mouseY = Input.GetMouseY();
     
    	static double angleX = 0.0, angleY = 0.0;	
     
    		if (LeftKeyDown)
    		{
    			angleY += 0.01;
     
     
    		// Build a rotation quaternion
    		Quaterniond rotationY;
    		rotationY.SetRotationAboutAxis (Vector3d (0.0, 1.0, 0.0), angleY);	
     
    		// Concatenate the transformation
    		cameraOrientation = rotationY * cameraOrientation;		
    		}
     
     
    	// Update static variables
    	oldMouseX = mouseX;
    	oldMouseY = mouseY;
     
    	// Construct the view matrix, according to the new orientation and position
    	ConstructViewMatrix ();
    }
     
    // Construct the view matrix with the orientation and the position
    void Camera::ConstructViewMatrix ()
    {
    	// First set the orientation given the quaternion
    	viewMatrix.Identity();
    	viewMatrix.Set (cameraOrientation);
     
    	// Now, we're gonna get the first three rows
    	Vector3d xAxis (viewMatrix (0, 0), viewMatrix (1, 0), viewMatrix (2, 0));
    	Vector3d yAxis (viewMatrix (0, 1), viewMatrix (1, 1), viewMatrix (2, 1));
    	Vector3d zAxis (viewMatrix (0, 2), viewMatrix (1, 2), viewMatrix (2, 2));
     
    	// Finally, set the position part of the matrix
    	viewMatrix.SetTranslation (-Dot (xAxis, cameraPosition),
    										-Dot (yAxis, cameraPosition),
    										-Dot (zAxis, cameraPosition));
    }
    EDIT : ça fonctionne avec le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    // This function gets input from mouse and keyboard
    void Camera::UpdateFromInput (const sf::RenderWindow & app_)
    {
    	// Get a reference to the input manager associated to our window, and store it for later use
       const sf::Input & Input = app_.GetInput();
    	bool LeftKeyDown = Input.IsKeyDown(sf::Key::Left);
    	bool RightKeyDown = Input.IsKeyDown(sf::Key::Right);
     
    	// Those variables stores the old position of the mouse
    	static int oldMouseX;
    	static int oldMouseY;
     
       // This function gets the position of the mouse
    	int mouseX = Input.GetMouseX();
    	int mouseY = Input.GetMouseY();
     
    	static double angleX = 0.0, angleY = 0.0;
    	const double mouseSensibility = 20.0;
     
    	// The two quaternions
    	Quaterniond rotationX, rotationY;
     
    	// If the mouse has moved on the x-axis
    	if ((mouseX - oldMouseX) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated
    		angleY -= (mouseX - oldMouseX) / mouseSensibility;
    	}
     
    	// Build a rotation quaternion
    	rotationY.SetRotationAboutYAxis (angleY);
     
    	// If the mouse has moved on the y-axis
    	if ((mouseY - oldMouseY) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated
    		angleX -= (mouseY - oldMouseY) / mouseSensibility;
    	}
     
    	// Build a rotation quaternion
    	rotationX.SetRotationAboutXAxis (angleX);
     
    	// Concatenate the two quaternions
    	cameraOrientation = rotationY * rotationX;		
     
    	// Update static variables
    	oldMouseX = mouseX;
    	oldMouseY = mouseY;
     
    	// Construct the view matrix, according to the new orientation and position
    	ConstructViewMatrix ();
    }
    Ca marche pas trop mal. Je fais mettre une petite scène histoire de voir si ça réagit bien comme je veux, il me restera à implanter les mouvements avec les flèches directionnelles, puis quelques fonctions supplémentaires pour pouvoir suivre un objet... et j'aurais une caméra fonctionnelle.

    Sinon, d'un côté organisation, imaginons un octree tout bête. Quand on voudra tester les AABBs auprès du frustum, est-il plus logique de créer les fonctions au sein même de la classe Camera (par exemple Camera::IsPointVisible), ou bien créer une classe Frustum et avoir un objet frustum, ou bien associé à la classe caméra un objet Frustum (auquel cas la classe Frustum se trouverait dans le dossier math, là ou ma classe Camera se trouve dans mon dossier GameLogic, puisqu'assez spécifique à un style de jeu) ?

  11. #11
    Membre éclairé
    Avatar de N_I_C_S
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 450
    Points : 681
    Points
    681
    Par défaut
    Oui, ton code est mieux, mais attention, si tu pars de tes 2 angles à 0 à chaque boucle (ce qui est mieux pour un pricipe de conservation des données, d'ailleurs), tu auras des problèmes en les calculant avec mouse - oldMouse. Il faudra les calculer avec mouse - unPointFixe (par ex.le centre de l'écran), sinon ils resteront tout le temps à 0.

    Sinon, pour le test de visibilité, je pense qu'il doit être indépendant de la classe Camera, soit dans la classe des octrees (genre Octree.testVisibility(Point3D) ), soit dans une 3eme classe (genre Utils.testVisibility(Point3D, Octree) ). Puis, tu aurais quelque part un truc comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    isVisible = Utils.testVisibility(laCamera.getPosition(), leOctree);

  12. #12
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Salut !

    Voilà ça avance pas trop mal, le code est fonctionnel et j'ai implémenté ce matin les touches du clavier. Ca marche bien, si ce n'est que lorsque la caméra tourne et que j'avance, et bien, ça recule, mais c'est normal, puisque je me contente que d'ajouter 0.1 si j'avance, or si je suis à l'envers, ça recule :p. Enfin bref, ça doit pas être bien compliqué à régler ça, mais il faut que j'attende la nouvelle version de SFML qui me permettra de bloquer la souris au centre de l'écran.

    Oui, ton code est mieux, mais attention, si tu pars de tes 2 angles à 0 à chaque boucle (ce qui est mieux pour un pricipe de conservation des données, d'ailleurs), tu auras des problèmes en les calculant avec mouse - oldMouse. Il faudra les calculer avec mouse - unPointFixe (par ex.le centre de l'écran), sinon ils resteront tout le temps à 0.
    Non, angleX et Y sont static, dont ils gardent leur valeurs (c'est pas très propre, j'ai pas mal de valeurs statiques, mais je vois pas comment les virer)). Faut jsute que j'ajoute un test pour limiter l'angle X (pour éviter que la caméra arrive à faire un tour sur elle-même ).

    Sinon, pour le test de visibilité, je pense qu'il doit être indépendant de la classe Camera, soit dans la classe des octrees (genre Octree.testVisibility(Point3D) ), soit dans une 3eme classe (genre Utils.testVisibility(Point3D, Octree) ). Puis, tu aurais quelque part un truc comme :

    Je pense aussi. En fait je voudrais séparer un maximum les classes mathématiques et les autres classes qui sont dépendantes d'un style de jeu (ma classe Camera se trouve dans le dossier GameUtils, car c'est une caméra type FPS, donc assez spécifique).

    Je sais pas encore si je vais choisir pour le culling une approche normale (en testant avec les 6 plans du frustum que je devrais extraire des matrices d'OpenGL (dans ce cas, ça m'obligera à inclure des fichiers OpenGL dans des classes mathématiques), ou soit l'approche radar de Game Programming Gems 5 qui ne necessite aucune extraction de plans.

    Par contre je comprends pas bien ce que tu dis. L'octree est composé de plusieurs AABB, il me faut donc les tester séparemment. Par exemple :

    Octree * node1;
    if (Camera.IsAABBVisible (node1->min, node1->max))
    // Si false, le noeud et ses enfants ne sont pas visibles, sinon on continue

    Mais là en effet ça me fais mettre des fonctions qui n'ont rien à voir avec la camera.

    Ah oui, voila le code de la caméra, un peu nettoyée. Il reste encore pas mal de boulots et de fonctions à ajouter, mais ça commence à prendre forme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    // Default constructor, do nothing
    Camera::Camera ()
    	: cameraPosition (), cameraOrientation (), viewMatrix (),
    	  mouseSensibility (2.0), movementsSpeed (0.1)
    {
    	// Initialisation of the key configuration with default data
    	keyConfig.insert (std::make_pair ("Left", sf::Key::Left));
    	keyConfig.insert (std::make_pair ("Right", sf::Key::Right));
    	keyConfig.insert (std::make_pair ("Forward", sf::Key::Up));
    	keyConfig.insert (std::make_pair ("Backward", sf::Key::Down));
     
    	// Initialisation of the state of each keys
    	keyStates.insert (std::make_pair (keyConfig["Left"], false));
    	keyStates.insert (std::make_pair (keyConfig["Right"], false));
    	keyStates.insert (std::make_pair (keyConfig["Forward"], false));
    	keyStates.insert (std::make_pair (keyConfig["Backward"], false));
    }
     
    // Set the position of the camera
    void Camera::SetPosition (const Vector3d & position_)
    {
    	cameraPosition = position_;
    }
     
    // This function gets input from mouse and keyboard
    void Camera::UpdateFromInput (const sf::RenderWindow & app_)
    {
    	// Get a reference to the input manager associated to our window, and store it for later use
       const sf::Input & Input = app_.GetInput();
     
    	// ----------------------------------- ROTATION -----------------------------------
     
    	// This function gets the position of the mouse
    	int mouseX = Input.GetMouseX();
    	int mouseY = Input.GetMouseY();
     
    	// Call the function that updates the orientation
    	UpdateOrientation (mouseX, mouseY);
     
    	// ------------------------------------- MOVE -------------------------------------
     
    	// Update the state of each keys
    	KeyStates::iterator itEnd = keyStates.end();
    	for (KeyStates::iterator it = keyStates.begin() ; it != itEnd ; ++it)
    		it->second = Input.IsKeyDown (it->first);
     
    	// Call the function that updates the position of the camera
    	UpdatePosition ();	
     
     
    	// Construct the view matrix, according to the new orientation and position
    	ConstructViewMatrix ();
    }
     
    // This function must be called by UpdateFromInput. It updates the camera
    // orientation given the positions of the mouse
    void Camera::UpdateOrientation (const int mouseX, const int mouseY)
    {
    	// Those variables stores the old position of the mouse
    	static int oldMouseX;
    	static int oldMouseY;
     
    	// And those the angles around each axis
    	static double angleX = 0.0, angleY = 0.0;
     
    	// The two rotation quaternions
    	Quaterniond rotationX, rotationY;
     
    	// If the mouse has moved on the x-axis
    	if ((mouseX - oldMouseX) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated
    		// (a movement on the x-axis means a rotation about the Y camera
    		// axis)
    		angleY += (mouseX - oldMouseX) / mouseSensibility;
    	}
     
    	// Build a rotation quaternion
    	rotationY.SetRotationAboutYAxis (angleY);
     
    	// If the mouse has moved on the y-axis
    	if ((mouseY - oldMouseY) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated
    		// (a movement on the y-axis means a rotation about the X camera
    		// axis)
    		angleX += (mouseY - oldMouseY) / mouseSensibility;
    	}
     
    	// Build a rotation quaternion
    	rotationX.SetRotationAboutXAxis (angleX);
     
    	// Concatenate the two quaternions (the order IS IMPORTANT)
    	cameraOrientation = rotationX * rotationY;		
     
    	// Update static variables
    	oldMouseX = mouseX;
    	oldMouseY = mouseY;
    }
     
    // This function must be called by UpdateFromInput. It updates the position of
    // the camera
    void Camera::UpdatePosition ()
    {
    	if (keyStates[keyConfig["Left"]])
    		cameraPosition.x -= movementsSpeed;
     
    	if (keyStates[keyConfig["Right"]])
    		cameraPosition.x += movementsSpeed;
     
    	if (keyStates[keyConfig["Forward"]])
    		cameraPosition.z -= movementsSpeed;
     
    	if (keyStates[keyConfig["Backward"]])
    		cameraPosition.z += movementsSpeed;
    }
     
    // Construct the view matrix with the orientation and the position
    void Camera::ConstructViewMatrix ()
    {
    	// First set the orientation given the quaternion
    	viewMatrix.Set (cameraOrientation);
     
    	// Now, we're gonna get the first three rows
    	Vector3d xAxis (viewMatrix (0, 0), viewMatrix (1, 0), viewMatrix (2, 0));
    	Vector3d yAxis (viewMatrix (0, 1), viewMatrix (1, 1), viewMatrix (2, 1));
    	Vector3d zAxis (viewMatrix (0, 2), viewMatrix (1, 2), viewMatrix (2, 2));
     
    	// Finally, set the position part of the matrix
    	viewMatrix.SetTranslation (-Dot (xAxis, cameraPosition),
    										-Dot (yAxis, cameraPosition),
    										-Dot (zAxis, cameraPosition));
    }

  13. #13
    Membre éclairé
    Avatar de N_I_C_S
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 450
    Points : 681
    Points
    681
    Par défaut
    angleX et Y sont static, dont ils gardent leur valeurs
    Oups, désolé

    Par contre je comprends pas bien ce que tu dis. L'octree est composé de plusieurs AABB, il me faut donc les tester séparemment.
    Oui, oui, je pensais bien à une fonction récursive (où les enfants d'un Octree sont aussi des Octree), ou une utilisation depuis une fonction récursive, c'était pas très clair.

    En fait, je m'y connais pas trop en octrees, mais le test de Game Programming Gems 5 a l'air mieux, non? En plus, je comprend mieux pourquoi tu tenais à garder la matrice de ta caméra.

  14. #14
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Oui, oui, je pensais bien à une fonction récursive (où les enfants d'un Octree sont aussi des Octree), ou une utilisation depuis une fonction récursive, c'était pas très clair.

    En fait, je m'y connais pas trop en octrees, mais le test de Game Programming Gems 5 a l'air mieux, non?
    La méthode de GPG5 est une méthode "radar", elle est décrite dnas cet article : http://www.lighthouse3d.com/opengl/v...x.php?camspace

    J'ai pas encore eu le temps de me plonger dans les maths impliqués par la méthode, mais l'avantage est qu'on a pas besoin d'extraire les plans de la matrice modelview d'OpenGL, on a juste besoin de trois vecteurs qui expriment le référentiel de la camera, et quelques autres valeurs (la valeur pour le plan éloigné et rapproché, et je crois qu'il faut le fov aussi).

    En plus, je comprend mieux pourquoi tu tenais à garder la matrice de ta caméra.
    Pourquoi dis-tu ça ? Je n'ai nullement besoin de la matrice pour la méthode de GPG5, je crois pas en tout cas. En fait c'est juste pour l'organisation, je préfère bien séparer les fonctions, et j'ai donc une fonction qui calcule la matrice, et une autre qui l'a renvoit (j'aurais pu mettre tout le code de création de la matrice dans la fonction qui renvoit la matrice, ainsi j'aurais pas eu besoin d'avoir une variable membre pour représenter la matrice, mais ça me paraissait pas très logique de mettre un code de création de matrice dans uen fonction Get :p).

  15. #15
    Membre éclairé
    Avatar de N_I_C_S
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 450
    Points : 681
    Points
    681
    Par défaut
    Pourquoi dis-tu ça ? Je n'ai nullement besoin de la matrice pour la méthode de GPG5, je crois pas en tout cas.
    En cherchant ce que c'était, je suis tombé sur un article qui avait l'air de dire ça
    Parce que, dans l'absolu, tu n'as pas forcément besoin d'une matrice, à la limite ni même de quaternions dans une camera FPS. Moi, j'avais en gros procédé ainsi (bon, c'est pas forcément un exemple, mais ça me paraît moins lourd) :

    D'abord, les principaux attributs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Vecteur3D positionPrecedente;
    Vecteur3D positionActuelle; //Les 2 vecteurs position, c'est pour les tests de collision
     
    Vecteur3D directionDeBase = new Vecteur3D(0.0f, 0.0f, -1.0f) //Direction à l'état initial
    Vecteur3D direction;
    float vitesse;
     
    float angleX;
    float angleY;
    float angleZ;
    Une fonction de rotation de la caméra :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Camera::setRotationSouris(int deltaX, int deltaY) {
      angleY += (float)deltaX * <sensibilité souris>;
      angleX += (float)deltaY * <sensibilité souris>;
     
      // Fonction mathematique de rotation rapide du 1er vecteur et stockage du 
      // résultat dans le 2e vecteur.
      // On tourne sur 2 axes car la rotation autour de Z n'influe pas sur 
      // la direction d'une camera FPS.
      vector_fast_YX_rotate(directionDeBase, angleX, angleY, direction);
    }
    Une fonction, par ex., pour avancer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Camera::avancer() {
      positionPrecedente = positionActuelle;
      positionActuelle += (direction * vitesse);
    }
    Et, pour l'affichage, dans la fonction ou la boucle de rendu, quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // le bon ordre des angles pour un FPS : Z, X, Y
    glRotatef(-maCamera.angleZ, 0.0f, 0.0f, 1.0f);
    glRotatef(-maCamera.angleX, 1.0f, 0.0f, 0.0f);
    glRotatef(-maCamera.angleY, 0.0f, 1.0f, 0.0f);
     
    glTranlatef(-maCamera.positionActuelle.x, -maCamera.positionActuelle.y, -maCamera.positionActuelle.z);
    Et si j'ai besoin d'une matrice de la caméra, rien ne m'empêche de la calculer par ailleurs en récupérant les paramètres position et angles.

    Dsl pour les bourdes de syntaxe, ça fait 3 plombes que j'ai pas fait de c++

  16. #16
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Hum... En effet t'as classe me paraît plutôt légère, d'ailleurs c'est bizare car dans tous les tutoriaux que j'ai vu qui utilisent des vecteurs pour les classes de caméra FPS, ils utilisent toujours beaucoup plus de vecteur (un vecteur up, right et forward je crois). Peut-être qu'on a toujours tendance à vouloir faire plus complexe :p. Sinon, l'avantage des quaternions est qu'il propose l'interpolation SLERP. J'ai pas encore essayé, mais visiblement c'est un moyen simple d'interpoler entre deux positions, avec une interpolation sphérique pour ce que j'en ait compris (j'ai un peu de mal avec tous ces maths, je me gourre peut-être sur un terme).

    En tout cas merci pour ton aide. JE vous tiens au courant quand j'ai terminé en entier ma classe, je la posterai ici !

  17. #17
    Membre éclairé
    Avatar de N_I_C_S
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 450
    Points : 681
    Points
    681
    Par défaut
    dans tous les tutoriaux que j'ai vu qui utilisent des vecteurs pour les classes de caméra FPS, ils utilisent toujours beaucoup plus de vecteur (un vecteur up, right et forward je crois)
    Oui, c'est une possibilité, en fait moi je permuttais les composantes du vecteur direction pour trouver les vecteurs orthogonaux, ça gagne un peu de calcul mais tout dépend de ce qu'on veut faire
    En tout cas merci pour ton aide
    Je t'en prie, a+ !

  18. #18
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Voila, j'ai bien avancé ma caméra, depuis que j'ai pu compiler la bêta de la prochaine version de SFML qui me propose dorénavent de pouvoir position le curseur de la souris où je veux. J'ai aussi réussi à faire en sorte que lorsque l'orientation de la caméra bouge, et qu'on souhaite strafer sur la gauche, ça strafe par rapport au nouvel axe X et non l'axe initial. Finalement, avec les quaternions, on se retrouve avec énormément de multiplications de partout. Je vais implémenter la fonction pour regarder vers un point, puis suivre un objet, et faire les intérpolations. Si les interpolations des quaternions m'apportent ce que je pense que ça va m'apporter (je me suis compris ), je garde, sinon je basculerai sur une caméra à base de vecteurs, ce sera sûrement moins casse-pieds (quoique, maintenant que c'est fait...).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    // Default constructor, do nothing
    Camera::Camera ()
    	: cameraPosition (), cameraOrientation (), viewMatrix (),
    	  mouseSensibility (10.0), movementsSpeed (1.0)
    {
    	// Initialisation of the key configuration with default data
    	keyConfig.insert (std::make_pair ("Left", sf::Key::Left));
    	keyConfig.insert (std::make_pair ("Right", sf::Key::Right));
    	keyConfig.insert (std::make_pair ("Forward", sf::Key::Up));
    	keyConfig.insert (std::make_pair ("Backward", sf::Key::Down));
     
    	// Initialisation of the state of each keys
    	keyStates.insert (std::make_pair (keyConfig["Left"], false));
    	keyStates.insert (std::make_pair (keyConfig["Right"], false));
    	keyStates.insert (std::make_pair (keyConfig["Forward"], false));
    	keyStates.insert (std::make_pair (keyConfig["Backward"], false));
    }
     
    // Another constructor that initializes the frustum associated to the camera
    Camera::Camera (const double fovY_, const double viewAspect_, const double zNear_,
    					 const double zFar_)
       : cameraPosition (), cameraOrientation ()
    {
    }
     
    // Set the position of the camera
    void Camera::SetPosition (const Vector3d & position_)
    {
    	cameraPosition = position_;
     
    	// Reconstruct the view matrix
    	ConstructViewMatrix ();
    }
     
    // This function gets input from mouse and keyboard
    void Camera::UpdateFromInput (sf::RenderWindow & app_)
    {
    	// Get a reference to the input manager associated to our window, and store it for later use
       const sf::Input & Input = app_.GetInput();	
     
    	// ----------------------------------- ROTATION -----------------------------------
     
    	// This function gets the position of the mouse
    	int mouseX = Input.GetMouseX();
    	int mouseY = Input.GetMouseY();
    	int halfWidth = app_.GetWidth() / 2;
    	int halfHeight = app_.GetHeight() / 2;
     
    	// Call the function that updates the orientation
    	UpdateOrientation (mouseX, mouseY, halfWidth, halfHeight);
     
    	// Set the mouse position to the center of the screen, so that the mouse cursor will
    	// never be outside the screen
    	app_.SetCursorPosition (halfWidth, halfHeight);
     
    	// ------------------------------------- MOVE -------------------------------------
     
    	// Update the state of each keys
    	KeyStates::iterator itEnd = keyStates.end();
    	for (KeyStates::iterator it = keyStates.begin() ; it != itEnd ; ++it)
    		it->second = Input.IsKeyDown (it->first);
     
    	// Call the function that updates the position of the camera
    	UpdatePosition ();	
     
     
    	// Construct the view matrix, according to the new orientation and position
    	ConstructViewMatrix ();
    }
     
    // This function must be called by UpdateFromInput. It updates the camera
    // orientation given the positions of the mouse
    void Camera::UpdateOrientation (const int mouseX_, const int mouseY_,
    										  const int halfWidth_, const int halfHeight_)
    {	
    	// And those the angles around each axis
    	static double angleX = 0.0, angleY = 0.0;
     
    	// The two rotation quaternions
    	Quaterniond rotationX, rotationY;
     
    	// If the mouse has moved on the x-axis
    	if ((mouseX_ - halfWidth_) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated
    		// (a movement on the x-axis means a rotation about the Y camera
    		// axis)
    		angleY += (mouseX_ - halfWidth_) / mouseSensibility;
    	}
     
    	// Build a rotation quaternion
    	rotationY.SetRotationAboutYAxis (angleY);
     
    	// If the mouse has moved on the y-axis
    	if ((mouseY_ - halfHeight_) != 0)
    	{
    		// Compute the angle by which the camera has to be rotated
    		// (a movement on the y-axis means a rotation about the X camera
    		// axis)
    		angleX += (mouseY_ - halfHeight_) / mouseSensibility;
    	}
     
    	// Build a rotation quaternion
    	rotationX.SetRotationAboutXAxis (angleX);
     
    	// Concatenate the two quaternions (the order IS IMPORTANT)
    	cameraOrientation = rotationX * rotationY;
    }
     
    // This function must be called by UpdateFromInput. It updates the position of
    // the camera
    void Camera::UpdatePosition ()
    {
    	// Get the conjugate quaternion of the camera orientation since cameraOrientation
    	// is a normalized quaternion, and get the new axis given to the new orientation
    	Quaterniond orientationConjugate = Conjugate (cameraOrientation);
    	Vector3d xAxis (1.0, 0.0, 0.0), zAxis (0.0, 0.0, 1.0);
    	xAxis = xAxis * orientationConjugate;
    	zAxis = zAxis * orientationConjugate;
     
    	// Since this is a FPS camera, I have to "block" the position camera on the y-axis
    	zAxis.y = 0.0;
     
    	if (keyStates[keyConfig["Left"]])
    		cameraPosition -= xAxis * movementsSpeed;
     
    	if (keyStates[keyConfig["Right"]])
    		cameraPosition += xAxis * movementsSpeed;
     
    	if (keyStates[keyConfig["Forward"]])
    		cameraPosition -= zAxis * movementsSpeed;
     
    	if (keyStates[keyConfig["Backward"]])
    		cameraPosition += zAxis * movementsSpeed;
    }
     
    // Construct the view matrix with the orientation and the position
    void Camera::ConstructViewMatrix ()
    {
    	// First set the orientation given the quaternion
    	viewMatrix.Set (cameraOrientation);
     
    	// Now, we're gonna get the first three rows
    	Vector3d xAxis (viewMatrix (0, 0), viewMatrix (1, 0), viewMatrix (2, 0));
    	Vector3d yAxis (viewMatrix (0, 1), viewMatrix (1, 1), viewMatrix (2, 1));
    	Vector3d zAxis (viewMatrix (0, 2), viewMatrix (1, 2), viewMatrix (2, 2));
     
    	// Finally, set the position part of the matrix
    	viewMatrix.SetTranslation (-Dot (xAxis, cameraPosition),
    										-Dot (yAxis, cameraPosition),
    										-Dot (zAxis, cameraPosition));
    }

Discussions similaires

  1. Problème avec une requête sur les dates
    Par diblasio dans le forum Requêtes
    Réponses: 11
    Dernier message: 09/08/2011, 16h00
  2. Réponses: 9
    Dernier message: 09/12/2008, 00h07
  3. Problème avec une fonction en utilisant Zsh
    Par Olivier Regnier dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 18/06/2007, 08h19
  4. Problème avec une Fonction utilisant WMI
    Par Eric_78180 dans le forum VBScript
    Réponses: 3
    Dernier message: 29/12/2006, 14h00
  5. problème avec une requete utilisant LIMIT
    Par kow_Ced dans le forum Requêtes
    Réponses: 2
    Dernier message: 11/08/2006, 16h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo