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

  • TObject );begin glClearColor(1.0, 1.0, 1.0, 1.0);glClear(GL_COLOR_BUFFER_BIT or

  • Работа с простой графикой и OpenGL. Delphi (Lazarus)


    Скачать 0.56 Mb.
    НазваниеDelphi (Lazarus)
    Дата02.05.2018
    Размер0.56 Mb.
    Формат файлаdocx
    Имя файлаРабота с простой графикой и OpenGL .docx
    ТипДокументы
    #42659
    страница6 из 6
    1   2   3   4   5   6

    Вращение, движение, масштабирование и проекции в OpenGL под Lazarus


    5. Май 2014 - 18:45 | admin

    Среда программирования: 

    Delphi (Lazarus)

    В OpenGL используются основные три системы координат: левосторонняя, правосторонняя и оконная. Первые две системы являются трехмерными и отличаются друг от друга направлением оси z: в правосторонней она направлена на наблюдателя, в левосторонней – в глубину экрана. Ось x направлена вправо относительно наблюдателя, ось y – вверх.

    http://grafika.me/files/les_screens/system_coord_opengl.jpg

    Системы координат в OpenGL

    Строго говоря, OpenGL позволяет путем манипуляций с матрицами моделировать как правую, так и левую систему координат. Но на данном этапе лучше пойти простым путем и запомнить: основной системой координат OpenGL является правосторонняя система.

    РАБОТА С МАТРИЦАМИ

    Для задания различных преобразований объектов сцены в OpenGL используются операции над матрицами, при этом различают три типа матриц: модельно-видовая, матрица проекций и матрица текстуры. Все они имеют размер 4x4. Видовая матрица определяет преобразования объекта в мировых координатах, такие как параллельный перенос, изменение масштаба и поворот. Матрица проекций определяет, как будут проецироваться трехмерные объекты на плоскость экрана (в оконные координаты), а матрица текстуры определяет наложение текстуры на объект.

    Умножение координат на матрицы происходит в момент вызова соответствующей команды OpenGL, определяющей координату (как правило, это команда glVertex*)

    Для того чтобы выбрать, какую матрицу надо изменить, используется команда:

    void glMatrixMode (GLenum mode)


    вызов которой со значением параметра mode равным

    GL_MODELVIEW,

    GL_PROJECTION,

    GL_TEXTURE

    включает режим работы с модельно-видовой матрицей, матрицей проекций, или матрицей текстуры соответственно. Для вызова команд, задающих матрицы того или иного типа, необходимо сначала установить соответствующий режим.

    Для определения элементов матрицы текущего типа вызывается команда

    void glLoadMatrix[f d] (GLtype *m)

    где m указывает на массив из 16 элементов типа float или double в соответствии с названием команды, при этом сначала в нем должен быть записан первый столбец матрицы, затем второй, третий и четвертый. Еще раз обратим внимание: в массиве m матрица записана по столбцам.

    Команда

    void glLoadIdentity (void)


    заменяет текущую матрицу на единичную.

    Часто бывает необходимо сохранить содержимое текущей матрицы для дальнейшего использования, для чего применяются команды

    void glPushMatrix (void)

    void glPopMatrix (void)


    Они записывают и восстанавливают текущую матрицу из стека, причем для каждого типа матриц стек свой. Для модельно-видовых матриц его глубина равна как минимум 32, для остальных – как минимум 2.

    МОДЕЛЬНО-ВИДОВЫЕ ПРЕОБРАЗОВАНИЯ

    К модельно-видовым преобразованиям будем относить перенос, поворот и изменение масштаба вдоль координатных осей. Для проведения этих операций достаточно умножить на соответствующую матрицу каждую вершину объекта и получить измененные координаты этой вершины.

    Сама матрица может быть создана с помощью следующих команд:

    void glTranslate[f d] (GLtype x, GLtype y, GLtype z)

    void glRotate[f d] (GLtype angle, GLtype x, GLtype y, GLtype z)

    void glScale[f d] (GLtype x, GLtype y, GLtype z)

    glTranlsate*() производит перенос объекта, прибавляя к координатам его вершин значения своих параметров.

    glRotate*() производит поворот объекта против часовой стрелки на угол angle (измеряется в градусах) вокруг вектора (x,y,z).

    glScale*() производит масштабирование объекта (сжатие или растяжение) вдоль вектора (x,y,z), умножая соответствующие координаты его вершин на значения своих параметров.

    Все эти преобразования изменяют текущую матрицу, а поэтому применяются к примитивам, которые определяются позже. В случае, если надо, например, повернуть один объект сцены, а другой оставить неподвижным, удобно сначала сохранить текущую видовую матрицу в стеке командой glPushMatrix(), затем вызвать glRotate() с нужными параметрами, описать примитивы, из которых состоит этот объект, а затем восстановить текущую матрицу командой glPopMatrix().

    Чтобы изображенная фигура выглядела пространственной, систему координат разворачивают вокруг оси X и вокруг оси Y.

    ПРОЕКЦИИ

    В OpenGL существуют стандартные команды для задания ортографической (параллельной) и перспективной проекций. Первый тип проекции может быть задан командами

    http://grafika.me/files/les_screens/glortho.jpg

     

    void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top,

    GLdouble near, GLdouble far)

    http://grafika.me/files/les_screens/glfrustum.jpg

    void glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top,

    GLdouble near, GLdouble far)

    Место команд в программе.
    Для того чтобы при каждой последующей перерисовке экрана не происходило изменение размеров сцены, связанное с переносом и проецированием, следует использовать видовые команды по определенным правилам.
    Первый способ – использование команды glLoadIdentity:

    glLoadIdentity; //Сброс всех матриц в 1

    glFrustum(-1, 1, -1, 1, 3, 10); //видовые параметры

    glTranslatef(0.0, 0.0, -5.0); //начальный сдвиг системы координат

    glRotatef(30.0, 1.0, 0.0, 0.0); //поворот относительно оси X

    glRotatef(70.0, 0.0, 1.0, 0.0); //поворот относительно оси Y

    glBegin(…);

    ….. // команды рисования

    glEnd;

    Второй способ – использование команд glPushMatrix и glPopMatrix:

    glPushMatrix(); //запоминаем текущую матрицу

    glFrustum(-1, 1, -1, 1, 3, 10); //видовые параметры

    glTranslatef(0.0, 0.0, -5.0); //начальный сдвиг системы координат

    glRotatef(30.0, 1.0, 0.0, 0.0); //поворот относительно оси X

    glRotatef(70.0, 0.0, 1.0, 0.0); //поворот относительно оси Y

    glBegin(…);

    ….. // команды рисования

    glEnd;

    glPopMatrix(); //восстанавливаем текущую матрицу

    ПРОГРАММА - ПРИМЕР ВРАЩЕНИЯ КУБА В LAZARUS НА OPENGL

    Разместите на форме три компонента

    OpenGLControl1: TOpenGLControl;

    Button1: TButton;

    Timer1: TTimer;

    Примечание. Обратите внимание для установки компонента TOpenGLControl смотрите урок "Подключение и работа с OpenGL в Lazarus под Windows".

    Пропишите на события создания формы Form1: OnFormCreate, нажатия кнопки Form1: OnButton1Click и работы таймера Form1: OnTimer1Timer следующий код:

    unit Unit1;

     

    {$mode objfpc}{$H+}

     

    interface

     

    uses

    Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,

    ExtCtrls, OpenGLContext, GL, GLU;

     

    type

     

    { TForm1 }

     

    TForm1 = class(TForm)

    Button1: TButton;

    OpenGLControl1: TOpenGLControl;

    Timer1: TTimer;

    procedure Button1Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

    procedure Timer1Timer(Sender: TObject);

    private

    { private declarations }

    public

    { public declarations }

    cube_rotation: GLFloat;

    Speed: Double;

    end;

     

    var

    Form1: TForm1;

     

    implementation

     

    {$R *.lfm}

     

    { TForm1 }

     

    procedure TForm1.Button1Click(Sender: TObject);

    begin

    Timer1.Enabled := true;

    end;

     

    procedure TForm1.FormCreate(Sender: TObject);

    begin

    Timer1.Enabled := false;

    Timer1.Interval := 100;

    Speed := 1;

    end;

     

    procedure TForm1.Timer1Timer(Sender: TObject);

    begin

    glClearColor(1.0, 1.0, 1.0, 1.0);

    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

    glEnable(GL_DEPTH_TEST);

     

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluPerspective(45.0, double(width) / height, 0.1, 100.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

     

    glTranslatef(0.0, 0.0,-6.0);

    glRotatef(cube_rotation, 1.0, 1.0, 1.0);

     

    glBegin(GL_QUADS);

    glColor3f(0.0,1.0,0.0); // Set The Color To Green

    glVertex3f( 1.0, 1.0,-1.0); // Top Right Of The Quad (Top)

    glVertex3f(-1.0, 1.0,-1.0); // Top Left Of The Quad (Top)

    glVertex3f(-1.0, 1.0, 1.0); // Bottom Left Of The Quad (Top)

    glVertex3f( 1.0, 1.0, 1.0); // Bottom Right Of The Quad (Top)

    glEnd();

    glBegin(GL_QUADS);

    glColor3f(1.0,0.5,0.0); // Set The Color To Orange

    glVertex3f( 1.0,-1.0, 1.0); // Top Right Of The Quad (Bottom)

    glVertex3f(-1.0,-1.0, 1.0); // Top Left Of The Quad (Bottom)

    glVertex3f(-1.0,-1.0,-1.0); // Bottom Left Of The Quad (Bottom)

    glVertex3f( 1.0,-1.0,-1.0); // Bottom Right Of The Quad (Bottom)

    glEnd();

    glBegin(GL_QUADS);

    glColor3f(1.0,0.0,0.0); // Set The Color To Red

    glVertex3f( 1.0, 1.0, 1.0); // Top Right Of The Quad (Front)

    glVertex3f(-1.0, 1.0, 1.0); // Top Left Of The Quad (Front)

    glVertex3f(-1.0,-1.0, 1.0); // Bottom Left Of The Quad (Front)

    glVertex3f( 1.0,-1.0, 1.0); // Bottom Right Of The Quad (Front)

    glEnd();

    glBegin(GL_QUADS);

    glColor3f(1.0,1.0,0.0); // Set The Color To Yellow

    glVertex3f( 1.0,-1.0,-1.0); // Bottom Left Of The Quad (Back)

    glVertex3f(-1.0,-1.0,-1.0); // Bottom Right Of The Quad (Back)

    glVertex3f(-1.0, 1.0,-1.0); // Top Right Of The Quad (Back)

    glVertex3f( 1.0, 1.0,-1.0); // Top Left Of The Quad (Back)

    glEnd();

    glBegin(GL_QUADS);

    glColor3f(0.0,0.0,1.0); // Set The Color To Blue

    glVertex3f(-1.0, 1.0, 1.0); // Top Right Of The Quad (Left)

    glVertex3f(-1.0, 1.0,-1.0); // Top Left Of The Quad (Left)

    glVertex3f(-1.0,-1.0,-1.0); // Bottom Left Of The Quad (Left)

    glVertex3f(-1.0,-1.0, 1.0); // Bottom Right Of The Quad (Left)

    glEnd();

    glBegin(GL_QUADS);

    glColor3f(1.0,0.0,1.0); // Set The Color To Violet

    glVertex3f( 1.0, 1.0,-1.0); // Top Right Of The Quad (Right)

    glVertex3f( 1.0, 1.0, 1.0); // Top Left Of The Quad (Right)

    glVertex3f( 1.0,-1.0, 1.0); // Bottom Left Of The Quad (Right)

    glVertex3f( 1.0,-1.0,-1.0); // Bottom Right Of The Quad (Right)

    glEnd();

     

    cube_rotation += 5.15 * Speed;

     

     

    OpenGLControl1.SwapBuffers;

    end;

     

    end.

    http://grafika.me/files/les_screens/matrix_opengl_laz.jpg

    Комментарии


    nik_1 аватар

    Опубликовано nik_1 в 3. Июль 2016 - 17:48.

    Timer1 - выдает ошибку. Использовал IdleTimer1, работает!

    unit Unit1;

    {$mode objfpc}{$H+}

    interface

    uses
    Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
    ExtCtrls, OpenGLContext, GL, GLU;

    type

    { TForm1 }

    TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    IdleTimer1: TIdleTimer;
    Panel1: TPanel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure IdleTimer1Timer(Sender: TObject);
    private
    { private declarations }
    public
    { public declarations }
    OpenGLControl1: TOpenGLControl; // Контекст воспроизведения OpenGL
    cube_rotation: GLFloat;
    Speed: Double;
    end;

    var
    Form1: TForm1;

    implementation

    {$R *.lfm}

    { TForm1 }

    procedure TForm1.Button1Click(Sender: TObject);
    begin

    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, double(width) / height, 0.1, 100.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTranslatef(0.0, 0.0,-6.0);
    glRotatef(cube_rotation, 1.0, 1.0, 1.0);

    glBegin(GL_QUADS);
    glColor3f(0.0,1.0,0.0); // Set The Color To Green
    glVertex3f( 1.0, 1.0,-1.0); // Top Right Of The Quad (Top)
    glVertex3f(-1.0, 1.0,-1.0); // Top Left Of The Quad (Top)
    glVertex3f(-1.0, 1.0, 1.0); // Bottom Left Of The Quad (Top)
    glVertex3f( 1.0, 1.0, 1.0); // Bottom Right Of The Quad (Top)
    glEnd();
    glBegin(GL_QUADS);
    glColor3f(1.0,0.5,0.0); // Set The Color To Orange
    glVertex3f( 1.0,-1.0, 1.0); // Top Right Of The Quad (Bottom)
    glVertex3f(-1.0,-1.0, 1.0); // Top Left Of The Quad (Bottom)
    glVertex3f(-1.0,-1.0,-1.0); // Bottom Left Of The Quad (Bottom)
    glVertex3f( 1.0,-1.0,-1.0); // Bottom Right Of The Quad (Bottom)
    glEnd();
    glBegin(GL_QUADS);
    glColor3f(1.0,0.0,0.0); // Set The Color To Red
    glVertex3f( 1.0, 1.0, 1.0); // Top Right Of The Quad (Front)
    glVertex3f(-1.0, 1.0, 1.0); // Top Left Of The Quad (Front)
    glVertex3f(-1.0,-1.0, 1.0); // Bottom Left Of The Quad (Front)
    glVertex3f( 1.0,-1.0, 1.0); // Bottom Right Of The Quad (Front)
    glEnd();
    glBegin(GL_QUADS);
    glColor3f(1.0,1.0,0.0); // Set The Color To Yellow
    glVertex3f( 1.0,-1.0,-1.0); // Bottom Left Of The Quad (Back)
    glVertex3f(-1.0,-1.0,-1.0); // Bottom Right Of The Quad (Back)
    glVertex3f(-1.0, 1.0,-1.0); // Top Right Of The Quad (Back)
    glVertex3f( 1.0, 1.0,-1.0); // Top Left Of The Quad (Back)
    glEnd();
    glBegin(GL_QUADS);
    glColor3f(0.0,0.0,1.0); // Set The Color To Blue
    glVertex3f(-1.0, 1.0, 1.0); // Top Right Of The Quad (Left)
    glVertex3f(-1.0, 1.0,-1.0); // Top Left Of The Quad (Left)
    glVertex3f(-1.0,-1.0,-1.0); // Bottom Left Of The Quad (Left)
    glVertex3f(-1.0,-1.0, 1.0); // Bottom Right Of The Quad (Left)
    glEnd();
    glBegin(GL_QUADS);
    glColor3f(1.0,0.0,1.0); // Set The Color To Violet
    glVertex3f( 1.0, 1.0,-1.0); // Top Right Of The Quad (Right)
    glVertex3f( 1.0, 1.0, 1.0); // Top Left Of The Quad (Right)
    glVertex3f( 1.0,-1.0, 1.0); // Bottom Left Of The Quad (Right)
    glVertex3f( 1.0,-1.0,-1.0); // Bottom Right Of The Quad (Right)
    glEnd();

    cube_rotation += 5.15 * Speed;

    OpenGLControl1.SwapBuffers;

    end;

    procedure TForm1.Button2Click(Sender: TObject);
    begin
    if IdleTimer1.Enabled = true then
    begin
    IdleTimer1.Enabled := false;
    Button2.Caption:='Вращать автоматически';
    end
    else
    begin
    IdleTimer1.Enabled := true;
    Button2.Caption:='Остановить вращение';
    end;
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    // Создание контекста воспроизведения OpenGL и привязка его к панели на форме
    OpenGLControl1:=TOpenGLControl.Create(Self);
    with OpenGLControl1 do begin
    Name:='OpenGLControl1';
    Align:=alClient;
    Parent:=Panel1;
    end;

    IdleTimer1.Enabled := false;
    IdleTimer1.Interval := 100;
    Speed := 1;

    Button2.Caption:='Вращать автоматически';
    Button1.Caption:='Повернуть';
    end;

    procedure TForm1.IdleTimer1Timer(Sender: TObject);
    begin
    Button1Click(Sender);
    end;

    end.

    ujif аватар

    Опубликовано ujif в 2. Июнь 2015 - 13:14.

    можно ли вращать этот куб без таймера, только кликая по
    кнопке ?

    admin аватар

    Опубликовано admin в 2. Июнь 2015 - 18:55.

    Можно. Перенесите код из процедуры Timer1Timer в Процедуру ButtonClick1. Timer Удалите.


    1   2   3   4   5   6


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