计算gluLookAt,glOrtho和glFrustum

时间:2014-03-28 14:04:02

标签: c++ opengl math 3d

我正在进行绘制线框GLUT标准对象的赋值。这看起来很简单,但我们被告知我们不能使用gluAtLook(),glOrtho(),glFrustrum,但我们必须使用glTranslate(),glScale()和glRotate。如何在不使用glMatrixMode(GL_PROJECTION)中的这些函数的情况下投影对象?

这是我到目前为止所做的:

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <math.h> // for sqrt()
#include <glut.h>


void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glLoadIdentity();             /* clear the matrix */
    /* viewing transformation  */
    glTranslatef(0.0, 0.0, -5.0);
    glScalef(1.0, 2.0, 1.0);      /* modeling transformation */
    glutWireCube(1.0);
    glFlush();

}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
    //glTranslatef(0.0, 0.0, -5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:7)

  

我们被告知我们不能使用gluAtLook(),glOrtho(),glFrustrum但我们必须使用glTranslate(),glScale()和glRotate

gluLookAt设置世界以查看空间变换,glOrtho查看正投影空间变换,glFrustum查看透视投影空间变换。当你说你的导师不允许使用它时,它显然意味着首先要了解这些功能是如何工作的。

互联网上有很多资源可以教你这么做。 Here's one由着名的加州大学伯克利分校教授Ravi Ramamoorthi博士撰写。 SongHo good articles可以帮助你做同样的事情。


我可以在2D中演示一个简单的案例。假设我们有一个用对象定义的世界(为简单起见,我们采用P点);我们希望相机处于(3,3),其X和Y轴指向与世界X和Y轴相反的方向。为简单起见,我们假设两个帧具有相同的缩放因子,即X和Y方向上的1个单位测量两个系统的相同距离(幅度)。因此,两个帧的区别仅在于方向和原点位置(W 0 ,V 0 是表示它们的符号)。

我们需要导出M world-&gt; view ,即将世界空间中的点映射到视图空间的矩阵。这就是现在已弃用的gluLookAt函数计算并乘以GL_MODELVIEW矩阵堆栈。该矩阵将用于从相机的角度来看世界。

We know that M world-&gt; view = T view-&gt; world 。将帧A的点映射到帧B的矩阵也将是将B的帧变换为A的帧的矩阵。推导就像这样

Step by step transformation of view's frame into world's frame

世界上的点P有(1,2)= P w 作为坐标,我们有效地找到一个矩阵,当乘以P <​​sub> w 时,它将给出P v 即视图框中的相同点坐标。该点被写为3D点,因为2D点的均匀扩展将是3D点;齐次坐标为1,因为它是一个点;如果它是一个矢量,那就是0。

第一步是轮换;旋转视图的框架-180°(右旋系统+ ve旋转逆时针);现在,两个帧的轴都沿着相同的方向。我们要解决原点差异,这是通过翻译完成的,这是第2步。将两者相乘将得到所需的矩阵。请注意,每个步骤都会通过后乘将视图的帧更接近世界的帧。此外,每个转换都基于我们所在的当前本地帧,而不是基于起始全局(世界)帧。

同样的想法也可以扩展到3D,需要更多努力。在上面的推导中我只需要旋转矩阵,平移矩阵和矩阵乘法;没有gluLookat。我给你的链接应该有助于计算相同的3D。投影矩阵推导更复杂一些。但是,您仍然可以在不使用glOrtho的情况下实现结果;我上面给出的链接有最终矩阵的公式;您可以使用它来组合矩阵并将其乘以GL_PROJECTION矩阵堆栈。

注意:上面的推导假定了列向量,因此转换矩阵(如旋转)和乘法顺序基于此完成。如果您假设行向量约定,则转置所有矩阵并反转自从

以来的乘法顺序
  

(AB)^ T = B ^ T A ^ T

答案 1 :(得分:2)

您需要做的是计算您自己的投影矩阵和模型视图矩阵。之后,您可以在致电glLoadMatrix后立即使用glLoadIdentity加载它们。

答案 2 :(得分:1)

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <math.h> // for sqrt()
#include <glut.h>

static GLfloat Xvalue = 0.0f;
static GLfloat Yvalue = 0.0f;
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static GLfloat zRot = 0.0f;
static GLfloat xScale = 1.0f;
static GLfloat yScale = 1.0f;
static GLfloat zScale = 1.0f;

void init(void)
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glShadeModel(GL_FLAT);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 0.0);
glLoadIdentity(); //clear the matrix 
glTranslatef(Xvalue, Yvalue, -3.0); // viewing transformation 
glScalef(xScale, yScale, zScale); // modeling transformation
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
glutWireCube(1.0);
glFlush();
}

void reshape(int w, int h)
{
GLfloat identity[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 };

if (h == 0) // don't want a divide by zero
{
    h = 1;
}

glViewport(0, 0, (GLsizei)w, (GLsizei)h);

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(identity);
GLfloat fovy = 52.0f; // in degrees
GLfloat c = 1.0 / (GLfloat)tan(fovy / 4.0), a = (GLfloat)w / (GLfloat)h, n = 1.0f, f = 1000.0f;
GLfloat projection[16] = { c / a, 0.0, 0.0, 0.0,
    0.0, c, 0.0, 0.0,
    0.0, 0.0, -(f + n) / (f - n), -1.0,
    0.0, 0.0, -2.0*f*n / (f - n), 0.0 };
glMultMatrixf(projection);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void keyInput(unsigned char key, int x, int y)
{ // Keyboard input processing routine.
switch (key)
{
case 'b': // move left
    Xvalue -= 0.1;
    glutPostRedisplay();
    break;
case 'B': // move right
    Xvalue += 0.1;
    glutPostRedisplay();
    break;
case 'c': // move down
    Yvalue -= 0.1;
    glutPostRedisplay();
    break;
case 'C': // move up
    Yvalue += 0.1;
    glutPostRedisplay();
    break;
case 'e': // scale down
    zScale -= 0.1;
    xScale -= 0.1;
    yScale -= 0.1;
    glutPostRedisplay();
    break;
case 'E': // scale up
    zScale += 0.1;
    xScale += 0.1;
    yScale += 0.1;
    glutPostRedisplay();
    break;
case 'f': // rotate x axis CW
    xRot -= 5.0f;
    glutPostRedisplay();
    break;
case 'F': // rotate x axis CCW
    xRot += 5.0f;
    glutPostRedisplay();
    break;
case 'g': // rotate y axis CW
    yRot -= 5.0f;
    glutPostRedisplay();
    break;
case 'G': // rotate y axis CCW
    yRot += 5.0f;
    glutPostRedisplay();
    break;
case 'h': // rotate z axis CW
    zRot -= 5.0f;
    glutPostRedisplay();
    break;
case 'H': // rotate z axis CCW
    zRot += 5.0f;
    glutPostRedisplay();
    break;
}
}


int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyInput);
glutMainLoop();
return 0;
}