【发布时间】: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值。例如,near20 和far10000 会做得很好,而near0.00001 和far100 会给出非常糟糕的结果。查看这篇文章了解更多详情sjbaker.org/steve/omniv/love_your_z_buffer.html