Главная страница
Навигация по странице:

  • 2.9 Упражнение:" Игра Арканоид"

  • Chapter 3 Рисуем простые объекты 3.1 Общие положения

  • 3.5 Четырехугольники и многоугольники

  • 3.6 Уражнение:"Многогранники"

  • 3.7 Уражнение:"Многогранники" Реализуйте проволочные многогранники с помощью проволочных треугольников, многоугольников и линий. 3.8 Резюме

  • Chapter 4 Полезные мелочи 4.1 Построение поверхностей

  • 4.2 Упражнение: "Сфера, цилиндр и диски".

  • 4.3 Интерполяция цветов

  • Opengl игорь Тарасов Часть i основы OpenGL


    Скачать 1.72 Mb.
    НазваниеOpengl игорь Тарасов Часть i основы OpenGL
    Дата10.04.2023
    Размер1.72 Mb.
    Формат файлаdocx
    Имя файлаOpenGL.docx
    ТипДокументы
    #1050532
    страница2 из 5
    1   2   3   4   5

    2.8  Анимация

    Давайте оживим нашего снеговика и добавим интерактивность. Для этого надо отрисовывать кадры и реагировать на внешние события от клавиатуры или мыши.

    Для отрисовки кадров их надо как-то различать. Для этого мы в функции display вводим переменную time типа int с модификатором static. Создайте новый проект и в функцию display введите следующее: Яtatic int time=0;". Модификатор static означает, что значение переменной будет сохраняться при выходе из функции. Начальное значение мы устанавливаем в ноль. Если функция display не зависит от времени, то счетчик кадров можно и не вести. Теперь добавьте следующие строчки:
    glPushMatrix();

    glTranslated( ((double)time)/100.0 ,0,0);

    ... // здесь код из предыдущего упражнения "Cнеговик"

    glPopMatrix();
    Запустив приложение, вы увидите, что снеговик пополз вдоль оси Х. Вот так вы можете делать анимацию. Т.е. теперь координаты объектов вычисляются в зависимости от времени. Я привел простой пример. Вообще говоря, для программирования сложной графики вам понадобится вычислять координаты каждого отдельного объекта в зависимости от времени.

    Далее мы рассмотрим пример с более сложной анимацией. Здесь вращается тор и его ось вращения. Я приведу исходный текст с подробными комментариями. Пример программы "Гироскоп":




    Исходный файл смотрите здесь. Исполняемый файл здесь.


    glPushMatrix(); // сохраняем текущие координаты, т.к. при выходе

    // из функции нам нужно вернуться к абсолютным координатам

    // попробуйте закомментировать вызов glPushMatrix

    // здесь и glPopMatrix в конце и вы увидите, что из этого получится
    glRotated(time/2, 0.0, 1.0, 0.0); // поворачиваем координаты

    glLineWidth(5); // устанавливаем толщину линии - пять

    glColor3f(1,0,0); // устанавливаем текущий цвет - красный
    glBegin(GL_LINES); // рисуем красную ось

    glVertex3d(-0.3,0,0); // т.к. мы повернули координаты,

    glVertex3d(1.5,0,0); // ось будет повернута в абсолютных

    glEnd(); // координатах, и т.к. функция display вызывается в цикле, и переменная

    // time увеличивается на единицу

    // при каждом вызове display, мы

    // получаем анимацию - вращающуюся ось
    glPushMatrix(); // теперь относительно повернутых координат

    // мы переходим к новым координатам

    glRotated(2*time, 1,0,0); // поворачиваем их на угол 2*time вокруг красной оси

    glTranslated(-0.3,0,0); // и сдвигаем на край оси

    glColor3f(0,0,1); // устанавливаем синий цвет

    glPushMatrix(); // теперь еще раз переходим к новым координатам,

    glRotated(90,0,1,0); // чтобы развернуть тор на 90 градусов

    // у вас крыша еще не поехала?

    // немного?

    // то-то же, тут не так все просто, но если понять что и как, то

    // очень удобно программировать графику

    glLineWidth(1);

    auxWireTorus(0.2, 0.7);

    glPopMatrix(); // нарисовав тор, мы возвращаемся к предыдущим

    // координатам, если забыли, начало этих координат

    // лежит на конце красной оси
    glLineWidth(7);

    glColor3f(0,1,0);
    glBegin(GL_LINES); // теперь рисуем три зеленых линиии

    glVertex3d(0,0,0); // что тут и как рисуется, я поясню в

    glVertex3d(0,1,0); // следующей

    glVertex3d(0,0,0); // главе, сейчас это не так важно

    glVertex3d(0,-0.5,1);

    glVertex3d(0,0,0);

    glVertex3d(0,-0.5,-1);

    glEnd();

    glPopMatrix(); // теперь возвращаемся к повернутым координатам на угол time/2

    glPopMatrix(); // ну и переходим к абсолютным координатам

    time++; // увеличиваем счетчик кадров или вермя, называйте как хотите, на единицу

    Как вы, наверное, догадались, надо создать очередной проект, скопировать туда мой шаблон, добавить его в проект, указать библиотеки opengl32.lib glu32.lib glaux.lib в Project->Setting->Link->Settings->Link->Object/library modules:, вставить этот код в функцию display. Еще вам нужно в начале функции display вставить строку static int time=0; и закомментировать строчку glEnable(GL_LIGHTING) в функции main.

    Запустив это приложение, вы увидите, как оно работает. Теперь закомментируйте соответсвующие друг другу вызовы glPushMatrix и glPopMatrix и посмотрите на результат. Я бы рекомендовал такой способ для изучения и понимания работы программы: вы комментируете куски кода и смотрите, что получается.

    Для того, чтобы реагировать на клавиатуру или мышь, вы должны определить функцию, которая будет вызываться при поступление событий от клавиатуры или мыши. Для кнопки клавиатуры вы определяете функцию со следующим прототипом void CALLBACK FunctionName(void) и устанавливаете ее как обработчик определенной кнопки - auxKeyFunc(key_code, FunctionName); key_code смотри в glaux.h. Пример: auxKeyFunc(AUX_LEFT, FunctionName) Здесь вы устанавливаете FunctionName как функцию, которая будет вызываться при нажатии на клавиатуре клавиши "стрелка влево".

    Для мыши вы устанавливаете свою функцию обработки событий мыши вызовом функции auxMouseFunc(int button,int action,AUXMOUSEPROC). Переменная button может принимать значения - AUX_LEFTBUTTON, AUX_MIDDLEBUTTON, AUX_RIGHTBUTTON. Переменная action принимает следующие значения - AUX_MOUSEDOWN, AUX_MOUSEUP, AUX_MOUSELOC. Функция AUXMOUSEPROC должна иметь прототип - void CALLBACK FunctionName(AUX_EVENTREC *event), где AUX_EVENTREC определено как
    typedef struct _AUX_EVENTREC

    {

    GLint event;

    GLint data[4];

    }AUX_EVENTREC;
    Для более детальной информации смотрите справочные руководства и исходные тексты библиотеки OpenGL Auxiliary library. Эта книга об OpenGL, а не о программировании интерфейсов пользователя. Поэтому, за подобной информацией вам придется лезть в соответсвующие справочные руководства по Win API, MFC, Java и т.п.

    В FunctionName вы можете изменить какую-нибудь глобальную переменную, и, соответсвенно, функция display будет рисовать кадры в зависимости от этой переменной.

    2.9  Упражнение:" Игра Арканоид"

    Напишите игру "Arconoid" - летающий шарик, снизу подставка, пользователь стрелками или мышкой управляет подставкой и отбивает шарик.


    Исходный файл смотрите здесь. Исполняемый файл здесь.
    2.10  Резюме

    На этом эта глава книги закончена. Вы научились рисовать трехмерные объекты и делать интерактивную анимацию, используя эти объекты. Этого, в общем-то, достаточно для написания примитивных программ.
    Chapter 3

    Рисуем простые объекты

    3.1  Общие положения

    Точки, линии, треугольники,четырехугольники, многоугольники - простые объекты, из которых состоят любые сложные фигуры. Все они рисуются следующим образом:
    glBegin(GLenum type); // указываем, что будем рисовать

    glVertex[2 3 4][s i f d](...); // первая вершина

    ………..

    // тут остальные вершины

    glVertex[2 3 4][s i f d](...); // последняя вершина

    glEnd(); // закончили рисовать примитив
    Сначала вы говорите, что будете рисовать - glBegin с соответсвующим параметром. Возможные значения type см. ниже. Далее вы указываете вершины, определяющие объкты указанного типа. И наконец, вы вызваете glEnd, чтобы указать, что вы закончили рисовать объекты типа, указанного в glBegin.
    3.2  Точки

    \\

    // рисуем точки

    glPointSize(2);

    glBegin(GL_POINTS);

    glColor3d(1,0,0);

    glVertex3d(-4.5,4,0); // первая точка
    glColor3d(0,1,0);

    glVertex3d(-4,4,0); // вторая точка
    glColor3d(0,0,1); // третья

    glVertex3d(-3.5,4,0);

    glEnd();

    glPointSize(5);

    glBegin(GL_POINTS);

    glColor3d(1,0,0);

    glVertex3d(-2,4,0); // первая точка
    glColor3d(0,1,0);

    glVertex3d(-1,4,0); // вторая точка

    glColor3d(0,0,1); // третье

    glVertex3d(0,4,0);

    glEnd();

    glPointSize(10);

    glEnable(GL_POINT_SMOOTH);

    glBegin(GL_POINTS);

    glColor3d(1,0,0);

    glVertex3d(2,4,0); // первая точка
    glColor3d(0,1,0);

    glVertex3d(3,4,0); // вторая точка
    glColor3d(0,0,1); // третья

    glVertex3d(4,4,0);

    glEnd();

    glDisable(GL_POINT_SMOOTH);
    Вы можете нарисовать столько точек, сколько вам нужно. Вызывая glVertex3d, вы устанавливает новую точку. Так же вы можете вызывать glColor3d внутри glBegin/glEnd. Размер точки устанавливается с помощью функции void glPointSize(GLfloat size). Режим сглаживания устанавливается вызовом функции glEnable() с параметром GL_POINT_SMOOTH. \\\\Отключается соответственно вызовом glDisable() c этим параметром. Последние функции - glPointSize и glEnable/glDisable надо вызывать вне glBegin/glEnd, иначе они будут проигнорированы. Функции glEnable/glDisable включают/выключают множество опций, но вы должны учитывать, что некоторые опции влекут за собой большие вычисления и, следовательно, изрядно затормаживают ваше приложение, поэтому без надобности не стоит их включать.

    3.3  Линии

    \\\\\\\\\\\\\\

    glLineWidth(1); // ширину линии устанавливаем 1

    glBegin(GL_LINES);

    glColor3d(1,0,0); // красный цвет

    glVertex3d(-4.5,3,0); // первая линия

    glVertex3d(-3,3,0);
    glColor3d(0,1,0); // зеленый

    glVertex3d(-3,3.3,0); // вторая линия

    glVertex3d(-4,3.4,0);

    glEnd();

    glLineWidth(3); // ширина 3

    glBegin(GL_LINE_STRIP); // см. ниже

    glColor3d(1,0,0);

    glVertex3d(-2.7,3,0);

    glVertex3d(-1,3,0);
    glColor3d(0,1,0);

    glVertex3d(-1.5,3.3,0);

    glColor3d(0,0,1);

    glVertex3d(-1,3.5,0);

    glEnd();

    glLineWidth(5);

    glEnable(GL_LINE_SMOOTH);

    glEnable(GL_LINE_STIPPLE); // разрешаем рисовать прерывистую линию

    glLineStipple(2,58360); // устанавливаем маску пояснения см. ниже
    glBegin(GL_LINE_LOOP);
    glColor3d(1,0,0);

    glVertex3d(1,3,0);

    glVertex3d(4,3,0);
    glColor3d(0,1,0);

    glVertex3d(3,2.7,0);

    glColor3d(0,0,1);

    glVertex3d(2.5,3.7,0);

    glEnd();
    glDisable(GL_LINE_SMOOTH);

    glDisable(GL_LINE_STIPPLE);
    glLineStipple устанавливает маску, при помощи которой будут рисоваться штриховые линии. Второй параметр задает саму маску. В двоичном виде это число выглядит так: 0000000011111111, т.е. всего 16 бит, старшие восемь установлены в ноль, значит тут линии не будет. Младшие установлены в единицу, тут будет рисоваться линия. Первый параметр определяет, сколько раз повторяется каждый бит. Скажем, если его установить равным 2, то накладываемая маска будет выглядить так: 00000000000000001111111111111111. Чтобы высчитать маску, я воспользовался калькулятором.Набрал в нем число в двоичной форме и перевел его в десятичную систему.

    Также линии можно рисовать, передавая в glBegin GL_LINE_STRIP и GL_LINE_LOOP. В первом случае будет рисоваться ломаная, т.е. первая вершина соединяется со второй, вторая с третьей и так далее. GL_LINE_LOOP идентичен GL_LINE_STRIP, только последняя вершина будет соединена с первой.
    3.4  Треугольники
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // см. ниже

    glBegin(GL_TRIANGLES);

    glColor3d(1,0,0); // рисуем треугольник

    glVertex3d(-4,2,0);

    glVertex3d(-3,2.9,0);

    glVertex3d(-2,2,0);

    glEnd();

    glLineWidth(2);

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //рисуем проволочные треугольники

    glBegin(GL_TRIANGLE_STRIP); // обратите внимание на порядок вершин

    glColor3d(0,1,0);

    glVertex3d(1,2,0);

    glVertex3d(0,2.9,0);

    glVertex3d(-1,2,0);

    glVertex3d(0,1.1,0);

    glEnd();
    glEnable(GL_LINE_STIPPLE);

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    glBegin(GL_TRIANGLE_FAN);

    glColor3d(0,0,1);

    glVertex3d(4,2,0);

    glVertex3d(2.6,2.8,0);

    glVertex3d(2,2,0);

    glVertex3d(3,1.1,0);

    glEnd();

    glDisable(GL_LINE_STIPPLE);
    glPolygonMode устанавливает опции для отрисовки многоугольника. Первый параметр может принимать значения - GL_FRONT, GL_BACK и GL_FRONT_AND_BACK. Второй параметр указывает, как будет рисоваться многоугольник. Он примает значения - GL_POINT(рисуются только точки), GL_LINE(рисуем линии) и GL_FILL(рисуем заполненный многоугольник). Первый параметр указывает: к лицевой, тыльной или же к обеим сторонам применяется опция, заданная вторым параметром. Треугольники можно рисовать, передав GL_TRIANGLES_STRIP или GL_TRIANGLES_FAN в glBegin. В первом случае первая, вторая и третья вершины задают первый треугольник. Вторая, третья и четвертая вершина - второй треугольник. Третья, четвертая и пятая вершина - третий треугольник и т.д. Вершины n, n+1 и n+2 определят n-ый треугольник. Во втором случае первая, вторая и третья вершина задают первый треугольник. Первая, третья и четвертая вершины задают второй треугольник и т.д. Вершины 1, n+1, n+2 определяют n-ый треугольник.
    3.5  Четырехугольники и многоугольники

    Четырехугольники рисуются вызовом функции glBegin с параметром GL_QUADS или GL_QUAD_STRIP. Для первого случая каждые четыре вершины определяют свой четырехугольник. Во втором случае рисуются связанные четырехугольники. Первая, вторая, третья и четвертая вершина определяют первый четырехугольник. Третья, четвертая, пятая и шестая вершина - второй четырехугольник и т.д. (2n-1), 2n, (2n+1) и (2n+2) вершины задают n-ый четырехугольник. Многоугольники задаются вызывом glBegin с параметром GL_POLYGON. Все вершины определяют один многоугольник. Для многоугольников можно задавать стили при помощи выше описанной функции glPolygonMode, толщину линии, толщину точек и цвет.

    3.6  Уражнение:"Многогранники"

    Изобразите точки, линии, треугольники, многоугольники в одном окне, как показано ниже.



    Исходный файл смотрите здесь. Исполняемый файл здесь.
    3.7 Уражнение:"Многогранники"
    Реализуйте проволочные многогранники с помощью проволочных треугольников, многоугольников и линий.
    3.8 Резюме
    Ну вот, вы еще на один шаг продвинулись в изучение библиотеки OpenGL. Теперь вы имеете представление о том, как рисовать элементарные фигуры. Из примитивов вы можете составить фигуры любой сложности.
    Chapter 4

    Полезные мелочи

    4.1  Построение поверхностей

    Существует набор функций для посторения сфер, цилиндров и дисков. Эти функции представляют очень мощный контроль за построением трехмерных объектов. Непосредственно рисовать вы будете, используя следующие функции: gluSphere, gluCylinder, gluDisk и gluPartialDisk. В начале книги вы научились строить трехмерные объекты с помощью функций из библиотеки Auxilary Library. Функции aux[Solid/Wire]Sphere, aux[Solid/Wire]Cylinder и aux[Solid/Wire]Cone просто вызывают gluSphere и gluCylinder. Как я уже ранее говорил, в aux[Solid/Wire]Cylinder и aux[Solid/Wire]Cone фирмы Microsoft имеются баги. Здесь будет подробно рассмотрено построение сфер и цилиндров, так что потребность в aux[Solid/Wire]Cylinder и aux[Solid/Wire]Cone отпадет.

    Первым параметром для gluSphere, gluCylinder, gluDisk является указатель на объект типа GLUquadricObj. Далее следуют параметры непосредственно создаваемой фигуры. Для сферы - это радиус; для цилиндра - радиус нижнего основания, радиус верхнего основания и высота; для диска - внутренний радиус, внешний радиус и для частичного диска - внутренний радиус, внешний радиус, угол, с которого начинать рисовать, длина дуги в градусах, которую рисовать. Последние два параметра у всех этих функций одинаковы. Это число разбиений вокруг оси Z и число разбиений вдоль оси Z. Как я уже говорил, все сложные объекты состоят из простых: точек, линий и многоугольников. Вы понимаете, что нарисовать/создать идеально гладкую сферу или цилиндр невозможно. Поэтому строится приближение из плоскостей. Для этого и нужно указать количество разбиений. Чем больше разбиение, тем лучше будет выглядеть ваша сфера. Однако, задавать здесть число с шестью нулями не стоит. Это лишено всякого смысла. Оптимальным, на мой взгляд, является число от 10 до 20. Чем больше объект, тем больше нужно разбиений. Число разбиений вдоль и поперек я выставляю одинаковыми. Сначала вы должны создать объект типа GLUquadricObj с помощью функции gluNewQuadric. Теперь устанавливаете свойства с помощью функции gluQuadricDrawStyle. Доступны стили: GLU_FILL - рисуется сплошной объект, \\\\GLU_LINE - проволочный объект, \\GLU_POINT - рисуются только точки. Рисуете то, что хотите. И не забудьте удалить созданный объект, воспользовавшись gluDeleteQuadric.

    Настало время поэкспериментировать. Создайте очередное консольное приложение и отредактируйте функцию display следующим образом.
    void CALLBACK display(void)

    {

    GLUquadricObj *quadObj;
    quadObj = gluNewQuadric(); // создаем новый объект для создания сфер и цилиндров

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glPushMatrix();

    glColor3d(1,0,0);

    gluQuadricDrawStyle(quadObj, GLU_FILL); // устанавливаем стиль: сплошной
    gluSphere(quadObj, 0.5, 10, 10); // рисуем сферу радиусом 0.5

    glTranslated(-2,0,0); // сдвигаемся влево

    glRotated(45, 1,0,0); // поворачиваем

    glColor3d(0,1,0);

    gluQuadricDrawStyle(quadObj, GLU_LINE); // устанавливаем

    // стиль: проволочный
    gluCylinder(quadObj, 0.5, 0.75, 1, 15, 15);

    glPopMatrix();

    gluDeleteQuadric(quadObj);

    auxSwapBuffers();

    }
    4.2  Упражнение: "Сфера, цилиндр и диски".

    Доработайте код, приведенный выше, чтобы в первой строке показывались три сферы. Цвет и стили(GLU_POINT, GLU_LINE и GLU_FILL) должны быть разными. В следующих трех строках должны быть цилиндры, диски и частичные диски.


    Исходный файл смотрите здесь. Исполняемый файл здесь.
    4.3  Интерполяция цветов

    Когда вы создаете многоугольник, вы можете задать цвет для каждой его вершины. Если разрешено сглаживание цветов, то многоугольник будет переливаться. Поясню на примере. Режим сглаживания по умолчанию разрешен. Он переключается функцией glShadeModel с аргументами \\\\GL_FLAT и GL_SMOOTH. GL_FLAT запрещает сглаживание. На мой взгляд, сглаживание редко нужно. Вещь красивая, но бесполезная. Я в своих неучебных программах этот режим никогда не использовал. Поэтому советую его отключать, особенно, при программировании анимации,чтобы не затормаживать приложение. Создайте очередной проект. В функцию main добавьте

    glShadeModel(GL\_SMOOTH);
    Функцию display отредактируйте следующим образом:
    void CALLBACK display(void)

    {

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glBegin(GL_TRIANGLES);
    glColor3d(1,0,0);

    glVertex2d(0,0);
    glColor3d(0,1,0);

    glVertex2d(0,3);
    glColor3d(0,0,1);

    glVertex2d(3,0);
    glEnd();

    auxSwapBuffers();

    }


    Исходный файл смотрите здесь. Исполняемый файл здесь
    1   2   3   4   5


    написать администратору сайта