Как да покажете правилно сфера в openGL

Не знам много за openGL/glut, но съм го използвал успешно преди за някои изключително прости неща в 2D. Сега искам да мога да рисувам сфери в 3D. Опитвам се да симулирам сблъсъци на частици, така че всичко, което наистина ще трябва да направя в края на графиката, е да нарисувам сфери. Ето моят неуспешен опит

void renderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
            // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    glutSwapBuffers();
}

void timerProc(int arg)
{
    glutTimerFunc(50,timerProc,0);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

    glColor3f(0.0,0.0,0.0);  //color = black
    glPushMatrix();
        glTranslated(0,0,0);
        glutSolidSphere(.74, 500, 500);
    glPopMatrix();

    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    srand(time(NULL));
    init();

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50,30);
    glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)-80,glutGet(GLUT_SCREEN_HEIGHT)-60);

    mainWindow=glutCreateWindow("New Window"); //global variable

    WIDTH=glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT=glutGet(GLUT_WINDOW_HEIGHT); //global variable

    glutDisplayFunc(renderScene);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

    glutTimerFunc(50,timerProc,0);
    glutMainLoop();
    return 0;
}

Надяваме се, че всичките ми проблеми произтичат от една наистина основна грешка... По някаква причина това създава овал. И въпреки че овалът е доста голям (може би около 1/8 от екрана широк и висок), ако намаля радиуса до .73, той изчезва, предполагам, защото е твърде малък, за да се види. Как бих направил така, че тази сфера да изглежда кръгла, както бихте очаквали, и така че, тъй като мога да видя всичко, което се случва в даден обем, да речем кутия 10x10x10, както бихте направили, ако просто стоите до кутия с частици, които летяха наоколо и надничаха в нея, или разумно приближение. В момента е трудно да се каже какво точно гледам (знам, че стоя на 1,1,1 и гледам произхода, но ми е трудно да разбера какво точно виждам) Освен това понякога, когато стартирайте го, целият екран е просто черен. След това, когато почистя и изградя и стартирам отново, всичко е наред. Всъщност не е голяма грижа, но досадно и бих искал да разбера какво се случва. Освен това, когато броят на срезовете и купчините беше по-малък, щеше да изглежда добре, ако радиусът беше голям, но щеше да се изкриви изключително много, когато радиусът беше малък, което ми се стори много странно...


person WanderingMathematician    schedule 15.04.2014    source източник
comment
Не съм сигурен дали това е основната причина за вашия проблем, но бих започнал, като преместя целия ви код за чертане на сфери от вашия timerProc в renderscene() и накарам вашия таймер просто да извика glutPostRedisplay(), вместо да прави собствен чертеж. Вероятно няма да реши напълно проблема ви, но е добра практика. Най-малкото ще гарантира, че буферите за цвят и дълбочина се изчистват при всеки кадър. Освен това добавете извикване към glFlush(), преди да размените буферите. Това ще гарантира, че всички извиквания на чертежи са завършени.   -  person redsoxfantom    schedule 16.04.2014
comment
Сферата все още ли изчезва, ако използвате glutSolidSphere(0.73, 10, 10) (т.е. имате по-малко срезове/стекове)?   -  person Christian Aichinger    schedule 16.04.2014
comment
@redsoxfantom Промени го, добре е да имаш добра практика :) Но това не промени нищо. @ChristianAichinger Да, да, така е. Ако оставя радиуса по-голям: glutSolidSphere(0.74, 10, 10) той става ужасно деформиран и много по-малък.   -  person WanderingMathematician    schedule 16.04.2014


Отговори (1)


Основният проблем, който имате тук, е Z изрязването. Първоначалният диапазон Z за сцената е (-1, 1), така че виждате само част от действителната сфера и чрез промяна на размера й излизате извън диапазона z.

Изображение

Има няколко проблема, които виждам в кода. Добре е да разберете как всъщност работи работният процес GLUT.

Да видим какво прави кодът грешно.

Основен

int main(int argc, char **argv)
{
    srand(time(NULL));
    init();

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50, 30);
    glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH) - 80, 
                       glutGet(GLUT_SCREEN_HEIGHT) - 60);

    mainWindow = glutCreateWindow("New Window"); //global variable

    WIDTH = glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT = glutGet(GLUT_WINDOW_HEIGHT); //global variable

    glutDisplayFunc(renderScene);

Тук дефинирате функцията за показване. Извиква се всеки път, когато съдържанието на прозореца трябва да бъде анулирано. В този случай той се анулира само при стартиране. Функцията renderScene не прави нищо страхотно, просто изчиства екрана. Така че в началото ще получите черен екран.

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

В момента няма нужда от смесване. Можете да пропуснете тази част напълно.

    glutTimerFunc(50, timerProc, 0);

Сега настройвате функцията timerProc да бъде извикана след 50 милисекунди.

    glutMainLoop();

Както се посочва в документацията: glutMainLoop влиза в цикъла за обработка на събития GLUT. Тази рутина трябва да бъде извикана най-много веднъж в програма GLUT. Веднъж извикана, тази рутина никога няма да се върне. Той ще извика при необходимост всички регистрирани обратни повиквания.

    return 0;
}

Рендиране на сцена

void renderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Това е единственото място, където изчиствате екрана. Timer Func не прави това.

    glLoadIdentity();

Нулираш матриците.

    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);

Настройка на матриците. (Една матрица, за да бъдем точни)

    glutSwapBuffers();

И без да чертаете нищо, сменяте буферите.

}

Функцията за изобразяване на сцена се извиква всеки път, когато рамката на прозореца трябва да бъде преначертана.

Таймер

Тази функция разчита на екрана, който първо се изчиства от renderScene. void timerProc(int arg) { glutTimerFunc(50, timerProc, 0);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

Този път не се изчиства. Само настройка на цвета.

    glColor3f(0.0, 0.0, 0.0);  //color = black
    glPushMatrix();
    glTranslated(0, 0, 0);
    glutSolidSphere(.74, 500, 500);
    glPopMatrix();

    glutSwapBuffers();
}

Как да го оправя?

Просто настройте матриците. С подходящ диапазон Z.

void resetTransformations() {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1, 1, -1, 1, -1000, 1000);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);
}

void renderScene()
{
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Reset transformations
    resetTransformations();

    // Just to see some triangles
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    glColor3f(0.0, 0.0, 0.0);  //color = black
    glPushMatrix();
    glTranslated(0, 0, 0);
    glutSolidSphere(0.74, 500, 500);
    glPopMatrix();

    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    srand(time(NULL));

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50, 30);
    glutInitWindowSize(256, 256);

    mainWindow = glutCreateWindow("New Window"); //global variable

    WIDTH = glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT = glutGet(GLUT_WINDOW_HEIGHT); //global variable

    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);

    glutMainLoop();
    return 0;
}
person mrVoid    schedule 15.04.2014
comment
Това наистина работи, но все още се случват няколко странни неща. Доколкото разбирам, glOrtho задава колко далеч можете да видите обекти? Ако променя това извикване на glOrtho(-10, 10, -10, 10, -1000, 1000); и радиуса на нещо по-голямо, да речем 7, сферата се свива, когато стартирам кода. Защо ще се свива? Мислех, че нищо не се променя и кодът за чертане се извиква само веднъж, тъй като съдържанието на прозореца се анулира само в началото на програмата... - person WanderingMathematician; 16.04.2014
comment
glOrtho е паралелна проекция на определен блок от пространството. Ако увеличите ширината и височината на блока като glOrtho(-10, 10, -10, 10, -1000, 1000);, вашата сфера ще обхваща по-малко пространство от този блок. - person mrVoid; 17.04.2014
comment
Имах предвид, че се свива, докато програмата работи. Започва по-малък от преди, което има смисъл, а след това се свива до нищо по време на изпълнение. - person WanderingMathematician; 17.04.2014
comment
Вярно, има грешка в отговора. Няма зададена самоличност. Фиксирана. - person mrVoid; 17.04.2014