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 有限这一事实实际上至关重要。当您设置near
和far
时,您将定义深度值的分布范围。可以将其想象为您可以将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的主要内容,如果未能解决你的问题,请参考以下文章