Уроки Коммент.

Создание игр » Featured, Теория » Навигация в трёхмерном пространстве

Навигация в трёхмерном пространстве

Навигация в 3д-миреНавигация в трёхмерном пространстве часто представляет собой проблему для начинающих программистов. Особенно, для тех, кто не до конца понимает как работают матрицы, либо просто не догадывается, что они содержат в себе практически готовое решение их проблемы. Часто для навигации в 3D программисты берут единичные вектора и, путём умножения их на матрицу вида камеры, получают вектора для навигации. Однако, если немного разобраться в проблеме и попытаться математически прикинуть решение задачи, оказывается, что даже эти вычисления совершенно лишние и что вектора для навигации уже содержатся в используемых матрицах и надо лишь знать, откуда их извлечь, и не более того.

В предыдущих уроках по матрицам (см. Урок “Матрицы”) я уже объяснял, что любая матрица трансформации есть ни что иное, как три вектора-базиса. Каждый из этих векторов является вектором, задающим ось координат “нового пространства” в “старом пространстве”. При этом, как обычно, один из этих векторов направлен (в новом пространстве) вбок, один вверх(либо вниз), а третий либо к “камере”, либо от неё.

Для навигации в трёхмерном пространстве, обычно так же необходимо иметь всего три вектора – один вбок (для стрейфа), один к камере либо от неё (что бы ходить вперёд/назад) и один вверх, либо вниз (для прыжков, например). Наблюдаете сходство с тем, что я написал в предыдущем абзаце? Проверим на практике, как оно работает?

Получение векторов для навигации в 3D

Итак, надеюсь, вы понимаете, что необходимые нам для навигации вектора мы можем извлечь непосредственно из матрицы трансформации объекта. Возможно, это стоило бы сделать для камеры, но, мне кажется, что в будущем нам понадобятся такие вектора и для других объектов, потому я реализовал эти методы в классе CEntity:

	D3DXVECTOR3 GetUp() const;
	D3DXVECTOR3 GetRight() const;
	D3DXVECTOR3 GetForward() const;

Вот как выглядит их исходный код:

D3DXVECTOR3 CEntity::GetUp() const
{
	D3DXVECTOR3 v(m_matrix._21, m_matrix._22, m_matrix._23);
	D3DXVec3TransformCoord(&v, &v, &GetParentMatrix());
	return v;
}
 
D3DXVECTOR3 CEntity::GetRight() const
{
	D3DXVECTOR3 v(m_matrix._11, m_matrix._12, m_matrix._13);
	D3DXVec3TransformCoord(&v, &v, &GetParentMatrix());
	return v;
}
 
D3DXVECTOR3 CEntity::GetForward() const
{
	D3DXVECTOR3 v(m_matrix._31, m_matrix._32, m_matrix._33);
	D3DXVec3TransformCoord(&v, &v, &GetParentMatrix());
	return v;
}

Использование векторов навигации для передвижения

Имея эти три вектора мы можем их использовать для движения, например, нашей камеры, скажем так:

void CTutorial3D::ProcessUserInput(float fDeltaTime)
{
	float fDelta = fDeltaTime*100;
 
	if (GetAsyncKeyState(VK_LEFT)&32768)
		m_camera.SetPos(m_camera.GetPos() - 
			m_camera.GetRight()*fDelta);
 
	if (GetAsyncKeyState(VK_RIGHT)&32768)
		m_camera.SetPos(m_camera.GetPos() + 
			m_camera.GetRight()*fDelta);
 
	if (GetAsyncKeyState(VK_DOWN)&32768)
		m_camera.SetPos(m_camera.GetPos() - 
			m_camera.GetForward()*fDelta);
 
	if (GetAsyncKeyState(VK_UP)&32768)
		m_camera.SetPos(m_camera.GetPos() + 
			m_camera.GetForward()*fDelta);
}

Собственно, вот Вам и готовое управление игровой камерой.

Исходники к статье.
Дема.

Ещё по этой теме:




Раздел: Featured, Теория · Теги: Создание движка

13 комментариев на "Навигация в трёхмерном пространстве"
  1. Scripter пишет:

    как всегда просто и поучительно :) спасибо.

  2. YuRik пишет:

    ваш блог гороздо интереснее читать, чем книги на ету тему:)

  3. Вячеслав пишет:

    Scripter, YuRik, спасибо :-)

  4. Antony пишет:

    Тут на вас уже ссылка есть в разделе полезных ресурсов.
    http://forum.vingrad.ru/forum/topic-252383.html
    Думаю, это приятно:)

    1. Вячеслав пишет:

      Да, очень приятно!
      Рад, что ресурс оказался кому-то полезен :-)

  5. Shadow пишет:

    Для меня эта тема с матрицами тоже пока остается нераскрытой. Прочитал у других авторов и не очень понял. Они и правда используют перемножения матриц. А я нашел вот такое (msdn):
    D3DXMatrixRotationX, D3DXMatrixRotationY и другие полезные преобразования. И пока не понятно, чем же эти способы отличаются от авторских? Почему некоторые предпочитают писать свои методы, а не использовать уже существующие в DirectX?

    1. Вячеслав пишет:

      Кому как удобнее – тот так и делает. Тут нет одного универсального способа, который идеально подходил бы во всех случаях. Где-то удобнее “вращать” текущую матрицу, где-то отталкиваться от векторов (вперёд/вверх/в сторону), где-то хранить углы (YawPitchRoll) и т.д.

      Эти “способы” ничем не отличаются “от авторских” – это всё один большой способ решить одну и ту же задачу разными путями и при этом то, насколько удобен тот иной путь, зависит от конкретной точки приложения (конкретной игры, конкретной игровой камеры, конкретного управления и так далее).

  6. Сергей пишет:

    Вячеслав, возможно вопрос не по теме но, допустим есть карта ландшафта, созданная в 3ds Max, как ее можно “подключить” к игре и там уже в игре перехватывать столкновения с объектами карты, реализовать ходьбу по поверхности, подъемы, спуски, так сказать сделать землю под ногами? Как можно будет различать объекты на карте, дерево это или здание, если они смоделированы таким способом.
    И еще один вопрос. Если делать генератор карт, то надо располагать уже существующие модели на генерируемой карте со всеми привязками к текстурам и ландшафт делать так, как генерируются вертексы?

    1. Вячеслав пишет:

      “Подключить” ландшафт к создаваемой вами игре можно, например, в виде модели – если позволяет полиогнальность. Либо ландшафт можно отрендерить (скажем в том же 3d max) ортогональной камерой в карту высот (в т.ч. можно в 32хбитную, если я правильно помню) и использовать эту карту. Разные есть варианты, в общем.

      После загрузки ландшафта, соответственно, просто создаёте физическую модель для него и после этого по нему можно будет “ходить”. Либо можно логику реализовать без сторонней физики – там ничего сложного нет, можно легко самостоятельно закодить всё за вечер.

      Не очень понял свзяь генерации ландшафта, расстоновки объектов и каких-то (не понял каких) “вертексов”… Объясните подробнее, пожалуйста.

      1. Сергей пишет:

        Можете посоветовать где можно почитать о “подключении” ландшафта или как это правильно называется, сам этот процесс, как создания карты, так и ее подключения, так и создания физической модели.
        На счет генерации ландшафта, вопрос состоял в том, как его сделать программно? И как там же расставить объекты, в процессе генерации или уже после.

        1. Вячеслав пишет:

          Где почитать о программировании ландшафтов – если честно, не знаю, особо достойных док не встречал. Но, по большому счёту, программирование отображения или физики ландшафта не отличается от любой другой модели (в простейшем случае) – тот же набор треугольников, которые надо просто отрисовать/просчитать коллизии.

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

          Если делать ландшафт “по-нормальному”, то для его редактирования проще всего либо написать собственный инструмент, либо использовать сторонние редакторы, заточенные именно под создание/генераци.ю/редактирование именно ландшафтов. Например, такие инструменты как L3DT.

          Расставлять объекты, опять же, проще всего в своём собственном редакторе. По своему опыту могу сказать, что если у Вас буду уже реализованные сам ландшафт и функции для отображения/трансформации объекты, то на этой базе создание собственного редактора для расстановки объектов займёт не более пары вечеров (если Вам достаточно минимального функционала).

          1. Сергей пишет:

            Спасибо, Вячеслав!

Оставить комментарий

*

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>