2016-02-21 4 views
1

Я работаю над симулятором nbody и хочу отобразить его с помощью OpenGL. Я хочу всегда смотреть в центр массовой системы отсчета. У меня есть следующий код. Я вычисляю COM, и я установил центральную координату в функции gluLookAt как центр масс. Затем я вычитаю «зум» из координаты z, чтобы получить положение глаз. По логике это должно гарантировать, что я всегда смотрю на то, какое значение имеет центр масс. Единственная проблема в том, что я отметил, где центр масс должен быть на экране с красной точкой, и он движется. Разве он не должен двигаться, если я всегда смотрю на него с той же относительной позиции? Вот мой код. Сосредоточьтесь на функции отображения, так как я предполагаю, что там будет ошибка. У меня был аналогичный код, работающий в другом проекте, и я не могу найти никаких различий.gluLookAt, похоже, работает неправильно, OpenGL

#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; 
} 
+0

'glRotated (angle, 1, 0, 0);' Вы не вращаете камеру там от ориентации, которую установил 'gluLookAt()'? На боковой ноте ваш 'far' слишком велик, а ваш' near' слишком мал. –

+0

Я вроде как не очень хочу, чтобы вы обрезали плоскость. Я никогда не понимал, что касается плоскости отсечения или почему это необходимо. – chasep255

+0

На самом деле имеет решающее значение тот факт, что графические процессоры имеют ограниченный z-буфер. Когда вы устанавливаете 'near' и' far', вы определяете диапазон, в который будут распределены значения глубины. Подумайте об этом, как будто у вас есть X-метки, которые вы можете распространять на линейку любой длины. Чем больше линейка, тем точнее она становится с этими ярлыками, но если ее очень мало, ваши ярлыки будут очень близки, и можно будет точно измерить микрометры с помощью линейки. Количество меток аналогично размеру вашего z-буфера. Единственное отличие состоит в том, что z-буфер нелинейный (вид логарифмический, посмотрите его). –

ответ

1

Две точки относительно:

glScalef(0.1, 0.1, 0.1); 
glRotated(angle, 1, 0, 0); 
  1. Поскольку ваша ось не по центру «COM», когда вы применяете вращение точки COM не будет оставаться на месте и логично будет двигаться вокруг экран.

  2. AFIK нормальный порядок - масштаб, поворот, перевод для преобразований. Это применит поворот, а затем масштаб.

EDIT:

Чтобы расширить, что: В настоящее время вы берете произвольную точку вращать, масштабировать его, а затем сосредоточиться на том месте, где он имел обыкновение быть. Если вы хотите повернуть свою модель (например, обозначать точку «COM») вокруг себя, ее необходимо центрировать (0,0,0).

Смежные вопросы