До сих пор для осуществления преобразований мы пользовались либо только достаточно простыми механизмами (сдвиг вектора), либо механизмами, которые нельзя применять повсеместно (кватернионы). Конечно у нас есть достаточно навороченный класс cVector, с помощью которого можно сдвигать и вращать вершины. Однако все эти преобразования будут выполняться на CPU и, следовательно, существенно тормозить нашу игру. У кватернионов те же недостатки. Поэтому сейчас настало время рассмотреть способ, с помощью которого можно осуществлять все преобразования практически даром!

    Речь пойдет о матричных преобразованиях, которые предоставляет нам в наше распоряжение OpenGL. В этой графической библиотеке реализовано три типа матриц: матрица проецирования, матрица вида, текстурная матрица. Сегодня речь пойдет только о матрице вида.

    Все эти три матрицы можно свободно изменять. Для начала нужно сообщить системе с каком матрицей мы будем работать. Сделать это можно вызвав функцию glMatrixMode:

    glMatrixMode( mode );
    // где mode это одно из следующих значений
    // GL_MODELVIEW – матрица вида
    // GL_PROJECTION – матрица проецирования
    // GL_TEXTURE – текстурная матрица

    С матрицей проецирования и текстурной матрицей все более менее понятно – они отвечают за проецирование (ортогональное, перспективное etc.) и модификацию текстурных координат. А вот матрица вида требует отдельного, более подробного объяснения. Дело в том что при рендеринге все вершины попадают на конвейер рендеринга в так называемом camera space'e. Это такое пространство, в котором ось OZ направлена в сторону противоположной направлению взгляда (ну и с помощью нормали вида достраиваются оси OX и OY), с началом координат в точке визирования (там где расположена камера). Поэтому если перед рендерингом поставить матрицу вида следующим образом:

    glMatrixMode( GL_MODELVIEW );

    // загрузка единичной матрицы
    glLoadIdentity();

    то вся выводимая геометрия будет выводиться непосредственно перед экраном а не там где ей положено быть. Для перевода координат геометрии из camera space'а в глобальные координаты, как раз и применяется матрица вида.

    После этого можно выбранную матрицу домножать справа на матрицы поворота, смещения или переноса:

    // поворот на угол angle (задается в градусах)
    // вокруг вектора ( vx , vy , vz )
    glRotatef( angle , vx , vy , vz );

    // перенос на вектор ( tx , ty , tz )
    glTranslatef( tx , ty , tz );

    // масштабирование по осям x, y, z
    // sx, sy, sz – масштабирующие коэффициенты 
    // по соответствующим осям
    glScalef( sx , sy , sz );

    К сожалению эти функции изменяют выбранную матрицу. Поэтому после окончания преобразований нужно возвращать измененную матрицу в исходное состояние. Можно было бы конечно высчитывать обратные матрицы, для выполнения обратных преобразований, но OpenGL предлагает другой, более простой и элегантный способ – стек матриц. Работа с ним осуществляется следующим образом – перед началом преобразований сохраняем матрицу в стеке, которую планируем изменять. Изменяем матрицу согласно нашим замыслам. Выполняем преобразование. Выталкиваем исходную матрицу из стека. Все просто! Работа со стеком осуществляется с помощью следующих функций:

    // помещение матрицы в стэк
    glPushMatrix();

    // выталкивание матрицы из стека
    glPopMatrix();

    При использовании преобразований следует помнить следующее правило: вектор домножается на матрицу справа, т.е. при перемножении справа стоит вектор, а слева – матрица. Таким образом, если у нас есть последовательность преобразований, то последовательность функций должна быть противоположной. Для большей ясности рассмотрим один пример: пускай у нас есть квадрат, центр которого расположен в начале координат. Нам надо этот квадрат поворачивать вокруг собственного центра, а затем, отодвинув его от начала координат на 3 единицы, повернуть его вокруг начала координат, ну и для большего интереса будем масштабировать этот квадрат. В качестве решения задачи имеем следующую последовательность преобразований:
1. масштабировать квадрат
2. повернуть квадрат вокруг своего центра
3. сдвинуть квадрат на 3 единицы
4. повернуть квадрат вокруг начала координат

    Теперь распишем вызовы соответствующих функций:

    glMatrixMode( GL_MODELVIEW );

    // вращение вокруг начала координат
    glRotatef( Angle , 0 , 0 , 1 );

    //сдвиг на 3 единицы
    glTranslatef( 3 , 0 , 0 );

    //вращение вокруг центра квадрата
    glRotatef( Angle++ , 0 , 0 , 1 );

    //масштабирование
    glScalef( Scale , Scale , 0 );

    Как видите, все согласно правилу.

    Вот пожалуй и все на сегодня, вроде все просто, однако если возникнут вопросы – пишите сами знаете куда )).

    ЗЫ исходные коды к данной статье прилагаются.

Добавить комментарий


Защитный код
Обновить