Ciao David,
premetto che su questo forum ci sono utenti moooolto più esperti del sottoscritto, ti rispondo perchè vedo che fai riferimento a un articolo che postai sul mio blog tempo fa.
Non uso più quell'approccio, che avevo trovato utile per capire alcuni concetti da niubbo. Tuttavia ho ancora il progetto che mi compila e, dopo averlo provato, non riesco a replicare il problema.
In quell'esempio quando ruoto la telecamera attorno agli assi D, U, R li ricalcolo in modo che siano sempre solidali con la posizione corrente della telecamera. Mi pare di capire che nel tuo caso ci sia qualcosa che non va nel momento in cui ruoti la telecamera per "guardare" in alto o in basso. Questo movimento è quello di rotazione della telecamera sul vettore R. In questo caso R rimane fisso e D (direction) e U (up) dovranno essere ricalcolati.
Rispetto alla classe che avevo scritto io è difficile dire cosa ci sia di diverso, quindi te la riporto in toto. E' presente sia la la classe GLCamera (che quando scrissi il post rinominai DSCamera) che la classe DSMath che include le funzioni che uso per effettuare operazioni fra vettori.
Puoi fare delle verifiche per capire se faccio qualcosa di diverso rispetto a quello che fai tu, il codice che ho postato è sufficiente per capire cosa viene processato dal momento in cui si preme su un tasto della tastiera fino alla chiamata alla funzione glLookAt.
DSMath.h
Codice:
#ifndef _DSMATH_H_
#define _DSMATH_H_
#include <math.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <OpenGL/glext.h>
#include <GLUT/glut.h>
#define PI 3.1415926535898
typedef struct tag_DSVector2f
{
GLfloat u;
GLfloat v;
} DSVector2f;
typedef struct tag_DSVector3f
{
GLfloat x;
GLfloat y;
GLfloat z;
} DSVector3f;
DSVector3f VectorProduct(DSVector3f a, DSVector3f b);
DSVector3f VectorSum(DSVector3f a, DSVector3f b);
DSVector3f VectorDiff(DSVector3f a, DSVector3f b);
GLfloat ScalarProduct(DSVector3f a, DSVector3f b);
GLfloat VectorLenght(DSVector3f a);
DSVector3f VectorNormalized(DSVector3f a);
DSVector3f RotateAroundXAxis(DSVector3f input, GLfloat degrees);
DSVector3f RotateAroundYAxis(DSVector3f input, GLfloat degrees);
DSVector3f RotateAroundZAxis(DSVector3f input, GLfloat degrees);
DSVector3f RotateAroundAnyAxis(DSVector3f input, DSVector3f axis, GLfloat degrees);
#endif
DSMath.cpp
Codice:
#include <iostream>
#include "DSMath.h"
#include <math.h>
DSVector3f VectorProduct(DSVector3f a, DSVector3f b)
{
DSVector3f c;
c.x = a.y*b.z - b.y*a.z;
c.y = a.z*b.x - a.x*b.z;
c.z = a.x*b.y - a.y*b.x;
return c;
}
DSVector3f VectorSum(DSVector3f a, DSVector3f b)
{
DSVector3f result;
result.x = a.x + b.x;
result.y = a.y + b.y;
result.z = a.z + b.z;
return result;
}
DSVector3f VectorDiff(DSVector3f a, DSVector3f b)
{
DSVector3f result;
result.x = a.x - b.x;
result.y = a.y - b.y;
result.z = a.z - b.z;
return result;
}
GLfloat ScalarProduct(DSVector3f a, DSVector3f b)
{
GLfloat result = a.x*b.x + a.y*b.y + a.z*b.z;
return result;
}
GLfloat VectorLenght(DSVector3f a)
{
GLfloat result = sqrt(a.x*a.x + a.y*a.y + a.z*a.z);
return result;
}
DSVector3f VectorNormalized(DSVector3f a)
{
DSVector3f result = {0.0f, 0.0f, 0.0f};
GLfloat lenght = VectorLenght(a);
if (lenght != 0.0)
{
result.x = a.x / lenght;
result.y = a.y / lenght;
result.z = a.z / lenght;
}
return result;
}
DSVector3f RotateAroundXAxis(DSVector3f input, GLfloat degrees)
{
DSVector3f output;
GLfloat radians = degrees*PI/180;
output.x = input.x;
output.y = cosf(radians)*input.y + sinf(radians)*input.z;
output.z = -sinf(radians)*input.y + cosf(radians)*input.z;
return output;
}
DSVector3f RotateAroundYAxis(DSVector3f input, GLfloat degrees)
{
DSVector3f output;
GLfloat radians = degrees*PI/180;
output.x = cosf(radians)*input.x - sinf(radians)*input.z;
output.y = input.y;
output.z = sinf(radians)*input.x + cosf(radians)*input.z;
return output;
}
DSVector3f RotateAroundZAxis(DSVector3f input, GLfloat degrees)
{
DSVector3f output;
GLfloat radians = degrees*PI/180;
output.x = cosf(radians)*input.x + sinf(radians)*input.y;
output.y = -sinf(radians)*input.x + cosf(radians)*input.y;
output.z = input.z;
return output;
}
DSVector3f RotateAroundAnyAxis(DSVector3f input, DSVector3f axis, GLfloat degrees)
{
DSVector3f output;
GLfloat radians = degrees*PI/180;
DSVector3f normalizedAxis = VectorNormalized(axis);
GLfloat C = cosf(radians);
GLfloat S = sinf(radians);
GLfloat DOT = ScalarProduct(input, normalizedAxis);
output.x = normalizedAxis.x*DOT*(1-C) + C*input.x + ((-normalizedAxis.z)*(input.y) + (normalizedAxis.y)*(input.z))*S;
output.y = normalizedAxis.y*DOT*(1-C) + C*input.y + ((normalizedAxis.z)*(input.x) - (normalizedAxis.x)*(input.z))*S;
output.z = normalizedAxis.z*DOT*(1-C) + C*input.z + ((-normalizedAxis.y)*(input.x) + (normalizedAxis.x)*(input.y))*S;
return output;
}
GLCamera.h
Codice:
#ifndef _GLCAMERA_H_
#define _GLCAMERA_H_
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <OpenGL/glext.h>
#include <GLUT/glut.h>
#include "GLKeyboardManager.h"
#include "DSMath.h"
class GLCamera
{
public:
GLCamera();
void UpdatePosition(void);
void UpdatedDirectionAxis(void);
void UpdatedUpAxis(void);
void UpdatedRightAxis(void);
// Translate Camera
void MoveRight(void);
void MoveLeft(void);
void MoveUp(void);
void MoveDown(void);
void ZoomIn(void);
void ZoomOut(void);
// Rotate Camera
void RotateCW_DirectionVector(void);
void RotateCCW_DirectionVector(void);
void RotateCW_UpVector(void);
void RotateCCW_UpVector(void);
void RotateCW_RightVector(void);
void RotateCCW_RightVector(void);
// Set Position
void SetPosition(GLfloat x, GLfloat y, GLfloat z);
private:
// Keynboard manager instance
GLKeyboardManager *m_keyboardManager;
// Camera per-frame increment
GLfloat m_translationDelta;
GLfloat m_rotationDelta;
// Camera Rotation
GLfloat m_directionAxisRotation;
GLfloat m_upAxisRotation;
GLfloat m_rightAxisRotation;
// Local Coordinates System
DSVector3f m_position;
DSVector3f m_upVector;
DSVector3f m_directionVector;
DSVector3f m_rightVector;
};
GLCamera.cpp
Codice:
#include <iostream>
#include "GLCamera.h"
#include "DSMath.h"
GLCamera::GLCamera()
{
m_keyboardManager = GLKeyboardManager::Instance();
m_translationDelta = 0.1f;
m_rotationDelta = 0.5f;
// Starting Camera Position
m_position.x = 0.0f;
m_position.y = 0.0f;
m_position.z = 0.0f;
// Starting Camera Rotation
m_directionAxisRotation = 0.0f;
m_rightAxisRotation = 0.0f;
m_upAxisRotation = 0.0f;
m_directionVector.x = 0.0f;
m_directionVector.y = 0.0f;
m_directionVector.z = -1.0f;
m_upVector.x = 0.0f;
m_upVector.y = 1.0f;
m_upVector.z = 0.0f;
m_rightVector = VectorProduct(m_directionVector, m_upVector);
return;
}
void GLCamera::UpdatePosition()
{
if (m_keyboardManager->m_capsShiftPressed)
{
if (m_keyboardManager->m_arrowUpPressed)
this->ZoomIn();
if (m_keyboardManager->m_arrowDownPressed)
this->ZoomOut();
}
else if (m_keyboardManager->m_ctrlPressed)
{
if (m_keyboardManager->m_arrowUpPressed)
this->ZoomIn();
if (m_keyboardManager->m_arrowDownPressed)
this->ZoomOut();
}
else if (!(m_keyboardManager->m_ctrlPressed || m_keyboardManager->m_capsShiftPressed))
{
if (m_keyboardManager->m_arrowLeftPressed)
this->MoveLeft();
if (m_keyboardManager->m_arrowRightPressed)
this->MoveRight();
if (m_keyboardManager->m_arrowUpPressed)
this->MoveUp();
if (m_keyboardManager->m_arrowDownPressed)
this->MoveDown();
if (m_keyboardManager->m_Q_Pressed)
this->RotateCCW_RightVector();
if (m_keyboardManager->m_A_Pressed)
this->RotateCW_RightVector();
if (m_keyboardManager->m_Z_Pressed)
this->RotateCCW_DirectionVector();
if (m_keyboardManager->m_X_Pressed)
this->RotateCW_DirectionVector();
if (m_keyboardManager->m_O_Pressed)
this->RotateCCW_UpVector();
if (m_keyboardManager->m_P_Pressed)
this->RotateCW_UpVector();
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Create the LookAt Matrix
// Create the Translation Matrix
// Multiply LookAt and Translation Matrices
// Apply transformation
// We leave the gluLookAt call to ve sure the vectors for the local camera are correct
gluLookAt(m_position.x, m_position.y, m_position.z,
m_position.x + m_directionVector.x, m_position.y + m_directionVector.y, m_position.z + m_directionVector.z,
m_upVector.x, m_upVector.y, m_upVector.z);
}
void GLCamera::MoveRight(void)
{
m_position.x += m_translationDelta*m_rightVector.x;
m_position.y += m_translationDelta*m_rightVector.y;
m_position.z += m_translationDelta*m_rightVector.z;
}
void GLCamera::MoveLeft(void)
{
m_position.x -= m_translationDelta*m_rightVector.x;
m_position.y -= m_translationDelta*m_rightVector.y;
m_position.z -= m_translationDelta*m_rightVector.z;
}
void GLCamera::MoveUp(void)
{
m_position.x += m_translationDelta*m_upVector.x;
m_position.y += m_translationDelta*m_upVector.y;
m_position.z += m_translationDelta*m_upVector.z;
}
void GLCamera::MoveDown(void)
{
m_position.x -= m_translationDelta*m_upVector.x;
m_position.y -= m_translationDelta*m_upVector.y;
m_position.z -= m_translationDelta*m_upVector.z;
}
void GLCamera::ZoomIn()
{
m_position.x += m_translationDelta*m_directionVector.x;
m_position.y += m_translationDelta*m_directionVector.y;
m_position.z += m_translationDelta*m_directionVector.z;
}
void GLCamera::ZoomOut()
{
m_position.x -= m_translationDelta*m_directionVector.x;
m_position.y -= m_translationDelta*m_directionVector.y;
m_position.z -= m_translationDelta*m_directionVector.z;
}
void GLCamera::RotateCW_DirectionVector()
{
m_directionAxisRotation = m_rotationDelta;
this->UpdatedDirectionAxis();
}
void GLCamera::RotateCCW_DirectionVector()
{
m_directionAxisRotation = -m_rotationDelta;
this->UpdatedDirectionAxis();
}
void GLCamera::RotateCW_RightVector() // A button
{
m_rightAxisRotation = -m_rotationDelta;
this->UpdatedRightAxis();
}
void GLCamera::RotateCCW_RightVector()
{
m_rightAxisRotation = m_rotationDelta;
this->UpdatedRightAxis();
}
void GLCamera::RotateCW_UpVector()
{
m_upAxisRotation = -m_rotationDelta;
this->UpdatedUpAxis();
}
void GLCamera::RotateCCW_UpVector() // O Button
{
m_upAxisRotation = m_rotationDelta;
this->UpdatedUpAxis();
}
void GLCamera::UpdatedDirectionAxis()
{
m_upVector = RotateAroundAnyAxis(m_upVector, m_directionVector, m_directionAxisRotation);
m_rightVector = VectorProduct(m_directionVector, m_upVector);
}
void GLCamera::UpdatedUpAxis()
{
m_directionVector = RotateAroundAnyAxis(m_directionVector, m_upVector, m_upAxisRotation);
m_rightVector = VectorProduct(m_directionVector, m_upVector);
}
void GLCamera::UpdatedRightAxis()
{
m_upVector = RotateAroundAnyAxis(m_upVector, m_rightVector, m_rightAxisRotation);
m_directionVector = RotateAroundAnyAxis(m_directionVector, m_rightVector, m_rightAxisRotation);
}
void GLCamera::SetPosition(GLfloat x, GLfloat y, GLfloat z)
{
m_position.x = x;
m_position.y = y;
m_position.z = z;
}