簡體   English   中英

轉動相機后,形狀傾斜 OpenGL

[英]After turning the camera, the shapes are tilted OpenGL

在 Y 軸和 X 軸上的相機旋轉以及隨后的移動之后,是一個奇怪的相機沿着 Z 軸旋轉。
例如,這里是正常狀態一切都好

但我在舞台上隨意移動,全部扭曲曲率

我不知道該怎么做以及如何解決問題,希望對您有所幫助。
我看到了這個問題,它對我沒有幫助,因為我什至不使用 glm,也不要標記為重復。

代碼:

#include <iostream>
#include <chrono>
#include <GL/glut.h>
#include "Camera.h"

using namespace std;

constexpr auto FPS_RATE = 120;
int windowHeight = 600, windowWidth = 600, windowDepth = 600;
float angle = 0, speedRatio = 0.25;
struct MyPoint3f
{
    float x;
    float y;
    float z;
};
MyPoint3f lastMousePos = { };
bool mouseButtonWasPressed = false;
float mouseSensitivity = 0.1;
float camMoveSpeed = 3;
float camPitchAngle = 0, camYawAngle = 0;
Camera cam;

void init();
void displayFunction();
void idleFunction();
void reshapeFunction(int, int);
void keyboardFunction(unsigned char, int, int);
void specialKeysFunction(int, int, int);
void mouseFunc(int, int, int, int);
void motionFunction(int, int);
double getTime();

double getTime()
{
    using Duration = std::chrono::duration<double>;
    return std::chrono::duration_cast<Duration>(
        std::chrono::high_resolution_clock::now().time_since_epoch()
        ).count();
}

const double frame_delay = 1.0 / FPS_RATE;
double last_render = 0;

void init()
{
    glutDisplayFunc(displayFunction);
    glutIdleFunc(idleFunction);
    glutReshapeFunc(reshapeFunction);
    glutKeyboardFunc(keyboardFunction);
    glutMouseFunc(mouseFunc);
    glutMotionFunc(motionFunction);
    glViewport(0, 0, windowWidth, windowHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, -windowDepth / 2, windowDepth / 2);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    cam.setShape(45, (double)windowWidth / windowHeight, 0.1, 1000);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    cam.set(Point3(0, 0, 350), Point3(0, 0, 349), Vector3(0, 1, 0));
}

void displayFunction()
{
    angle += speedRatio;
    if (angle >= 360 || angle <= -360) angle = 0;
    if (camPitchAngle <= -360) camPitchAngle = 0;
    if (camPitchAngle >= 360) camPitchAngle = 0;
    if (camYawAngle <= -360) camYawAngle = 0;
    if (camYawAngle >= 360) camYawAngle = 0;
    cout << camPitchAngle << " " << camYawAngle << endl;
    cam.pitch(-(camPitchAngle *= mouseSensitivity));
    cam.yaw(-(camYawAngle *= mouseSensitivity));
    camPitchAngle = 0; camYawAngle = 0;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);

    glPushMatrix();

    glRotatef(angle, 1, 0, 0);
    glRotatef(angle, 0, 1, 0);

    glColor3f(0, 1, 0);
    glutWireCube(150.0);

    glBegin(GL_LINES);
    glColor3f(1, 0, 0);
    for (int i = 0; i <= 75; i += 5)
    {
        glVertex3i(i, 0, 0);
        glVertex3i(-i, 0, 0);
        glVertex3i(0, i, 0);
        glVertex3i(0, -i, 0);
        glVertex3i(0, 0, i);
        glVertex3i(0, 0, -i);
    }
    glEnd();
    glPopMatrix();

    //RSHIFT and CTRL
    if (GetAsyncKeyState(VK_LSHIFT))
    {
        cam.slide(0, 1.0 * camMoveSpeed, 0);
    }
    if (GetAsyncKeyState(VK_LCONTROL))
    {
        cam.slide(0, -1.0 * camMoveSpeed, 0);
    }

    glutSwapBuffers();
}

void idleFunction()
{
    const double current_time = getTime();
    if ((current_time - last_render) > frame_delay)
    {
        last_render = current_time;
        glutPostRedisplay();
    }
}

void reshapeFunction(int w, int h)
{

}

void keyboardFunction(unsigned char key, int w, int h)
{
    switch (key)
    {
    case '+': case '=':
        speedRatio += 0.125;
        break;
    case '-': case '_':
        speedRatio -= 0.125;
        break;
    case 'A': case 'a':
        cam.slide(-1.0 * camMoveSpeed, 0, 0);
        break;
    case 'D': case 'd':
        cam.slide(1.0 * camMoveSpeed, 0, 0);
        break;
    case 'W': case 'w':
        cam.slide(0, 0, -1.0 * camMoveSpeed);
        break;
    case 'S': case 's':
        cam.slide(0, 0, 1.0 * camMoveSpeed);
        break;
    case 'Z': case 'z':
        cam.yaw(-1);
        break;
    case 'X': case 'x':
        cam.yaw(1);
        break;
    case 27:
        angle = 0;
        speedRatio = 0;
        cam.set(Point3(0, 0, 350), Point3(0, 0, 349), Vector3(0, 1, 0));
        break;
    default:
        cout << key << endl;
        break;
    }
}

void specialKeysFunction(int key, int x, int y)
{
    cout << key << endl;
}

void mouseFunc(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        mouseButtonWasPressed = true;
        lastMousePos.x = x;
        lastMousePos.y = y;
    }
}

void motionFunction(int mousePosX, int mousePosY)
{
    if (mousePosX >= 0 && mousePosX < windowWidth && mousePosY >= 0 && mousePosY < windowHeight)
    {
        if (mouseButtonWasPressed)
        {
            camPitchAngle += -mousePosY + lastMousePos.y;
            camYawAngle += mousePosX - lastMousePos.x;
            lastMousePos.x = mousePosX;
            lastMousePos.y = mousePosY;
        }
    }
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(windowWidth, windowHeight);
    glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2, (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);
    glutCreateWindow("Window");
    init();
    glutMainLoop();
    return 0;
}

相機.h 相機.cpp

當你做

glRotatef(angle, 1, 0, 0); glRotatef(angle, 0, 1, 0);

然后模型繞y軸旋轉,然后旋轉的模型繞x軸旋轉,因為glRotatef設置了一個旋轉矩陣並將其與當前矩陣相乘。
因為模型在繞 x 軸旋轉之前先繞 y 軸旋轉,所以(視圖空間)y 軸保持在視圖空間的 yz 平面。

如果要將 x 軸保持在視圖空間的 xz 平面中,則必須首先圍繞 x 軸進行旋轉:

glRotatef(angle, 0, 1, 0);
glRotatef(angle, 1, 0, 0);


當您將pich()yaw()應用於相機對象時,也會出現同樣的問題。 如果您切換它(首先yaw()然后pitch() ),那么這將無法解決問題,因為每次鼠標移動( pich()yaw()pich()yaw() , pich() , yaw() ...)。 所以在一個pitch()之后總是有一個yaw() pitch()並且模型會傾斜。

要解決這個問題,您必須總結camPitchAnglecamYawAngle 考慮鼠標強度:

void motionFunction(int mousePosX, int mousePosY)
{
    if (mousePosX >= 0 && mousePosX < windowWidth && mousePosY >= 0 && mousePosY < windowHeight)
    {
        if (mouseButtonWasPressed)
        {
            camPitchAngle += (-mousePosY + lastMousePos.y) * mouseSensitivity;
            camYawAngle   += (mousePosX - lastMousePos.x) * mouseSensitivity;
            lastMousePos.x = mousePosX;
            lastMousePos.y = mousePosY;
        }
    }
}

復制displayFunction的相機對象( cam / curr_cam )並將camPitchAnglecamYawAngle到副本。 使用副本設置視圖和投影矩陣:

void displayFunction()
{
    // [...]

    // cam.pitch(-(camPitchAngle *= mouseSensitivity)); <--- delete
    // cam.yaw(-(camYawAngle *= mouseSensitivity));     <--- delete

    // [...]

    Camera curr_cam = cam;
    curr_cam.yaw( -camYawAngle );
    curr_cam.pitch( -camPitchAngle );

    // [...]

    if (GetAsyncKeyState(VK_LSHIFT))
    {
        curr_cam.slide(0, 1.0 * camMoveSpeed, 0);
    }
    if (GetAsyncKeyState(VK_LCONTROL))
    {
        curr_cam.slide(0, -1.0 * camMoveSpeed, 0);
    }

    // [...]   
}    

當然你必須分別設置camYawAngle = 0 camPitchAngle = 0; z , xESC被按下時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM