Aqui estão algumas dicas sobre a rotação da câmera (mouselook). Depois de implementar de forma ingênua uma classe de câmera do zero, descobri que precisava fazer alguns ajustes adicionais para obter um bom comportamento rotacional:
Redefina as coordenadas do mouse para o centro da tela em cada quadro, para que o mouse nunca fique preso nas bordas da tela
Mantenha o vetor "para cima" da câmera (desaprovar rolo) e recompute o vetor "para o lado"
Não permitir olhar para cima além do eixo vertical + y ou para baixo além do eixo -y (muito acima / abaixo)
Corrija a ordem das rotações (para cima / para baixo primeiro e depois para a esquerda / direita)
Renormalize os vetores "para cima", "mira" e "lateralmente" em cada quadro
Espero que você possa usar parte desse código para sua vantagem:
const int mouseDeltaX = mouseAxisX * (input.GetMouseX() - int(app.GetWidth()/2));
const int mouseDeltaY = -mouseAxisY * (input.GetMouseY() - int(app.GetHeight()/2)); // mouse y-offsets are upside-down!
// HACK: reset the cursor pos.:
app.SetCursorPosition(app.GetWidth()/2, app.GetHeight()/2);
float lookRightRads = mouseDeltaX * CAMERA_ANGULAR_SPEED_DEG * DEG_TO_RAD;
float lookUpRads = mouseDeltaY * CAMERA_ANGULAR_SPEED_DEG * DEG_TO_RAD;
// Limit the aim vector in such a way that the 'up' vector never drops below the horizon:
static const float zenithMinDeclination = DEG_TO_RAD * MIN_UPWARDS_TILT_DEG;
static const float zenithMaxDeclination = DEG_TO_RAD * (180.0f - MIN_UPWARDS_TILT_DEG);
const float currentDeclination = std::acosf(camera.aim_.y_); ///< declination from vertical y-axis
const float requestedDeclination = currentDeclination - lookUpRads;
// Clamp the up/down rotation to at most the min/max zenith:
if(requestedDeclination < zenithMinDeclination)
lookUpRads = currentDeclination - zenithMinDeclination;
else if(requestedDeclination > zenithMaxDeclination)
lookUpRads = currentDeclination - zenithMaxDeclination;
// Rotate both the "aim" vector and the "up" vector ccw by
// lookUpRads radians within their common plane -- which should
// also contain the y-axis: (i.e. no diagonal tilt allowed!)
camera.aim_.rotateAboutAxis(camera.right_, lookUpRads);
camera.up_.rotateAboutAxis(camera.right_, lookUpRads);
ASSERT_ORTHONORMAL(camera.aim_, camera.up_, camera.right_);
// Rotate both the "aim" and the "up" vector ccw about the vertical y-axis:
// (again, this keeps the y-axis in their common plane, and disallows diagonal tilt)
camera.aim_.rotateAboutAxis(Y_AXIS, -lookRightRads);
camera.up_.rotateAboutAxis(Y_AXIS, -lookRightRads);
camera.updateRightAxis();
Observe que:
mouseAxisX e mouseAxisY são definidos como +/- 1, dependendo se você deseja que o eixo x ou y seja invertido. Normalmente, os jogos oferecem essa opção pelo menos para o eixo vertical.
MIN_UPWARDS_TILT_DEG é definido como 1,0 graus (para que o espectador possa olhar de -89 graus para baixo a +89 graus para cima, o que parece bastante convincente como uma faixa vertical completa de 180 graus - os 2 graus ausentes nos extremos são desprezíveis) .
camera.aim_, camera.right_ e camera.up_ são, obviamente, vetores 3D, e o método rotateAboutAxis () você pode juntar na wikipedia e em qualquer número de fontes online. Y_AXIS é um vetor constante fixo (0,1,0).
ASSERT_ORTHONORMAL () é uma verificação de integridade apenas no modo de depuração, que nunca é compilada no modo otimizado / liberação.
Pedimos desculpas antecipadamente pelo código do estilo C ... então, novamente, aqui você está recebendo conselhos de um cara chamado Mediocritus! ; ^)