2009-07-13 7 views
1

J'ai une structure de caméra qui contient les vecteurs de position, de direction et de direction. Je voudrais mettre à jour ces vecteurs basés sur le vecteur de gravité que je reçois de l'accéléromètre de l'iPhone. L'effet que je vais faire est le suivant: lorsque le haut du téléphone est incliné, la caméra regarde vers le sol. En d'autres termes, la scène/géométrie suit l'orientation du vecteur de gravité tandis que la caméra suit l'orientation du téléphone lui-même. J'ai pensé que je pourrais multiplier la matrice que j'ai construite à partir des vecteurs de la caméra par celle construite à partir du vecteur de gravité, puis sortir les nouveaux vecteurs de direction et de montée, mais je ne pense pas comprendre complètement le processus. Je n'arrive pas à le faire fonctionner. J'apprécierais grandement toute aide. Merci!Comment contrôler une caméra en openGL avec un vecteur de gravité provenant de l'accéléromètre de l'iPhone?

Répondre

1

Vous devez simplement mettre à jour la direction dans laquelle votre caméra regarde. Vous n'avez pas besoin de changer la matrice du monde, la méthode openGL "gluLookAt()" le fait automatiquement pour vous dans les coulisses. Si vous avez une configuration de classe de caméra, il suffit de créer une fonction pour définir le vecteur de direction de la caméra que vous aurez besoin d'obtenir calculer basé sur une valeur flottante/double (je suppose) de la boussole de l'iPhone. Lorsque la mise à jour de votre caméra est à la position lookAt(), elle doit changer la caméra pour qu'elle soit à l'emplacement correct.

Ce n'est pas très différent de ce que vous faites lorsque vous faites pivoter votre appareil photo dans un jeu basé sur FPS. La différence est que vous voulez faire pivoter la caméra le long de X-Axis au lieu de le long de l'axe Y. Jetez un coup d'œil à la manière dont une classe de caméra effectue une rotation pour déplacer la caméra vers la gauche ou la droite avec le clavier, puis modifiez-la pour qu'elle fonctionne en utilisant les valeurs de direction de votre compas.

Voici un code C++ j'ai écrit qui peut vous donner un aperçu de la façon dont votre classe appareil devrait fonctionner:

/* This reshapes the camera using the perspective projection */ 
void Camera::ReshapePerspectiveForPicking(void) 
{ 
    glMatrixMode(GL_PROJECTION); 

    // Sets the clipping volume 
    gluPerspective(m_FieldOfView, (float)m_width/(float)m_height, m_zNear, m_zFar); 

    gluLookAt( camPos.x, camPos.y, camPos.z, 
      camPos.x + camView.x, camPos.y + camView.y, camPos.z + camView.z, 
      0.0f, 1.0f, 0.0f); 

    glMatrixMode(GL_MODELVIEW); 
} 

Prenez note à la ligne ci-dessus (0.0f, 1.0f, 0,0 F). C'est le vecteur de direction UP. C'était statique pour mon jeu parce que l'appareil photo n'avait jamais besoin de baisser les yeux. Vous auriez simplement besoin de changer ce vecteur en créant un nouveau vecteur vers le haut sur l'orientation de la boussole.

La méthode ci-dessous était simplement une méthode alternative dont nous avions besoin pour parfois mettre à jour la caméra en lui passant un vecteur spécial. Vous pouvez probablement l'ignorer, je l'ai juste inclus pour que vous puissiez en tirer des leçons.

/* This updates the camera to look at the changed camera position. This uses a passed in camPosition and camView GameMath::Vector */ 
    void Camera::Update(GameMath::Vector camPos, GameMath::Vector camView) 
    { 
     glMatrixMode(GL_PROJECTION); 
     gluLookAt( camPos.x, camPos.y, camPos.z, 
       camPos.x + camView.x, camPos.y + camView.y, camPos.z + camView.z, 
       0.0f, 1.0f,0.0f); 
    } 

Voici ma méthode pour faire tourner la caméra le long de l'axe Y (Rappelez-vous souhaitez faire pivoter le long de l'axe X-) -I réécrivaient cette méthode maintenant, car il est un peu louche (je l'ai écrit il y a des années) mais c'est suffisant pour vous montrer comment cela peut être fait.

void Camera::Rotate(void) 
{ 
    if (m_rotateCamera == true) 
    { 
     // Keep the radians within 2 pi, roughly 
     float minimumRadiansRotate = 0.00; 
     float maximumRadiansRotate = 6.2831853072; 
     m_YRotateAngle = GameMath::Wrap(m_YRotateAngle, minimumRadiansRotate, maximumRadiansRotate); 

     m_YRotateAngle += m_rotateSpeed * m_rotateDirection; // Add to the camera's current angle value 
     camView.x = sin(m_YRotateAngle); 
     camView.z = -cos(m_YRotateAngle); 
    } 
} 

Il est un peu difficile de vous fournir un morceau de code spécifique pour faire ce que vous voulez faire parce que votre classe appareil photo est probablement différente de la mienne, même si cela devrait vous permettre de comprendre ce qui doit être fait. Le framework CoreLocation contient les bits de code dont vous aurez besoin pour lire les valeurs de la boussole dans le cas où vous n'avez pas encore codé cette partie.

Bonne chance.

+0

Cela fonctionnerait pour le plus récent iPhone qui a une boussole intégrée (à moins que je comprends mal ce que vous expliquez), mais je ne travaille avec un accéléromètre donc tout ce que j'ai à un moment donné est le nouveau vecteur De plus, le nouveau vecteur ascendant n'est pas garanti perpendiculaire à l'axe des x de la caméra, alors comment déterminer la nouvelle direction de la caméra? –

1

Je pense que le sample GLGravity application d'Apple fait exactement ce que vous voulez, à moins que je ne lis votre demande mal.

+0

Oui, c'est très similaire à ce que j'essaie d'atteindre. C'est pourquoi j'ai commencé mes recherches avec. Cependant, obtenir cet effet tout en stockant les vecteurs d'orientation pour une utilisation ultérieure est l'endroit où je trouve la difficulté. Merci! –

0

Je dois commencer par sayin, je suis très nouveau pour ce genre de choses, alors méfiez-vous, mais ...

i regardé le code ci-dessus et brock son explication et je pense que je suis venu avec une caméra rotative autour des axes x et y. En fait, mon appareil photo tourne autour du z aussi, mais je pense que c'est une histoire différente (je alimente simplement les valeurs filtrées des valeurs de l'accéléromètre x directement au vecteur «up» pour créer l'illusion que mes objets sont affectés par la gravité réelle ... fonctionne plutôt bien).

donc ... voici ce que je suis venu avec:

float lx = sin(DEGREES_TO_RADIANS(horzAngle)); 
float ly = sin(DEGREES_TO_RADIANS(vertAngle)); 
float lz = -cos(DEGREES_TO_RADIANS(horzAngle)); 

float x; 
float y; 
float z; 

    // get the default camera eye for the object 
    // this will center the object on the screen 
[sprite.camera restore]; 
[sprite.camera eyeX:&x eyeY:&y eyeZ:&z]; 

// add distance calcs 
x = x + (-1 * sprite.distance)*(lx); 
z = z + (-1 * sprite.distance)*(-1); 

[sprite.camera setEyeX:x eyeY:y eyeZ:z]; 
[sprite.camera setCenterX:x + lx centerY:y + ly centerZ:z + lz]; 

est d'utiliser la bibliothèque cocos2d (très facile à utiliser) ... ce encapsule les choses de la caméra afin qu'elle va finir par appeler gluLookAt comme ceci:

gluLookAt(eyeX, eyeY, eyeZ, 
      centerX, centerY, centerZ, 
      upX, upY, upZ 
      ); 

comme je l'ai dit, je suis nouveau à cela, donc cela pourrait ne pas regarder à droite, mais il semble ... j'ai l'intention d'ajouter l'accéléromètre pour contrôler la vertAngle que vous décrivez , donc quand j'aurai le code accéléré branché, je vais essayer de me souvenir de poster ça ici.

aussi, si je manque quelque chose que quelqu'un d'autre peut ajouter de la lumière, j'aimerais l'entendre.

grâce,

john

0

Qu'est-ce que vous voulez vraiment est une nouvelle matrice de projection basée sur des valeurs d'accélération. Oolong fournit ce crazy math pour le faire (pas le mien).

/* 
Oolong Engine for the iPhone/iPod touch 
Copyright (c) 2007-2008 Wolfgang Engel http://code.google.com/p/oolongengine/ 

This software is provided 'as-is', without any express or implied warranty. 
In no event will the authors be held liable for any damages arising from the use of this software. 
Permission is granted to anyone to use this software for any purpose, 
including commercial applications, and to alter it and redistribute it freely, 
subject to the following restrictions: 

1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 
3. This notice may not be removed or altered from any source distribution. 
*/ 

#import "Accelerometer.h" 

#define FILTERINGFACTOR 0.1 

@implementation Accel 

- (void) SetupAccelerometer: (float) AcclerometerFrequency 
{ 
     //Configure and start accelerometer 
     [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0/AcclerometerFrequency)]; 
     [[UIAccelerometer sharedAccelerometer] setDelegate:self]; 
} 



- (void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)Acceleration 
{ 
     // use a basic low-pass filter to only keep the gravity in the accelerometer values 
     _accelerometer[0] = Acceleration.x * FILTERINGFACTOR + _accelerometer[0] * (1.0 - FILTERINGFACTOR); 
     _accelerometer[1] = Acceleration.y * FILTERINGFACTOR + _accelerometer[1] * (1.0 - FILTERINGFACTOR); 
     _accelerometer[2] = Acceleration.z * FILTERINGFACTOR + _accelerometer[2] * (1.0 - FILTERINGFACTOR); 
} 

- (void) GetAccelerometerMatrix:(GLfloat *) matrix 
{ 

     GLfloat length = sqrtf(_accelerometer[0] * _accelerometer[0] + _accelerometer[1] * _accelerometer[1] + _accelerometer[2] * _accelerometer[2]); 

     //Clear matrix to be used to rotate from the current referential to one based on the gravity vector 
     bzero(matrix, sizeof(matrix)); 
     matrix[15] = 1.0f; 
     //matrix[3][3] = 1.0; 

     //Setup first matrix column as gravity vector 
     matrix[0] = _accelerometer[0]/length; 
     matrix[1] = _accelerometer[1]/length; 
     matrix[2] = _accelerometer[2]/length; 

     //Setup second matrix column as an arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz} defined by by the equation "Gx * x + Gy * y + Gz * z = 0" in which we arbitrarily set x=0 and y=1 
     matrix[4] = 0.0; 
     matrix[5] = 1.0; 
     matrix[6] = -_accelerometer[1]/_accelerometer[2]; 
     length = sqrtf(matrix[4] * matrix[4] + matrix[5] * matrix[5] + matrix[6] * matrix[6]); 
     matrix[4] /= length; 
     matrix[5] /= length; 
     matrix[6] /= length; 

     //Setup third matrix column as the cross product of the first two 
     matrix[8] = matrix[1] * matrix[6] - matrix[2] * matrix[5]; 
     matrix[9] = matrix[4] * matrix[2] - matrix[6] * matrix[0]; 
     matrix[10] = matrix[0] * matrix[5] - matrix[1] * matrix[4]; 
} 

- (void) GetAccelerometerVector:(double *) AccelValue; 
{ 
     // the vector is read-only, so make a copy of it and do not expose a pointer to it 
     AccelValue[0] = (double)_accelerometer[0]; 
     AccelValue[1] = (double)_accelerometer[1]; 
     AccelValue[2] = (double)_accelerometer[2]; 
} 

@end 
Questions connexes