Direct2D. Перспективная трансформация

Перспективная трансформация Direct2D

Перспективная проекция Direct2D отличается от перспективной трансформации «по четырем точкам» тем, что она строится по углам поворота вокруг осей X, Y, Z, учитывает смещения и точку вращения.

Эффект перспективной трансформации

В Direct2D перспективная трансформация представлена эффектом CLSID_D2D13DPerspectiveTransform. В предыдущей статье мы уже рассмотрели, что такое эффекты Direct2D и как их использовать.

По-прежнему, используем ID2D1DCRenderTarget. Рисуем прямо на канве pb: TPaintBox. Обработчик OnPaint выглядит так.

Тут комментариев больше, чем кода. Код на самом деле очень простой.

Получаем изображение, которое собираемся трансформировать, создаем эффект, инициализируем и рисуем. Теперь по свойствам.

Режим интерполяции

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_INTERPOLATION_MODE. В переменной FInterpolMode должно содержаться одно из следующих пяти значений:

D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR
Метод «ближайшего соседа» выбирает ближайшую единственную точку и использует ее, без учета остальных соседних пикселей. Это самый быстрый режим, но изображение получается невысокого качества.
D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_LINEAR
Использует четырехточечную выборку и линейную интерполяцию. Этот режим требует больше времени обработки, чем режим ближайшего соседа, но выводит изображение более высокого качества.
D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_CUBIC
Для интерполяции используется кубическое ядро из 16 точек. Самый долгий по времени режим, но при этом получается изображение более высокого качества.
D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR
Режим множественной выборки использует 4 выборки в одном пикселе для качественного сглаживания краев. Нужен, в основном, чтобы избавиться от «лесенок» на границах.
D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_ANISOTROPIC
Используется анизотропная фильтрация для выборки шаблона в соответствии с полученной в результате трансформации формой растрового изображения. Наиболее качественный и распространенный на сегодня метод обработки.

Режим границы

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_BORDER_MODE.

Определяет, как будет рассчитываться граница изображения, «лесенками» (D2D1_BORDER_MODE_HARD) или мягко, без резких переходов (D2D1_BORDER_MODE_SOFT). По умолчанию — D2D1_BORDER_MODE_SOFT.

Расстояние до плоскости проекции

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_DEPTH. FDepth имеет тип Single, не может быть равным нулю или отрицательным. Измеряется в DIP’ах.

В Direct2D координаты измеряются в единицах, называемых аппаратно-независимыми пикселями (DIP). DIP определяется как 1/96 логического дюйма. В Direct2D все операции рисования указываются в DIP, а затем масштабируются до текущего значения DPI.

Расстояние до плоскости определяет степень «перспективности» проекции. Если стоим слишком близко, проекция будет ярко выражена. Чем дальше от плоскости, тем перспектива естественней.

Рис.1. Depth = 100

Изображение имеет ширину 1200. На рис.1 мы стоим на расстоянии 100 от плоскости. По сути, упершись носом в эту плоскость.

Рис.2. Depth = 1000

Но при отдалении на 1000, как на рис.2, перспектива уже не так явно заметна. Угол поворота по Y один и тот же.

Положение наблюдателя по осям X и Y в 3D-сцене

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_PERSPECTIVE_ORIGIN. Определяет координаты наблюдателя в плоскости (X,Y).

От точки наблюдения естественным образом зависит и вид перспективной проекции. По сути, это камера. Можно сделать эффект «облета» камеры вокруг объекта. Полностью сделать облет не получится, т.к. свойство Depth не может быть отрицательным. Но эффектно из стороны в сторону пролететь вдоль плоскости вполне себе можно.

В большинстве случаев, имеет смысл выставлять значение свойства, равное центру изображения. Т.е. смотрим строго прямо, без излишеств и артхауса.

Углы поворота для осей X, Y, Z

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_ROTATION. Значение свойства — вектор TD2D_VECTOR_3F. Углы поворота задаются в градусах.

Вид проекции напрямую зависит от точки вращения.

Центральная точка вращения

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_ROTATION_ORIGIN . Значение свойства — вектор TD2D_VECTOR_3F, который содержит координаты точки.

Это точка, вокруг которой совершаются вращения, заданные свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_ROTATION. От ее выбора зависит и вид проекции, и траектория.

Чаще всего необходимо вращать изображения вокруг себя. В этом случае координаты устанавливаются в центр изображения, с указанием координаты z=0.

Рис.3. Угол поворота по X=-7, по Y=61. Точка вращения Z=0

На рис.3 изображение вращается вокруг себя. Точка вращения расположена на плоскости проекции, z=0. Сдвинем точку вращения «вглубь» экрана на -1000.

Рис.4. Угол поворота по X=-7, по Y=61. Точка вращения Z=-1000

Теперь на рис.4 изображение описывает круги вокруг точки вращения, уходя по орбите вглубь экрана. Видим, что увеличивая угол по Y, картинка будет «улетать» все дальше по орбите, демонстрируя обратную сторону, как на рис.5.

Рис.5. Угол поворота по X=-7, по Y=135. Точка вращения Z=-1000

Если сейчас вернуть точке вращения Z=0, вид станет таким.

Рис.6. Угол поворота по X=-7, по Y=135. Точка вращения Z=0

Выбор точки вращения основывается исключительно на здравом смысле и творческой задумке программиста.

Перенос перед поворотом плоскости проекции

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_LOCAL_OFFSET . Значение свойства — вектор TD2D_VECTOR_3F. Содержит координаты переноса.

На проекцию помимо точки вращения и углов поворота влияет расположение плоскости перед трансформацией. Зададим перенос {-300, 0.0, 0.0} для проекции на рис.6.

Рис.7. Угол поворота по X=-7, по Y=135. Точка вращения Z=0. Перенос на X=-300

Видим, что проекция как бы выдвинулась вперед, такое ощущение, что вращение теперь не по центру изображения. Обнулим все углы вращения.

Рис.8. Перенос на X=-300

На рис.8 видно, что действительно, теперь вращение будет не по центральной оси изображения. Точка вращения осталась прежней, а изображение сдвинулось влево на 300.

На рис.7 перспектива стала более выраженной, яркой. Привлекает внимание. Уменьшением расстояния до плоскости Depth такого не добиться. Пригодится для инфографики и презентаций.

Перенос после поворота плоскости проекции

Задается свойством D2D1_3DPERSPECTIVETRANSFORM_PROP_GLOBAL_OFFSET . Значение свойства — вектор TD2D_VECTOR_3F. Содержит значение смещений для переноса.

Просто переносит готовую проекцию согласно указанным смещениям. Что это значит. Если было задано смещение X=-300 до трансформации, и указано X=600 после трансформации, то визуально изображение сместится на 300 вправо от центральной линии.

В копилку

В ходе написания выяснил, что метод TDirect2DCanvas.StretchDraw раза в 3-4 медленнее, чем предложенный в коде метод через трансформацию масштаба + сдвиг.


Друзья, спасибо за внимание!

Впереди новые интересные эффекты.

Не пропустите, подписывайтесь на телегу. )))

Невозможно все вместить в статью. Если есть вопросы по коду или эффекту, с удовольствием отвечу.


Скачать

В целом, надо просто поэкспериментировать. В примере углы по X и Y можно менять мышью. Можно кнопками стрелок на клавиатуре. Двойной клик по центру откроет панель свойств. Повторный двойной клик — закроет. Клавиатура работает только при невидимой панели свойств. Ctrl+F12 покажет/уберет фон с городом.

Исходники (Delphi XE 7-10) 410 Кб

Исполняемый файл 1.28 Мб

Если при запуске будет такой вид, без надписей по бокам картинки, это означает, что у Вас Windows 7 и DirectX 10. Следовательно, нет ID2D1DeviceContext, нет D2D1Effect. О чем свидетельствует темно-красная надпись в нижней панели окна программы. То есть, эффект перспективной трансформации недоступен.

Необходимо накатить обновления из Windows Update. Есть инструкция для установки DirectX 11 под Windows 7. Должен быть предварительно установлен Service Pack 1.

Direct2D версии 1.0

5 3 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x
()
x