gluLookAt 似乎产生了错误的视图,OpenGL

Posted

技术标签:

【中文标题】gluLookAt 似乎产生了错误的视图,OpenGL【英文标题】:gluLookAt seems to be producting wrong view, OpenGL 【发布时间】:2016-02-21 06:00:32 【问题描述】:

我正在开发一个 nbody 模拟器,我想用 OpenGL 显示它。我想一直看着质心参考系。我有以下代码。我计算 COM 并将 gluLookAt 函数中的中心坐标设置为质心。然后我从 z 坐标中减去“缩放”以获得眼睛位置。从逻辑上讲,这应该确保我始终关注质心的任何值。唯一的问题是我用红点标记了屏幕上的质心应该在哪里,并且它正在移动。如果我总是从同一个相对位置看它,它不应该永远不动吗?这是我的代码。专注于显示功能,因为我认为这就是错误所在。我在另一个项目中有类似的代码,但我真的找不到任何差异。

#include "Universe.cuh"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "timer.hpp"
#include <GL/glut.h>

Universe u;
float* vbuf;
double angle = 0.0, zoom = 1000;
void display()
   
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);

    glLoadIdentity();

    float3 c = u.getCenterOfMass();
    gluLookAt(c.x, c.y, c.z - zoom, c.x, c.y, c.z, 0, 1, 0);
    glScalef(0.1, 0.1, 0.1);
    glRotated(angle, 1, 0, 0);

    glColor4f(1, 1, 1, 0.25);

    glBegin(GL_POINTS);
    
        glColor3f(1.0, 0.0, 0.0);
        glVertex3d(c.x, c.y, c.z);
    
    glEnd();
    glutSwapBuffers();


void reshape(int w, int h)

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, (double)w / (double)h, 1.0, zoom * 1e9);
    glMatrixMode(GL_MODELVIEW);


void copy_to_vbuf()

    for(int i = 0; i < u.size(); i++)
    
        vbuf[3 * i + 0] = u.getObjects()[i].p.x;
        vbuf[3 * i + 1] = u.getObjects()[i].p.y;
        vbuf[3 * i + 2] = u.getObjects()[i].p.z;
    


void keyboard(unsigned char c, int x, int y)

    if(c == 'w')
        angle += 1;
    else if(c == 's')
        angle -= 1;
    else if(c == '=')
        zoom /= 1.2;
    else if(c == '-')
        zoom *= 1.2;
    glutPostRedisplay();


void idle()

    u.timeStep();
    copy_to_vbuf();
    glutPostRedisplay();


int main(int argc, char** argv)

    cudaSetDevice(0);
    srand(time(0));

    u.getConfiguration().max_velocity = 10;
    u.getConfiguration().softening_factor = 0.01;
    u.getConfiguration().threshold_angle = 35;
    u.getConfiguration().time_step = 0.1;

    const int N = 5;
    vbuf = new float[3 * N];
    for(int i = 0; i < N; i++)
    
        Object o;
        o.m = rand() % 100 + 1;
        o.p.x = 500.0 * rand() / RAND_MAX - 250.0;
        o.p.y = 500.0 * rand() / RAND_MAX - 250.0;
        o.p.z = 500.0 * rand() / RAND_MAX - 250.0;
        u.addObject(o);
    

    copy_to_vbuf();

    glutInit(&argc, argv);
    glutInitDisplayMode(GL_DOUBLE);

    glutInitWindowSize(1000, 1000);
    glutCreateWindow("N-Body");

    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    glutKeyboardFunc(keyboard);

    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glPointSize(1.0);


    glutMainLoop();
    return 0;

【问题讨论】:

glRotated(angle, 1, 0, 0); 你不是从gluLookAt() 设置的方向旋转相机吗?附带说明一下,您的far 太大,而您的near 太小。 我不太想要一个远剪裁平面。我从来不明白远剪裁平面的点或为什么有必要。 GPU 的 z-buffer 有限这一事实实际上至关重要。当您设置nearfar 时,您将定义深度值的分布范围。可以将其想象为您可以将X 标签分布到任意长度的标尺中。尺子越大,这些标签的精度就越低,但如果它非常小,您的标签将非常接近,并且可以使用尺子准确地测量微米。标签的数量类似于 z 缓冲区的大小。唯一的区别是 z-buffer 是非线性的(有点对数。查一下)。 好的。所以我分离出来的只是近场为 1,远场为 100,我可以相应地缩小宇宙。 是的,但请记住,它不是线性的。 near 在这方面发挥了巨大的作用。如果它足够大,那么您可以拥有更大的far 值。例如,near 20 和 far 10000 会做得很好,而 near 0.00001 和 far 100 会给出非常糟糕的结果。查看这篇文章了解更多详情sjbaker.org/steve/omniv/love_your_z_buffer.html 【参考方案1】:

关于以下两点:

glScalef(0.1, 0.1, 0.1);
glRotated(angle, 1, 0, 0);

    由于您的轴未以“COM”为中心,因此当您应用旋转时,COM 点不会停留在原位,并且会在逻辑上在屏幕上移动。

    AFIK 的正常顺序是缩放、旋转、平移以进行转换。这将应用旋转然后缩放。

编辑:

对此进行扩展:目前,您可以任意点旋转它,缩放它,然后将注意力集中在它曾经所在的点上。如果您想围绕自身旋转模型(例如标记“COM”的点),它需要以 (0,0,0) 为中心。

【讨论】:

以上是关于gluLookAt 似乎产生了错误的视图,OpenGL的主要内容,如果未能解决你的问题,请参考以下文章

带有锥体的 gluLookAt 未显示预期结果

在按键时更改 gluLookAt。上、右、下、左

gluLookAt() 的问题 - 旋转

OpenGL的视图变换模型变换投影变换视口变换

gluLookAt 的相机外在矩阵

gluLookAt 问题 - 如何使曲线运动?