【问题标题】:rotating camera in OpenGL using Glut libraries and gluLookAt使用 Glut 库和 gluLookAt 在 OpenGL 中旋转相机
【发布时间】:2014-12-15 16:07:32
【问题描述】:

我正在尝试在 OpenGL 中实现一个能够绘制 Lorenz 系统的软件。我以静态方式实现了我的目的:系统只绘制一次,仅此而已。现在我想在系统周围移动我的相机并展示系统本身的 3D 特性。我注意到我无法更新绘制的图像,因为如果我更新系统的点,它们会在每次更新中不断变化(洛伦兹系统是数学方程的结果,因此我有很大的浮点数作为结果)。然后我意识到我必须只画一次系统,然后以某种方式围绕它移动相机。不幸的是我不知道该怎么做。为了我的目的,我在更改 gluLookAt 调用时尤其遇到问题。假设我想根据键盘给出的输入移动相机。你能帮帮我吗?在这里你可以看看我的简单代码。

初始化方法:

void myinit() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor4f(1.0f, 0.0f, 0.0f, 0.09f);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_POINT_SMOOTH);
glPointSize(1.0f);

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  // Really Nice Perspective Calculations

glViewport(0, 0, 400, 400); //glViewport(0, 0, width_of_window_rendering_area, height_of_window_rendering area);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,  (GLfloat)400/400, 0.1, 100); //Sets the frustum to perspective mode, sets up the way in which objects

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

画法

void mydisplay() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //if perspective
glLoadIdentity();
gluLookAt(0.0, 0.0, 100.0,  //position
          0.0, 0.0, 0.0,  //where we are looking
          0.0, 1.0, 0.0); //up vector

glBegin(GL_POINTS);
for (int i = 0; i < iterations; i++) {
    if(i == 200000){
        glColor4f(1.0f, 0.0f, 0.0f, 0.09f);
    }
    if(i == 400000){
        glColor4f(1.0f, 0.0f, 1.0f, 0.09f);
    }
    if(i == 600000){
        glColor4f(0.0f, 0.0f, 1.0f, 0.09f);
    }
    if(i == 800000){
        glColor4f(0.0f, 1.0f, 1.0f, 0.09f);
    }

    // compute a new point using the strange attractor equations
    float xnew=x + h*(s*(y - x));
    float ynew=y + h*(x*(p - z) - y);
    float znew=z + h*(x*y - b*z);

    x = xnew;
    y = ynew;
    z = znew;

    glVertex3f(x, y, z);
}
glEnd();

glutSwapBuffers();
}

主要

int main (int argc, char **argv){

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

glutInitWindowSize(400, 400);
glutCreateWindow("Strange Attractors in C++ and OpenGL Tutorial");

glutDisplayFunc(mydisplay);
glutKeyboardFunc(mykey);

myinit();
glutMainLoop();

while(esc != true){
    glutDisplayFunc(mydisplay);
}
return 0;
}

这是结果:

【问题讨论】:

  • 将结果存储在缓冲区中并使用不同的矩阵多次绘制该缓冲区
  • @ratchetfreak 谢谢!这已经是我可以使用的非常有用的技巧了。我编辑了这个问题,因为我正在寻找有关如何修改 gluLookAt 调用的更深入的答案。再次感谢!
  • 我不知道为什么人们在没有解释原因的情况下将问题降级。我正在努力寻找解决方案并寻求帮助。
  • 由于格式问题和缺少MCVE,我投了反对票。
  • 虽然使用现代结构是最好的,但您可以通过将大的 for 循环分成四个其他循环并在每个循环之前调用 glColor 来节省 iterations-4glColor 的调用.除了循环内的所有比较和函数调用开销之外,它还可以让 OpenGL 驱动程序更有效地工作。

标签: opengl glut glulookat


【解决方案1】:

使用计时器回调来增加角度并发布重绘:

#include <GL/glut.h>
#include <vector>

struct Vertex
{
    float x, y, z, w;
    float r, g, b, a;
};
std::vector< Vertex > verts;

void fillVerts()
{
    // calculate vertices
    // http://paulbourke.net/fractals/lorenz/
    double h = 0.01;
    double a = 10.0;
    double b = 28.0;
    double c = 8.0 / 3.0;

    Vertex cur;
    cur.a = 0.09f;

    double x0 = 0.1;
    double y0 = 0;
    double z0 = 0;
    for( unsigned int i = 0; i < 100000; i++ ) 
    {
        if(i == 20000)
        {
            cur.r = 1.0f;
            cur.g = 0.0f;
            cur.b = 0.0f;
        }
        if(i == 40000)
        {
            cur.r = 1.0f;
            cur.g = 0.0f;
            cur.b = 1.0f;
        }
        if(i == 60000)
        {
            cur.r = 0.0f;
            cur.g = 0.0f;
            cur.b = 1.0f;
        }
        if(i == 80000)
        {
            cur.r = 0.0f;
            cur.g = 1.0f;
            cur.b = 1.0f;
        }

        const double x1 = x0 + h * a * (y0 - x0);
        const double y1 = y0 + h * (x0 * (b - z0) - y0);
        const double z1 = z0 + h * (x0 * y0 - c * z0);
        x0 = x1;
        y0 = y1;
        z0 = z1;

        if( i > 100 )
        {
            cur.x = x0;
            cur.y = y0;
            cur.z = z0;
            verts.push_back( cur );
        }
    }
}

float angle = 0;
void timer( int extra )
{
    // spin
    angle += 0.5;

    glutPostRedisplay();
    glutTimerFunc( 16, timer, 0 );
}

void display(void)
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    const double w = glutGet( GLUT_WINDOW_WIDTH );
    const double h = glutGet( GLUT_WINDOW_HEIGHT );
    gluPerspective( 60.0, w / h, 1.0, 10000.0 );

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt( 70, 70, 70, 0, 0, 0, 0, 0, 1 );

    glRotatef( angle, 0, 0, 1 );

    // draw curve
    glEnableClientState( GL_VERTEX_ARRAY );
    glEnableClientState( GL_COLOR_ARRAY );
    glVertexPointer( 3, GL_FLOAT, sizeof( Vertex ), &verts[0].x );
    glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].r );
    glDrawArrays( GL_LINE_STRIP, 0, verts.size() );
    glDisableClientState( GL_VERTEX_ARRAY );
    glDisableClientState( GL_COLOR_ARRAY );

    glutSwapBuffers();
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
    glutInitWindowSize( 800,600 );
    glutCreateWindow( "Attractor" );

    glutDisplayFunc( display );
    glutTimerFunc( 0, timer, 0 );

    fillVerts();

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    glEnable( GL_POINT_SMOOTH );
    glPointSize(1.0f);

    glutMainLoop();
    return 0;
}

提前而不是在显示回调中计算点位置/颜色也是一个好主意。

【讨论】:

  • 这个真的很好!!非常感谢!但我只有几个问题:1)我不明白你是如何决定那个 gluLookAt 调用的论点的。您是如何发现 70、70、70 是相机的好位置?此外,我尝试对它们进行一些不同的调整,只是为了弄清楚会发生什么变化。例如,如果我将相机放置在 0,0,200,我应该仍然可以看到系统(根据我的诚实意见),但我看不到,为什么? 2) 不是使用计时器,而是 glut 是否允许我使用键盘输入来控制角度?
  • 对于#2,请查看 glutKeyboardFunc()glutSpecialFunc()
  • 对于#1,如果您检查gluLookAt() docs,您会注意到它显示The UP vector must not be parallel to the line of sight from the eye point to the reference point. 如果您希望相机位于原点正上方向下看它,您必须选择一个up 与视图方向垂直的向量,例如 (0, 1, 0) 可以工作。
  • 至于我选择(70, 70, 70) 的原因,它使相机远离所有三个轴并与所有三个轴成一定角度。它还会将您置于以原点为中心的对象之外。
  • 我明白了,这就是你使用 0,0,1 作为向上向量的原因!事实上,如果我把相机放在 0,0,100 并且作为向上向量 0,1,0 它可以工作!不幸的是,我只能用简单的“谢谢”来表达我的感激之情..真的..非常感谢..
【解决方案2】:

我认为您可能会发现,通常使用 glut 函数会变得太慢而无法制作有用的动画。

我用 1200 X 800 X 1200 像素的分辨率做了类似的事情,我开始使用与您正在使用的类似的 openGL 函数。一次将数据传递给 gpu 非常慢。

现在我首先计算图像,然后为图像设置动画,我使用 glsl 着色器对 gpu 进行编程。

我将大型数组(如顶点数组和颜色纹理)传递给 gpu 一次,然后我只需要在每次重绘时传递少量数据(如更新的模型矩阵和一些制服)。重绘是在由计时器调用的方法中完成的(可能是 30-60 次/秒)。

相机停留在一个位置;对象旋转(更新的模型矩阵)。

因为大部分数据在一次(快速)操作中传输到 gpu,并且由于大量计算从 cpu 卸载到 gpu 管道,所以这是一个非常有效的过程。

这方面的学习曲线可能比你想投入的时间要长,但如果你愿意的话,红皮书和橙皮书是不错的起点。它们有点过时了,但仍然很好。

红皮书(OpenGL 编程指南,第 8 版)和橙皮书(OpenGL® 着色语言,第二版)均可免费下载。只是谷歌他们;它们很容易找到。

【讨论】:

  • 也许您的意思是说“OpenGL 固定函数例程”,而您说的是“过剩函数”?正如您正确讨论的那样,OP 使用了很多 glColorglVertex 例程。使用的 GLUT 函数的数量很少,相比之下,在性能上可以忽略不计。
  • @radical7 你说得对,我说的是 OpenGL 固定函数。我的错。然而,我的观点仍然是一样的,因为要绘制大量的点,设置着色器并使用 glDrawArrays(GL_POINTS, 0, numPOINTS) 命令之类的东西会变得更加高效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
相关资源
最近更新 更多