2013-02-22 3 views
3

Я хочу изучить OpenGL и решил начать с очень простого примера - визуализации формы кометы Wild 2, как это было сделано из измерений с космического корабля Stardust (подробности о данных в : http://nssdc.gsfc.nasa.gov/nmc/masterCatalog.do?ds=PSSB-00133). Пожалуйста, имейте в виду, что я абсолютно ничего не знаю о OpenGL. Некоторые Google-fu помогли мне дойти до кода, представленного ниже. Несмотря на все мои усилия, моя комета сосет:Базовый рендеринг кометы Дикие данные формы 2 с использованием OpenGL

An OpenGL rendering of comet Wild 2

Я хотел бы, чтобы она выглядела симпатичнее, и я понятия не имею, как поступить (кроме чтения Красную книгу, или аналогичный). Например:

  • Как я могу сделать очень простой «каркасный» рендеринг формы?
  • Предположим, что Солнце находится в «нижнем» направлении (то есть вдоль -Y), как я могу добавить свет и увидеть тень на другой стороне?
  • Как добавить «события мыши», чтобы я мог поворачивать свой просмотр и увеличивать/уменьшать масштаб?

Как я могу сделать этот монстр более красивым? Любые ссылки на онлайновые учебники или примеры кода?

Я поместил исходный код, данные и Makefile (для OS X) в BitBucket:

рт.ст. клона https://[email protected]/arrieta/learning-opengl

Данные состоят из 8,761 триплетов (вершин, в кадре тела фиксированной) и 17 518 треугольников (каждый треугольник представляет собой триплет целых чисел, относящихся к одному из 8 761 вершинных триплетов).

#include<stdio.h> 
#include<stdlib.h> 

#include<OpenGL/gl.h> 
#include<OpenGL/glu.h> 
// I added this in case you want to "copy/paste" the program into a 
// non-Mac computer 
#ifdef __APPLE__ 
# include <GLUT/glut.h> 
#else 
# include <GL/glut.h> 
#endif 

/* I hardcoded the data and use globals. I know it sucks, but I was in 
    a hurry. */ 
#define NF 17518 
#define NV 8761 
unsigned int fs[3 * NF]; 
float vs[3 * NV]; 
float angle = 0.0f; 

/* callback when the window changes size (copied from Internet example) */ 
void changeSize(int w, int h) { 
    if (h == 0) h = 1; 
    float ratio = w * 1.0/h; 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glViewport(0, 0, w, h); 
    gluPerspective(45.0f, ratio, 0.2f, 50000.0f); /* 45 degrees fov in Y direction; 50km z-clipping*/ 
    glMatrixMode(GL_MODELVIEW); 
} 

/* this renders and updates the scene (mostly copied from Internet examples) */ 
void renderScene() { 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity(); 
    gluLookAt(0.0f, 0.0f, 10000.0f, /* eye is looking down along the Z-direction at 10km */ 
      0.0f, 0.0f, 0.0f,  /* center at (0, 0, 0) */ 
      0.0f, 1.0f, 0.0f); /* y direction along natural y-axis */ 

    /* just add a simple rotation */ 
    glRotatef(angle, 0.0f, 0.0f, 1.0f);  
    /* use the facets and vertices to insert triangles in the buffer */ 
    glBegin(GL_TRIANGLES); 
    unsigned int counter; 
    for(counter=0; counter<3 * NF; ++counter) { 
    glVertex3fv(vs + 3 * fs[counter]); /* here is where I'm loading 
              the data - why do I need to 
              load it every time? */ 
    } 
    glEnd(); 
    angle += 0.1f;    /* update the rotation angle */ 
    glutSwapBuffers(); 
} 


int main(int argc, char* argv[]) { 
    FILE *fp; 
    unsigned int counter; 


    /* load vertices */ 
    fp = fopen("wild2.vs", "r"); 
    counter = 0; 
    while(fscanf(fp, "%f", &vs[counter++]) > 0); 
    fclose(fp); 

    /* load facets */ 
    fp = fopen("wild2.fs", "r"); 
    counter = 0; 
    while(fscanf(fp, "%d", &fs[counter++]) > 0); 
    fclose(fp); 

    /* this initialization and "configuration" is mostly copied from Internet */ 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); 
    glutInitWindowPosition(0, 0); 
    glutInitWindowSize(1024, 1024); 
    glutCreateWindow("Wild-2 Shape"); 

    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    glEnable(GL_DEPTH_TEST); 

    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; 
    GLfloat mat_shininess[] = { 30.0 }; 
    GLfloat light_position[] = {3000.0, 3000.0, 3000.0, 0.0 }; 
    glClearColor (0.0, 0.0, 0.0, 0.0); 
    glShadeModel (GL_SMOOTH); 
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); 
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); 
    glLightfv(GL_LIGHT0, GL_POSITION, light_position); 

    glutDisplayFunc(renderScene); 
    glutReshapeFunc(changeSize); 
    glutIdleFunc(renderScene); 

    glutMainLoop(); 
    return 0; 
} 

EDIT

Это начинает выглядеть лучше, и у меня сейчас много ресурсов, чтобы изучить на некоторое время. Он все еще сосет, но на мои вопросы ответили!

Another image, which does not suck as much

Я добавил нормалей, и может переключаться между "текстурой" и каркасные:

With normals

PS. В repository показаны изменения, внесенные в соответствии с предложениями SeedmanJ.

+2

FYI: «Решил начать с очень простого примера». «Простой пример» - это треугольник, а не сложная сетка. –

+0

@ НикольБолас: хорошая точка - тускло отметили. – Escualo

+2

Не используйте немедленный режим. Не используйте конвейер с фиксированной функцией. http://open.gl/introduction http://www.arcsynthesis.org/gltut/ –

ответ

3

Это очень легко изменить в каркасном рендеринга в OpenGL, вы должны будете использовать

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 

и переключиться обратно на оказание наполняющей

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 

О фары, OpenGL позволяет использовать не более 8 различных огней, генерируя окончательный рендеринг благодаря нормалям и материалам. Вы можете активировать режим освещения с:

glEnable(GL_LIGHTING); 

, а затем активировать каждый из ваших огней либо:

glEnable(GL_LIGHT0); 
glEnable(GL_LIGHT1); 

изменить свет свойство, как его положение, пожалуйста, посмотрите на http://linux.die.net/man/3/gllightfv

Вам нужно будет настроить свои нормали для каждой вершины, которую вы определяете, если вы используете метод glBegin(). В визуализации VBO это то же самое, но нормали также содержатся в vram. В методе glBegin() вы можете использовать

glNormal3f(x, y, z); for example 

для каждой вершины, которую вы определяете.

И для получения дополнительной информации о том, что вы можете сделать, красная книга - это хороший способ начать.

Перемещение вашей «сцены» - это еще одна вещь, которую OpenGL косвенно позволяет вам делать. Как все это работает с матрицей,

вы можете использовать либо

glTranslate3f(x, y, z); 
glRotate3f(num, x, y, z); 
.... 

Управление ключевых событий и событий мыши имеет (я почти уверен, что) ничего общего с OpenGL, это зависит от импровизировать вашего используя, например, glut/SDL/..., поэтому вам придется ссылаться на свои собственные документы.

Окончательно, для получения более подробной информации о некоторых из функций, которые вы можете использовать, http://www.opengl.org/sdk/docs/man/, а также учебная часть, ведущая вас к различным интересным веб-сайтам.

Надеюсь, это поможет!

+0

Отличный совет! Благодаря! – Escualo

1

Как я могу сделать очень простой «каркасный» рендеринг формы?

glPolygonMode(GL_FRONT, GL_LINE);

Пусть Солнце вдоль «дна» направлении (то есть, по -Y), как я могу добавить свет и увидеть тень на другой стороне?

Хорошие тени сложны, особенно с трубопроводом с фиксированной функцией.

Но перед этим вам нужно normals, чтобы пойти с вашими вершинами.Вы можете рассчитать per-face normals pretty easily.

Как добавить «события мыши», чтобы я мог поворачивать свой просмотр и увеличивать/уменьшать масштаб?

Попробуйте обработчики мышки here.

+0

Спасибо! Очень полезная информация. Я скоро добавлю управление мышью ... – Escualo

-7

Хотя мне нравится говорить «Начните с чего-то более простого», я думаю, иногда вам нужно «погрузиться», чтобы получить хорошее понимание, на небольшой промежуток времени! Отлично сработано!

Кроме того, если вы хотите пример, пожалуйста, спросите ... я написал хорошо документированы, и эффективный, но читаемым чистый Win32 (Нет .NET или MFC) OpenGL FPS!

Хотя кажется, что другие люди ответили на большинство вопросов ... Я могу вам помочь, если вы хотите, может быть, сделать прохладную текстуру (если у вас ее нет) ...

Чтобы ответить на этот вопрос:

glBegin(GL_TRIANGLES); 
    unsigned int counter; 
    for(counter=0; counter<3 * NF; ++counter) { 
    glVertex3fv(vs + 3 * fs[counter]); /* here is where I'm loading 
              the data - why do I need to 
              load it every time? */ 
} 
glEnd(); 

Это оказывает вершины 3D-модели (в случае, если вид изменился) и используя DC (контекст устройства), BitBlt-х IT- на окна ! Это нужно сделать многократно (в случае, если что-то заставило окно очистить) ...

+0

'-1'. Рассуждение: «Надеюсь, вы используете Win32, а не glut.h или glew.h или что-нибудь в этом роде!» <- это неплохой совет; как насчет кросс-платформенной поддержки? Кроме того, как вы должны получить 2.0+ функциональность * без * GLEW? Не говоря уже о том, что на современных графических процессорах предложенный вами подход в основном бесполезен, поскольку содержимое указанного буфера будет меняться с каждым движением мыши. –

+0

Также, как правило, это затрудняло бы кросс-платформу, пример, который я предложил, разделяет WinAPI и упрощает его применение для кросс-платформенной реализации (просто путем изменения некоторых функций и удаления WinProc). Мне просто не нравится полагаться на несколько библиотек и заголовок ... Они часто устаревают. – Mitch

+1

Итак, в основном вы предлагаете изобретать колесо, потому что «библиотеки могут устареть». Кроме того, «удаляет API низкого уровня, добавляя абстракции» - в этом весь смысл, не так ли? Вы подразумеваете, что вы вызываете каждую функцию, получая необработанный указатель каждый раз? Потому что все остальное было бы «абстракцией». Кроме того, существуют другие библиотеки, кроме GLEW, например GLFW. Ваше предложение не «продвинуто», оно явно необоснованно в современных обычаях, но вы, похоже, застряли в 1998 году. –

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