Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2 - Преобразования модели и координат.doc
Скачиваний:
6
Добавлен:
19.07.2019
Размер:
126.98 Кб
Скачать

Министерство образования и науки Российской Федерации

КАЗАНСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ

им. А.Н.Туполева

Г.М. Набережнов, н.Н. Максимов Преобразования модели и координат

Методическое пособие

к лабораторным работам по курсу

«Компьютерная геометрия и графика»

Казань 2007

1. Преобразования модели, преобразования координат, локальные системы координат

Между парами функций glBegin() и glEnd() программистом создается поток вершин некоторого примитива, которые последовательно поступают на конвейер обработки. Самая первая операция обработки, которой вершины при этом подвергаются, - это аффинные преобразования матрицей моделирования-вида (VM). Эта матрица накапливает в себе все преобразования модели и вида, которые должны выполняться над вершиной.

Функция

void glMatrixMode (GLenum mode)

устанавливает в качестве текущей матрицу VM при параметре mode равном GL_MODELVIEW.

Функция

void glLoadIdentity (void) устанавливает текущую матрицу в 1.

В базовой библиотеке GL имеются такие функции преобразования модели:

1) void glTranslate{fd} ( TYPE x, TYPE y, TYPE z )

CT := CT*

2) void glRotate{fd} ( TYPE a, TYPE x, TYPE y, TYPE z )

CT := CT*R, R – матрица вращения, создается функций glRotate*( ).

3) void glScale{fd} ( TYPE x, TYPE y, TYPE z )

CT:=CT*

Пример 1:

glMatrixMode(GL_MODELVIEW); //Текущей устанавливается матрица VM, CT:=VM

glLoadIdentity( ); // VM:=1

glScalef( 1.5, 1.2, 1.0); // VM:=VM*MS, MS – матрица масштабирования, созданная функцией

glTranslatef(2.0, 2.0, 0.0); // VM:=VM*MT = MS* MT

glRotatef( 30.0, 0.0, 0.0, 1.0); // VM:=VM*MR = MS* MT* MR

. . . . . . .

glBegin(GL_POINTS);

glVertex*(A0);

glEnd( );

В этом примере над точкой A0 будут выполнены такие преобразования

A1 = VM*A0 = MS* MT* MR*A0.

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

Создать программу, рисующую Fig.1. Эта фигура получается если Fig.0 зеркально отобразить относительно оси x0 затем повернуть на угол 300 и наконец сместить на 4.5 и 8.0 ед. по осям x0 и y0.

Приведенная ниже программа решает эту задачу. Функция fig0( ) создает нашу фигуру в положении Fig.0. Выделенный жирным фрагмент программы устанавливает VM=T*R*S и затем эта матрица применяется ко всем точкам Fig.0. В результате фигура оказывается в положении Fig.1.

Пример 2.

#include <GL/glut.h>

#include <stdlib.h>

#include <math.h>

#include <windows.h>

#define PI 3.1459

GLfloat R=640.0/480; //Форматное соотношение

GLfloat w=40; //Ширина мирового окна

GLfloat h; //Высота мирового окна

GLfloat l, r, b, t; //Параметры мирового окна

GLfloat f=30.0 ;

void init(void)

{ h=w/R; l=-w/2; r=w/2; b=-h/2; t=h/2; //Расчет параметров мирового окна

glClearColor(1.0,1.0,0.0,0.0);

glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(l, r, b, t);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

void reshape(GLsizei W, GLsizei H)

{ if(R>W/H) glViewport(0,0,W,W/R);

else glViewport(0,0,H*R,H);

}

void showAxis(void)

{ glColor3f(0.0f,0.0f,1.0f);

glBegin(GL_LINES);

glVertex2f(0,0);

glVertex2f(0,t);

glVertex2f(0,0);

glVertex2f(r,0);

glEnd();

}

void fig0(void)

{ glColor3f(0.0,1.0,0.0);

glBegin(GL_LINE_LOOP);

glVertex2f(0.0,0.0);

glVertex2f(0.0,3.0);

glVertex2f(5.0,2.0);

glVertex2f(5.0,0.0);

glEnd();

}

void scene(void)

{ glClear(GL_COLOR_BUFFER_BIT);

showAxis();

fig0();

//glPushMatrix();

glTranslatef(4.5, 8.0, 0.0);

glRotatef(f, 0.0, 0.0, 1.0);

glScalef(1.0, -1.0, 1.0);

fig0();

//glPopMatrix( );

glFlush();

//glutSwapBuffers();

//f+=30; if(f==360) f=0;

//Sleep(200);

}

void main(int argc, char **argv)

{ glutInit(&argc, argv);

glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

//glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

glutInitWindowSize(640, 480);

glutInitWindowPosition(20, 20);

glutCreateWindow("Myprog");

glutReshapeFunc(reshape);

glutDisplayFunc(scene);

//glutIdleFunc(scene);

init();

glutMainLoop();

}

Некоторые дополнительные функции:

void glPushMatrix (void) – проталкивает текущую матрицу в стек матриц, текущая матрица всегда в вершине стека, т.о. после вызова этой функции, матрица, которая находится в вершине стека, идентична той, что под ней.

void glPopMatrix (void) – выталкивает данные из текущего стека матриц, замещая текущую матрицу на ту, что находится под ней.

void glutSwapBuffers (void) – буфер в котором выполнялось рисование делается отображаемым и наоборот.

void glutReshapeFunc (void (*func)(int width, int height) – регистрирует функцию func, которая должна вызываться всякий раз, когда изменяются размеры окна или оно перемещено. Параметр func есть указатель на функцию, которая ожидает два параметра: новые значения ширины width и высоты height окна.

void glutIdleFunc (void (*func)(void)) – регистрирует функцию, которая будет выполняться в отсутствии событий.

Как пользоваться этими функциями? Рассмотрим это на примере приведенной выше программы.

1) Наберите программу Пример 2 со всеми закомментированными строками. Выполните ее. На экране увидите изображение как на рис.1. Измените размер экранного окна, потянув мышкой за его границу. Вы увидите, что вся сцена изменит свое положение.

Причина этого в том, что при первом вызове функция scene( ) стартует при VM=1 и фигура в положении Fig.0 нарисуется при VM=1, а в положении Fig.1 при VM=T*R*S. При изменении размеров window будет заново вызвана функция scene( ) и она стартует уже при VM= T*R*S, а затем примет значение VM=VM*T*R*S =T*R*S*T*R*S. И так VM будет накапливать все предыдущие преобразования при каждом вызове функции scene( ).

Раскомментируйте строки glPushMatrix( ) и glPopMatrix( ) в функции scene( ) и заново запустите программу. Вы убедитесь, что сцена не будет изменяться при повторных вызовах функции scene( ). Функция glPushMatrix( ) при вызове scene( ) сохранит в стеке VM=1, затем установится VM = T*R*S, будет нарисована фигура в положении Fig.1, а затем функция glPopMatrix( ) вытолкнет из вершины стека текущую матрицу и заменит ее сохраненной VM=1. При этом, сколько бы раз мы не вызывали функцию scene( ), стартовать она будет всегда при VM=1.

2) Раскомментируйте строку glutIdleFunc(scene) в функции main( ) и строку f+=30; if(f==360) f=0; в функции scene( ) и запустите программу. Замысел здесь в том, чтобы scene( ) вызывалась постоянно и каждый раз с новым параметром f. Ожидаемый эффект – фигура в положении Fig.1 должна постоянно вращаться. Однако ожидаемого эффекта мы не достигнем – на экране будет мерцающее, плохо понятное изображение. Причина этого в том, что установлен режим использования одного буфера кадра как для рисования, так и для отображения (glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)), а новое рисование вызывается сразу же как завершено предыдущее.

3) Закомментируйте glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB), раскомментируйте glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB), раскомментируйте glutSwapBuffers(). Тем самым вы установите режим двойной буферизации (в одном буфере кадра выполняется рисование, другой отображается) и переключение буферов. На экране вы увидите устойчивую картинку сцены с быстро вращающейся фигурой в положении Fig.1.

4) Раскомментируйте строку Sleep(200) – это задержка. Так вы регулируете частоту смены кадров. Запустите программу и на экране вы увидите плавно вращающуюся фигуру в положении Fig.1.

Программу Пример 2 мы понимали таким образом:

- функция fig0( ) описывает фигуру в МСК в положении Fig.0, далее везде МСК будет обозначаться как СК0;

- последовательность вызовов, выделенная жирным в функции scene( ), формирует преобразование модели (матрицу VM), эквивалентное композиции масштабирования, вращения и затем перемещения, VM= T*R*S;

- применение полученной матрицы VM к fig0( ) переводит фигуру в положение Fig.1.

Эту же программу можно понимать и другим образом:

- функция fig0( ) описывает фигуру в некоторой локальной системе координат СКL;

- последовательность вызовов, выделенная жирным в функции scene( ), формирует матрицу VM, которую можно понимать как координатный фрейм FL0, эквивалентный композиции координатных фреймов FL0 =F10*F21*FL2, где F10 = T, F21=R, FL2=S.

- применение полученной матрицы VM к fig0( ) осуществляет преобразование координат вершин fig0( ) из СКL в СК0.

На Рис. 2 показана локальная СКL и все промежуточные в соответствии с преобразованием FL0 =F10*F21*FL2, при F10 = T, F21=R, FL2=S.