Шаг 28 - Масштаб и поворот

В этом шаге мы посмотрим как в OpenGL производится масштабирование и поворот объекта.

Для нагдядности этих операций сделаем приложение с диалогом, в котором мы будем задавать масштабы по X,Y и угол поворота относительно оси Z (которая, кстати, идет из ваших глаз в глубь экрана)

Как обычно создадим проект. Добавим в проект диалог с тремя вышеупомянутыми полями.

Свяжем с этими полями соответствующие переменные (при этом создав класс диалога). Добавим пункт меню View->Transformation, дав ему какой-либо идентификатор. Для упрощения жизни добавим кнопочку на toolbar, связав ее с идентификатором сделаного меню. И, наконец, сделаем обработчик нашего пункта меню.

void CExampleView::OnViewTrans() 
{
	// TODO: Add your command handler code here
	CScaleDlg dlg;

	if(dlg.DoModal()==IDOK)
	{
		m_Scale_X = dlg.m_Edit_X;
		m_Scale_Y = dlg.m_Edit_Y;
		m_Angle = dlg.m_Angle;
	}

	if(m_Scale_X=="" || m_Scale_Y=="" || m_Angle=="")
	{
		AfxMessageBox("You must enter values", MB_OK);
		return;
	}

	m_fScale_X = (float)atof((LPCTSTR)m_Scale_X);
	m_fScale_Y = (float)atof((LPCTSTR)m_Scale_Y);
	m_fAngle = (float)atof((LPCTSTR)m_Angle);

	InvalidateRect(NULL, FALSE);
}

Для того, чтобы заработал данный код вам понадобится включить в файл C...View.cpp заголовочные файлы класса диалога, который мы недавно создали и создать несколько переменных, в которые мы занесем данные из переменных диалога.

В переменные m_Scale_X, m_Scale_Y и m_Angle мы занесем данные из переменных диалога, а в переменные m_fScale_X, m_fScale_Y, m_fAngle занесем численное значение, полученное из строковых переменных с помощью функции atof(...).

Конечно, можно было бы и не создавать строковые переменные, но мы сейчас не гоняемся за оптимальностью кода. Главное, чтобы было понятно.

Теперь обратимся к тому, ради чего все делаем, к функции OnDraw(...):

void CExampleView::OnDraw(CDC* pDC)
{
	CRect clientRect;

	CExampleDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	// TODO: add draw code for native data here
	GetClientRect(&clientRect);
	glViewport(0, 0, clientRect.right, clientRect.bottom);

	glClearColor (0.5, 0.5, 0.75, 1.0);	// цвет фона
	glClear (GL_COLOR_BUFFER_BIT);	// очистка буфера цвета

	glColor3f (1.0, 0.0, 0.5);		// текущий цвет примитивов

	glPushMatrix();

	glRotatef(m_fAngle, 0.0f, 0.0f, 1.0f);
	glScalef(m_fScale_X, m_fScale_Y, 1.0f);

	glRectf(-0.5f, 0.5, 0.5f, -0.5f);

	glPopMatrix();

	SwapBuffers(pDC->m_hDC);
}

Мне кажется, что комментарии тут излишни. Вращение задается функцией glRotatef(...), где первый аргумент это угол поворота против часовой стрелки, а остальные три показывают относительно каких осей координат будет производится поворот на заданный угол. В последних 3-х аргументах имеет значение только знак, абсолютное значение роли не играет.

С масштабом все граздо проще. Каждый аргумент - масштаб по соответствующей оси. Последняя функция - glRect(...) это просто замена блока

glBegin(GL_QUADS);
	glVertex2f(-0.5, 0.5)
	glVertex2f(0.5, 0.5);
	glVertex2f(0.5, -0.5);
	glVertex2f(-0.5, -0.5);
glEnd();

Это, так сказать, для ленивых. Если посмотреть повнимательнее, то в OnDraw есть еще 2 команды: PopMatrix и PushMatrix. Более подробно мы встретимся с этими командами в разделе 3D, но смысл этих команд очень прост. Перед началом рисования мы как бы сохраняем текущее состояние сцены, т.е. состояние по умолчанию. При этом используется так называемый стек матриц. Попробуйте убрать эти команды из программы и посмотреть, что получится.

Шпаргалка

  1. Создать проект
  2. Сделать диалог со своими переменными и создать класс диалога
  3. Получить данные из диалога и преобразовать их в числовой вид
  4. Произвести поворот и масштабирование в функции OnDraw(...)

Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Kirill V. Ratkin.