Всем привет! На связи Глеб, в предыдущей статье мы рассмотрели работу с объектами на Blender. Но для того, чтобы создать минимально жизнеспособный генератор, нужно разобраться в том, как работают камеры.

Получение доступа к камере
На сцене камера отображается, как обычный объект «bpy.types.Object». Мы можем менять стандартные свойства, которые рассмотрели в предыдущей статье. Но для камеры также определен набор специальных настроек: фокусное расстояние, размер сенсорной матрицы и прочие. Доступ к ним мы можем получить через класс «bpy.types.Camera».
В прошлой статье мы увидели, что у экземпляра «bpy.types.Object» есть свойство «data», в котором лежит экземпляр класса, предоставляющий доступ к специальным свойствам. Это как раз то, что нам нужно. Ведь в случае с камерой внутри «data» лежит тот самый объект с типом «bpy.types.Camera».

Поэтому, чтобы получить доступ к свойствам, которые мы упомянули ранее, нужно сделать следующее:
camera_object = bpy.data.objects['Camera'] camera = camera_object.data
Теперь через переменную «camera» мы можем получить доступ к следующим свойствам и методам. Часть из которых мы рассмотрим чуть позже.
Выбор основной камеры
Так как на сцене может быть несколько камер, нам нужно выбрать основную, с которой будет вестись съемка.
# Получаем сцену, с которой работаем scene = bpy.context.scene # Получаем камеру, которую будет использовать, как основную camera = bpy.data.objects['Camera'] # Устанавливаем камеру, как основную для этой сцены scene.camera = camera
Что видит камера?
Для настройки камеры полезно понять какие объекты попадают в её поле зрения. Для этого мы можем переключиться в режим «Camera view», которой покажет, что видит основная камера сцены.

Разрешение
В blender нет свойства, которое бы отвечало за разрешение конкретной камеры. Для этой цели мы будем использовать свойство рендеринга.
# Получаем настройки рендеринга для конкретной сцены render = bpy.context.scene.render # Меняем разрешение относительно осей x и y в пикселях render.resolution_x = 1920 render.resolution_y = 1080
Важно! Новое разрешение автоматически применится ко всем камерам.

На данный момент мы научились получать доступ к камере и менять разрешение. Пришло время разобраться со свойствами, которые предоставляет класс «bpy.types.Camera».
lens
Это свойство отвечает за фокусное расстояние. Единицей измерения является миллиметр.
camera = bpy.data.cameras['Camera'] camera.lens = 10

sensor_width / sensor_height
Помимо фокусного расстояния мы можем взаимодействовать с размером сенсорной матрицы. Как и в случае с фокусным расстоянием, единицей измерения является миллиметр. Размер матрицы удобно использовать, когда у нас есть реальная камера, свойства которой мы хотим воспроизвести при генерации данных.
camera = bpy.data.cameras['Camera'] camera.sensor_width = 32
shift_x / shift_y
Смысл этих свойств легче всего объяснить с помощью наглядного примера.


Единицы измерения этих свойств рассчитываются относительно наибольшей стороны кадра:
shift_in_pixels / max(resolution_x, resolution_y) <- Это формула
Допустим, разрешение 1920×1080 и мы хотим сместить кадр на 100 пикселей вправо и 200 пикселей вниз.
resolution = ( bpy.context.scene.render.resolution_x, bpy.context.scene.render.resolution_y ) shift_x_in_px = 100 shift_y_in_px = -200 camera = bpy.data.cameras[‘Camera’] camera.shift_x = shift_x_in_px / max(resolution) camera.shift_y = shift_y_in_px / max(resolution)
Проецирование точек на кадр
Зачастую, нам требуются получить координаты объектов изображенных на кадре. Для этой цели мы будем использовать функцию «world_to_camera_view», находящуюся в библиотеке «bpy_extras».
Эта функция получает на вход следующие аргументы:
-
scene [ bpy.types.Scene ]: используется для определения размера кадра
-
obj [ bpy.types.Object ]: Камера, с которой происходит съемка
-
coord [ mathutils.Vector ]: Координаты точки, которую мы хотим отобразить на кадр
В результате использования «world_to_camera_view» мы получим вектор, состоящий из 3 значений: координата по оси х, координата по оси y, дистанция от камеры до объекта.
from bpy_extras.object_utils import world_to_camera_view cube = bpy.data.objects['Cube'] scene = bpy.context.scene camera = bpy.data.objects['Camera'] world_to_camera_view(scene, camera, cube.location) # Vector((0.4990274906158447, 0.513164222240448, 11.256155967712402))

Наведение на объект
На этом этапе, мы хотим навести камеру на интересующий нас объект. Для решения этой задачи я нашел два решения.
Constraints
В blender есть встроенная возможность «приказать» камере отслеживать какой-то объект. Но стоит заметить, что камера будет наводиться на центр выбранного объекта.
# Получение доступа к объектам camera = bpy.data.objects[‘Camera’] target = bpy.data.objects[‘Cube’] # Создание ограничения constraint = camera.constraints.new(type=’TRACK_TO’) constraint.target = target

Есть и другие интересные ограничения, которые можно использовать при создании своего генератора. Подробнее об этом можно прочитать в документации.
mathutils.vector
Суть этого подхода в том, что мы рассчитываем угол, на который нужно повернуть камеру, чтобы она смотрела на точку, а затем производим поворот. В отличии от предыдущего подхода, мы передаем координату, а не объект. Это добавляет нам пространство для маневра. К примеру, мы можем навести камеру на один из углов куба.
# Функция для наведения def point_camera_at( camera: bpy.types.Object, target: mathutils.Vector, track_axis: str = 'Z', up_axis: str = 'Y' ): vector = camera.location - target camera.rotation_euler = vector.to_track_quat( track_axis, up_axis ).to_euler() # Получаем доступ к объектам camera = bpy.data.objects['Camera'] cube = bpy.data.objects['Cube'] # Получаем точки контура объекта cube. Используем функцию из предыдущей статьи. bbox = bounding_box_world(cube) # Наводим камеру на угол point_camera_at(camera, bbox[0])
Важно! Изменяя положение камеры через api, стоит обратить внимание на одну небольшую хитрость: после трансформации нужно вручную обновить состояние сцены. Если пропустить этот шаг, то функция «world_to_camera_view» будет возвращать проекции относительно старого положения и поворота.
# Обновляем состояние сцены bpy.context.view_layer.update()
The end
Blender мы в Friflex используем в рамках разработки наших продуктов по оцифровке спорта, в том числе idChess. И в серии статей на Хабр я делюсь своим опытом. В следующих материалах мы рассмотрим свойства источников света и работу с материалами через пользовательские свойства и драйверы и научимся загружать объекты из разных файлов и запускать рендеринг сцены через консоль.
Если вы работали с blender и хотите обсудить прочитанное или поделиться своим опытом и знаниями, жду вас в комментариях! Сделаем статью более полной и полезной для новичков.
ссылка на оригинал статьи https://habr.com/ru/company/friflex/blog/668978/
Добавить комментарий