Главная
Матричные преобразования в OpenGL
- Информация о материале
- Автор: gdever
- Категория: OpenGL
- Просмотров: 23080
До сих пор для осуществления преобразований мы пользовались либо только достаточно простыми механизмами (сдвиг вектора), либо механизмами, которые нельзя применять повсеместно (кватернионы). Конечно у нас есть достаточно навороченный класс 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 );
Как видите, все согласно правилу.
Вот пожалуй и все на сегодня, вроде все просто, однако если возникнут вопросы – пишите сами знаете куда )).
ЗЫ исходные коды к данной статье прилагаются.
Камера в OpenGL (на кватернионах).
- Информация о материале
- Автор: gdever
- Категория: OpenGL
- Просмотров: 11449
Как вы наверное могли уже понять нам понадобятся кватернионы и классы для работы с DirectInput'ом (статьи по этим темам можно посмотреть на этом сайте в разделах Алгоритмы и DirectX->DirectInput8 соответственно). Поэтому приступим сразу к реализации камеры.
Первым делом нам надо настроить сопособ проецирования (между ортогональной проекцией и перспективной мы ни минуты не сомневаясь выберем последнюю). Делается это так:
//выбираем матрицу которую будем устанавливать glMatrixMode( GL_PROJECTION ); //загружаем единичную матрицу glLoadIdentity(); //устанавливаем перспективную проекцию с углом обзора в 60 градусов //ближней плоскостью отсечения на расстоянии 1 и дальней на расстоянии 1000 //здесь же 1.33 – это отношение ширины экрана к высоте (800/600) gluPerspective( 60 , 1.33 , 1 , 1000 );
Как вы видите мы здесь использовали функцию gluPerspective, которая как видно про префиксу «glu» является частью библиотеки утилит. Для того чтобы компиляция прошла без ошибок, вам надо будет подключить файл glu.h и либку glu32.lib. Например так:
#pragma comment ( lib , "glu32.lib" )
Реализация класса камеры.
class Camera{ public: Vector4 target , norm , eye; Camera( void ){} Camera( Vector4 e , Vector4 n , Vector4 t ){ eye = e; norm = n; target = t; } //basik movement functions void MoveLeft( void ); void MoveRight( void ); void MoveForward( void ); void MoveBackward( void ); void MoveUp( void ); void MoveDown( void ); //input functions void KeyboardInput( Keyboard & ); void MouseInput( Mouse & , int , int ); //init functions void ReInitCamera( void ); void InitCamera( Vector4 , Vector4 , Vector4 ); //camera rotation functions void SpinAlongY( float );//Y - norm };
Здесь поля target , norm , eye - это соответственно вектор направления взгляда, вектор вертикали вида, и координаты точки визирования. Для облегчения восприятия рекомендую обратить свой взор на рисунок:
Теперь быстренько пробежимся по методам класса. «Быстренко» потому что они до безобразия простые.
void Camera::MoveUp( void ){ eye += CAM_VELOSITY * norm; } void Camera::MoveDown( void ){ eye -= CAM_VELOSITY * norm; } void Camera::MoveLeft( void ){ eye += CAM_VELOSITY * ( norm * target ); } void Camera::MoveRight( void ){ eye += CAM_VELOSITY * ( target * norm ); } void Camera::MoveForward( void ){ eye += CAM_VELOSITY * target; } void Camera::MoveBackward( void ){ eye -= CAM_VELOSITY * target; } void Camera::KeyboardInput( cKeyboard &Keyboard ){ Keyboard.GetKeyboardState(); if( Keyboard.GetButtonState( DIK_W ) )MoveForward(); if( Keyboard.GetButtonState( DIK_S ) )MoveBackward(); if( Keyboard.GetButtonState( DIK_A ) )MoveLeft(); if( Keyboard.GetButtonState( DIK_D ) )MoveRight(); ReInitCamera(); } void Camera::ReInitCamera( void ){ glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluLookAt( eye.x , eye.y , eye.z , eye.x + target.x , eye.y + target.y , eye.z + target.z , norm.x , norm.y , norm.z ); } void Camera::InitCamera( cVector4 EYE , cVector4 TARGET , cVector4 NORM ){ eye = EYE; target = TARGET; norm = NORM; ReInitCamera(); } void Camera::SpinAlongX( float Angle ){ cQuaternion ry; ry.fRy( Angle ); target = ry * target; } void Camera::MouseInput( cMouse &Mouse , int SCREEN_WIDTH , int SCREEN_HEIGHT ){ float x( Mouse.GetOffset( 0 ) ); float AngleX( ( ( float ) -x ) / 300 ); SpinAlongX( AngleX ); SetCursorPos( SCREEN_WIDTH / 2 , SCREEN_HEIGHT / 2 ); ReInitCamera(); }
Здесь CAM_VELOSITY – это некоторая константа, которая хранит скорость перемещения камеры. Далее:
//сообщаем системе, что сейчас будем менять матрицу вида glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); //передаем параметры положения камеры gluLookAt( eye.x , eye.y , eye.z , eye.x + target.x , eye.y + target.y , eye.z + target.z , norm.x , norm.y , norm.z );
Вот вроде и все. Просто да?
Исходники можно скачать здесь.
Робин Гуд
- Информация о материале
- Автор: Labus
- Категория: Разное
- Просмотров: 19652
Серию обзоров фильмов открываю этой статьей. Это просто обзоры, не претендующие на рецензии. Здесь я буду высказывать свое личное отношение к тому или иному фильму, как простого зрителя. Целью ставлю просто ознакомить читателя с новинками и стоит ли на них идти в кино или можно посмотреть дома, или вообще не смотреть и не портить себе карму.
Нормальные формы баз данных ч.1
- Информация о материале
- Автор: gdever
- Категория: Создание ПО
- Просмотров: 47011
Ключ - поле записи, чьё значение уникально для всего набора записей, имеет значение отличное от NULL и неизменно на протяжении всей жизни записи.
Первая нормальная форма – любое поле любой записи хранит только одно значение.
Например, если в поле хранится список идентификаторов, разделённых запятыми, то это нарушение данного определения и база не находится в первой нормальной форме.
Вторая нормальная форма – БД находится в первой нормальной форме и любое неключевое поле полностью зависит от ключа.
Например, у нас есть запись с полями (Идентификатор, Название CD-Диска, Название группы), где ключом является поле «Идентификатор». При этом, очевидно, что поле «Название группы» зависит не только от «Идентификатора» но и от поля «Название CD-Диска». Поэтому такая БД не находится во второй нормальной форме.
Третья нормальная форма – БД находится во второй нормальной форме и нет неключевых полей зависящих от значения других неключевых полей.
Например, у нас в записи хранятся код региона и его название (помимо самих полей с информацией о CD-диске). Понятно, что название региона зависит от кода, и наоборот, поэтому такая БД не будет находиться в третьей нормальной фоме.
PS Ссылки по теме:
Нормальные формы баз данных ч.2
Отличие японского и китайского языков
- Информация о материале
- Автор: gdever
- Категория: Разное
- Просмотров: 59028
Иногда возникает вопрос - а что, мол общего/отличного в японском и китайском языках? Про то, что кто-то у кого-то позаимствовал иероглифы наслышаны многое, но этим знания по предмету исчерпываются. Дабы исправить этот пробел решил запостить то, что известно мне.
На самом деле между этими двумя языками больше различий чем общего. Из точек сопряжения можно действительно выделить китайские иероглифы, завезенные корейцами на японский архипелаг. Плюс чтение некоторых слов в некоторых случаях в японском языке - может использоваться китайское чтение. Понятно что произноситься китайские слова в речи японцев будут несколько по-другому. Кстати, китайцы до сих пор не упускают случая попенять японцам на это заимствование. Мол, можете сколько угодно со своим роботом Асимо выкоблучиваться, иероглифы-то все равно наши ))
Фишка японского (и одновременно одна из самых больших его задниц) заключается в том что практически любой иероглиф имеет как японское чтение так и китайское, а иногда несколько китайских и японских чтений (при этом эти чтения могут спокойно являться разными частями речи и существенно отличаться по смыслу). Наличие только китайского или японского чтения достаточно редко встречается. Если иероглиф употребляется самостоятельно, то используется японское чтение, а если в составе какого-либо слова то китайское. Как правило так, однако есть слова (и достаточно много), в которых этому правилу не следуют. Например "каратэ-до", "кара" и "тэ" это японские чтения иероглифов "пустой" и "рука", а "до" это китайское чтение иероглифа "путь". И такое веселье сплошь и рядом. Китайский, понятно, таких проблем лишен.
Далее. Языки принципиально разные по фонетике. Попробуйте посмотреть фильмы без дубляжа. Сразу заметите, что тональность китайского языка более высокая, речь, если можно так сказать, "чирикающая". Японский более низкий по тональности. То что в японском практически все слоги открытые делает речь похожей на журчащий ручей (откуда-то с другого сайта утащил эту метафору). Кстати о слогах - в китайском их более 400, а в японском на порядок меньше. Поэтому китайский очень музыкальный язык, в котором большую роль играет тонизация, ударение и прочие приблуды, недоступные всем кому медведь на ухо наступил. Помнится, видел где-то пример, как из слова shi написали рассказ (пару абзацев). Вполне связный и осмысленный. В японском с их небольшим набором звуков проблема прямо противоположная - повальная омонимия. Зачастую несколько слов с абсолютно разными значениями и написаниями читаются одинаково. Какое из них используется собеседником в каждом конкретном случае, удается понять только из контекста. Ну или если собеседник подскажет. Навскидку вот такой пример - "shin". Это может быть слово "бог", а может быть "новый". Иероглифы понятно разные.
Языки принадлежат разным типам. Китайский принадлежит типу изолирующих языков. Т.е. все слова являются неизменяемыми. Японский принадлежит агглютинативным языкам, т.е. словообразование осуществляется присоединением к корню или основе аффиксов, обозначающие какое-либо конкретное грамматическое значение. Например "hana[su]" - глагол "разговаривать", "hana[shi]" - отглагольное существительное "разговор". Славянские языки кстати являются флективными языками (т.е. в них все меняется в очень широком диапазоне). Ну и так по-мелочи - в японском есть времена а в китайском нет, в японском есть падежи а в китайском нет.
Ну и письменность в китайском и японском отличается. В первом случае письменность логографическая, т.е. одному знаку соответствует одно понятие. В случае с японским языком все несколько сложнее. По понятным причинам заимствованная письменность не могла идеально "лечь" на японский язык, поэтому японцам пришлось "доработать напильником", прибавив к китайскому набору иероглифов два силлабария - таблицы годзюон. Поэтому Японская письменность является хоть немного но более продвинутой.
Вот вкратце всё что мне было сказать.
Страница 7 из 8