如何选择一个特定的视口转换,同时保持之前的转换在OpenGL

How to select a specific viewport to transform, while keeping the previous transformations in OpenGL

本文关键字:转换 OpenGL 视口 选择 一个 何选择      更新时间:2023-10-16

这是我应该做的作业,我目前关注的指导方针是:

用户可以通过点击"活动"视窗来选择它(你应该改变视窗的颜色)边框(当viewport被选中时)。任何变换(旋转、平移等)都应该是 用户应该能够使用WASD键和/或箭头在选定的视口中导航场景键(用于正射影投影)。鼠标控制(就像在FPS游戏中)和方向键和/或箭头对于透视投影。应该只允许在活动视窗中进行导航。的其他视口应保持静态。

我已经有了可以以fps方式转换视角视图的代码,并硬编码了一些前视图的相机转换,但我似乎不知道如何制作一个函数或其他东西来区分视图,因为如果我可以的话,我将能够插入转换到那个的代码。我目前正在使用mousecickcallbackfunction来检测鼠标的位置,但主要问题是它在我的displaycallbackfunction之后运行,这是视图创建和运行的地方,因此意味着我必须找到一种方法来使它能够从显示功能转换,而不是鼠标检测它。

我的一些代码是这样的:
void DisplayCallbackFunction(void)
{
/* clear the screen */
glViewport(0, 0, windowWidth, windowHeight);
glClearColor(0.2f, 0.2f, 0.2f, 0.8f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//create viewport
setViewport(1);
//Perspective
//glFrustum(-1.0f,1.0f, -1.0f, 1.0f, 1.0f, 100);
gluPerspective(45.0f,1.0f, 0.1f, 100.0f);
//Orthographic
//glOrtho(-1.0f, 1.0f, -1.0, 1.0, 1.0f, 100.0f);
//gluOrtho2D(1.0f, 1.0f, 1.0f, 1.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*
if (x < windowWidth / 2 && y < windowHeight / 2) {
    viewport = 3;
    std::cout << "Viewport =" << viewport << std::endl;
}
if (x > windowWidth / 2 && y < windowHeight / 2) {
    viewport = 4;
    std::cout << "Viewport =" << viewport << std::endl;
}
if (x > windowWidth / 2 && y > windowHeight / 2) {
    viewport = 2;
    std::cout << "Viewport =" << viewport << std::endl;
}
if (x < windowWidth / 2 && y > windowHeight / 2) {
    viewport = 1;
    std::cout << "Viewport =" << viewport << std::endl;
}
break;*/
    gluLookAt(
        cameraPosition.x, cameraPosition.y, cameraPosition.z,// camera position
        cameraPosition.x + forwardVector.x,
        cameraPosition.y + forwardVector.y,
        cameraPosition.z + forwardVector.z,// what the camera is looking at 
        0.0f, 1.0f, 0.0f);//what the camera thinks is up

/* This is where we draw things */
//glColor3f(0.5f, 0.8f, 0.1f); //RGB  or 4f-> RGBA
//drawObjects();

//cube code is here


//second viewport
setViewport(2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

gluLookAt(
    rz, rz2, 6.0f,// camera position
    rz, rz2, 0.0f,// what the camera is looking at 
    0.0f, 1.0f, 0.0f);//what the camera thinks is up

//other cube
//third viewport
setViewport(3);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
    -6.0f, 0.0f, 0.0f,// camera position
    0.0f, 0.0f, 0.0f,// what the camera is looking at 
    0.0f, 1.0f, 0.0f);//what the camera thinks is up
//3rd cube
//fourth viewport
setViewport(4);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
    0.0f, 6.0f, 0.0f,// camera position
    0.0f, 0.0f, 0.0f,// what the camera is looking at 
    0.0f, 0.0f, 1.0f);//what the camera thinks is up
//fourth cube
//HUD or Overlay viewport
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_QUADS);
glVertex3f(-0.02, -1.0, 0.0);// bottom left
glVertex3f(0.02, -1.0, 0.0); //bottom right
glVertex3f(0.02, 1.0, 0.0); // top right
glVertex3f(-0.02, 1.0, 0.0); // top left
glBegin(GL_QUADS);
glVertex3f(-1.0, -0.02, 0.0);// bottom left
glVertex3f(1.0, -0.02, 0.0); //bottom right
glVertex3f(1.0, 0.02, 0.0); // top right
glVertex3f(-1.0, 0.02, 0.0); // top left
glBegin(GL_QUADS);
glVertex3f(0.0, 0.0, 0.0);// bottom left
glVertex3f(0.02, 0.0, 0.0); //bottom right
glVertex3f(0.02, 1.0, 0.0); // top right
glVertex3f(0.0, 1.0, 0.0); // top left
glEnd();
/* Swap Buffers to Make it show up on screen */
glutSwapBuffers();
}
void KeyboardCallbackFunction(unsigned char key, int x, int y)
{
std::cout << "Key Down:" << (int)key << std::endl;

switch (key)
{
case 32: // the space bar
    break;
case 27: // the escape key
//case 'q': // the 'q' key
    exit(0);
    break;
case 'W':
case 'w':
    cameraPosition += (forwardVector * movementScalar);
    break;
case 'S':
case 's':
    cameraPosition -= (forwardVector * movementScalar);
    break;
case 'A':
case 'a':
    rightVector = glm::cross(forwardVector, glm::vec3(0.0f, 1.0f, 0.0f));
    rightVector = glm::normalize(rightVector);
    cameraPosition -= (rightVector * movementScalar);
        break;
case 'D':
case 'd':
    rightVector = glm::cross(forwardVector, glm::vec3(0.0f, 1.0f, 0.0f));
    rightVector = glm::normalize(rightVector);
    cameraPosition += (rightVector * movementScalar);
    break;


}
}


void SpecialInput(int key, int x, int y)
{
switch (key)
{

case GLUT_KEY_LEFT:
    rz += 1.0;
    break;
case GLUT_KEY_RIGHT:
    rz -= 1.0f;
    break;
case GLUT_KEY_UP:
    rz2 -= 1.0f;
    break;
case GLUT_KEY_DOWN:
    rz2 += 1.0f;
    break;
}
glutPostRedisplay();
}
void MouseClickCallbackFunction(int button, int state, int x, int y)
{
// Handle mouse clicks
switch (button) {
    if (state == GLUT_DOWN) {
case GLUT_RIGHT_BUTTON:
    std::cout << "Mouse X: " << x << "Mouse Y: " << y << std::endl;
    break;
case GLUT_LEFT_BUTTON:
    std::cout << "Mouse X: " << x << "Mouse Y: " << y << std::endl;
    if (x < windowWidth / 2 && y < windowHeight / 2) {
        viewport = 3;
        std::cout << "Viewport =" << viewport<<std::endl;
    }
    if (x > windowWidth / 2 && y < windowHeight / 2) {
        viewport = 4;
        std::cout << "Viewport ="<< viewport << std::endl;
    }
    if (x > windowWidth / 2 && y > windowHeight / 2) {
        viewport = 2;
        std::cout << "Viewport ="<< viewport << std::endl;
    }
    if (x < windowWidth / 2 && y > windowHeight / 2) {
        viewport = 1;
        std::cout << "Viewport ="<< viewport << std::endl;
    }
    break;
    }


}
}

所以我可能完蛋了,因为这应该是午夜的截止日期,老师没有告诉我们足够的信息来正确完成它。如果有人能告诉我如何选择一个特定的视口进行左键转换,我将不胜感激,然后通过箭头键转换相机。

实际上你知道你需要做的一切。OpenGL不会为你保存状态。相反,你负责记住状态,并将其传输到OpenGL的每个视图你渲染。所以定义:

struct ViewportState {
    int vp[2], vs[2]; // position annd size of the viewport on screen
    vec3 pos; // camera position in the world
    vec3 rot; // euler angles of camera rotation
};
ViewportState viewports[number_of_viewports];
int active_viewport = 0;

写一个函数来计算viewport的视图矩阵:

mat4 ViewMatrix(const ViewportState &vp)
{
    // build a view matrix m based on vp.pos and vp.rot
    return m;
}

现在在渲染时使用这些:

void DisplayViewport(int i)
{
    const ViewportState &vp = viewports[i];
    glViewport(vp.vp[0], vp.vp[1], vp.vs[0], vp.vs[1]);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    if(i == active_vieport)
    {
        // draw a highlighted border around viewport
    }
    // load ViewMatrix(vp)
    // draw the actual 3d content of the viewport
}
void DisplayCallbackFunction(void)
{
    // ...
    for(int i = 0; i < nviewports; ++i)
        DisplayViewport(i);
    //...
}

键盘和鼠标将修改活动视窗:

void KeyboardCallbackFunction(unsigned char key, int x, int y)
{
    // ...
    case 'w':
        viewports[active_viewport].pos -= (ViewMatrix(viewports[active_viewport]) * vec4(0,0,movementScalar,1)).xyz;
        break;
    case 'a':
        viewports[active_viewport].pos -= (ViewMatrix(viewports[active_viewport]) * vec4(movementScalar,0,0,1)).xyz;
        break;
    // ...
}

激活不同的视口:

void MouseClickCallbackFunction(int button, int state, int x, int y)
{
    // iterate over viewports, find the one within x/y coordinates and set active_viewport accordingly
}

你有两个选择。

  1. 渲染你的视口场景到一个由纹理支持的帧缓冲区。然后将纹理渲染到屏幕
  2. 使用矩阵将场景从视口空间转换为屏幕空间。为了防止自己画出盒子,使用剪刀测试剪切到视窗