Работа с простой графикой и OpenGL. Delphi (Lazarus)
Скачать 0.56 Mb.
|
Вращение, движение, масштабирование и проекции в OpenGL под Lazarus5. Май 2014 - 18:45 | admin Среда программирования: Delphi (Lazarus) В OpenGL используются основные три системы координат: левосторонняя, правосторонняя и оконная. Первые две системы являются трехмерными и отличаются друг от друга направлением оси z: в правосторонней она направлена на наблюдателя, в левосторонней – в глубину экрана. Ось x направлена вправо относительно наблюдателя, ось y – вверх. Системы координат в 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 существуют стандартные команды для задания ортографической (параллельной) и перспективной проекций. Первый тип проекции может быть задан командами void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) 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. КомментарииОпубликовано 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 в 2. Июнь 2015 - 13:14. можно ли вращать этот куб без таймера, только кликая по кнопке ? Опубликовано admin в 2. Июнь 2015 - 18:55. Можно. Перенесите код из процедуры Timer1Timer в Процедуру ButtonClick1. Timer Удалите. |