This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English

Камеры

Камера в Defold — это компонент, который изменяет область просмотра (viewport) и проекцию игрового мира. Компонент камеры определяет базовую перспективную или ортографическую камеру, которая предоставляет матрицы вида и проекции в рендер-скрипт.

Перспективная камера обычно используется для 3D-игр, где вид камеры и размер и перспектива объектов основаны на усечённой пирамиде (view frustum) и расстоянии и угле обзора от камеры до объектов в игре.

Для 2D-игр часто предпочтительно использовать ортографическую проекцию. Это означает, что вид камеры больше не определяется усечённой пирамидой, а ограничен параллелепипедом. Ортографическая проекция нереалистична, так как не изменяет размер объектов в зависимости от расстояния. Объект на расстоянии 1000 единиц будет отображаться того же размера, что и объект прямо перед камерой.

projections

Создание камеры

Чтобы создать камеру, кликните правой кнопкой мыши по игровому объекту и выберите Add Component ▸ Camera. Также можно создать файл компонента камеры в иерархии проекта и добавить его к игровому объекту.

create camera component

Компонент камеры имеет следующие свойства, определяющие усечённую пирамиду камеры:

camera settings

Id
Идентификатор компонента
Aspect Ratio
(Только для перспективной камеры) — соотношение ширины и высоты усечённой пирамиды. 1.0 означает квадратный вид. 1.33 подходит для соотношения 4:3, например 1024x768. 1.78 — для 16:9. Это значение игнорируется, если включён Auto Aspect Ratio.
Fov
(Только для перспективной камеры) — вертикальный угол обзора камеры в радианах. Чем шире угол обзора, тем больше камера видит.
Near Z
Z-значение ближней плоскости отсечения.
Far Z
Z-значение дальней плоскости отсечения.
Auto Aspect Ratio
(Только для перспективной камеры) — если включено, камера автоматически вычисляет соотношение сторон.
Orthographic Projection
Включите, чтобы использовать ортографическую проекцию (см. ниже).
Orthographic Zoom
(Только для ортографической камеры) — масштаб ортографической проекции (> 1 = приближение, < 1 = отдаление).

Использование камеры

Все камеры по умолчанию включены и обновляются каждый кадр, а Lua-модуль camera доступен во всех скриптовых контекстах. Начиная с Defold 1.8.1, больше не нужно явно включать камеру через отправку сообщения acquire_camera_focus компоненту камеры. Старые сообщения acquire и release всё ещё поддерживаются, но рекомендуется использовать сообщения enable и disable, как для любого другого компонента, который нужно включать или выключать:

msg.post("#camera", "disable")
msg.post("#camera", "enable")

Чтобы получить список всех доступных камер, используйте функцию camera.get_cameras():

-- Внимание: вызовы render доступны только в рендер-скрипте.
-- camera.get_cameras() можно использовать везде,
-- но render.set_camera — только в рендер-скрипте.

for k,v in pairs(camera.get_cameras()) do
	-- таблица camera содержит URL всех камер
	render.set_camera(v)
	-- здесь выполняется рендеринг — всё, что использует материалы с
	-- матрицами вида и проекции, будет использовать матрицы этой камеры.
end
-- чтобы отключить камеру, передайте nil (или вызовите без аргументов) в render.set_camera.
-- после этого все вызовы рендеринга будут использовать матрицы вида и проекции,
-- заданные напрямую в рендер-контексте через render.set_view и render.set_projection
render.set_camera()

Модуль camera содержит множество функций для управления камерой. Вот несколько из них, полный список доступен в API документации:

camera.get_aspect_ratio(camera)        -- получить соотношение сторон
camera.get_far_z(camera)               -- получить дальнюю плоскость отсечения
camera.get_fov(camera)                 -- получить угол обзора
camera.set_aspect_ratio(camera, ratio) -- установить соотношение сторон
camera.set_far_z(camera, far_z)        -- установить дальнюю плоскость отсечения
camera.set_near_z(camera, near_z)      -- установить ближнюю плоскость отсечения
... и другие

Камера идентифицируется URL, который представляет полный путь к компоненту в сцене, включая коллекцию, игровой объект и id компонента. В примере используйте URL /go#camera для доступа к компоненту камеры из той же коллекции, и main:/go#camera для доступа к камере из другой коллекции или рендер-скрипта.

create camera component

-- Доступ к камере из скрипта в той же коллекции:
camera.get_fov("/go#camera")

-- Доступ к камере из скрипта в другой коллекции:
camera.get_fov("main:/go#camera")

-- Доступ к камере из рендер-скрипта:
render.set_camera("main:/go#camera")

Каждый кадр компонент камеры с текущим фокусом камеры отправляет сообщение set_view_projection на сокет “@render”:

-- builtins/render/default.render_script
--
function on_message(self, message_id, message)
	if message_id == hash("set_view_projection") then
		self.view = message.view                    -- [1]
		self.projection = message.projection
	end
end
  1. Сообщение от компонента камеры содержит матрицу вида и матрицу проекции.

Компонент камеры предоставляет рендер-скрипту матрицу проекции перспективной или ортографической камеры в зависимости от свойства Orthographic Projection. Матрица проекции учитывает ближнюю и дальнюю плоскости отсечения, угол обзора и соотношение сторон камеры.

Матрица вида определяет позицию и ориентацию камеры. Камера с Orthographic Projection центрирует вид на позиции игрового объекта, к которому прикреплён компонент камеры, тогда как камера с Perspective Projection располагает нижний левый угол вида на позиции игрового объекта.

Рендер-скрипт

Начиная с Defold 1.9.6, при использовании дефолтного рендер-скрипта Defold автоматически устанавливает последнюю включённую камеру для рендеринга. Ранее требовалось явно отправлять сообщение use_camera_projection рендереру, чтобы уведомить его об использовании матриц камеры. Сейчас это не обязательно, но для обратной совместимости можно продолжать использовать.

Также можно явно задать конкретную камеру для рендеринга в рендер-скрипте. Это полезно, например, в многопользовательских играх для точного контроля, какая камера используется.

-- render.set_camera автоматически применит матрицы вида и проекции
-- для всего рендеринга, пока не будет вызван render.set_camera() без аргументов.
render.set_camera("main:/my_go#camera")

Чтобы проверить, включена ли камера, используйте функцию get_enabled из Camera API:

if camera.get_enabled("main:/my_go#camera") then
	-- камера включена, используем её для рендеринга
	render.set_camera("main:/my_go#camera")
end

Чтобы использовать set_camera вместе с отсечением по усечённой пирамиде (frustum culling), передайте опцию: render.set_camera("main:/my_go#camera", {use_frustum = true})

Панорамирование камеры

Перемещайте камеру по игровому миру, перемещая игровой объект, к которому прикреплён компонент камеры. Компонент автоматически отправит обновлённую матрицу вида на основе текущих координат по осям X и Y.

Масштабирование камеры

Для перспективной камеры масштабирование происходит перемещением игрового объекта по оси Z. Компонент камеры автоматически обновит матрицу вида с учётом текущей позиции по Z.

Для ортографической камеры масштабирование выполняется изменением свойства Orthographic Zoom:

go.set("#camera", "orthographic_zoom", 2)

Адаптивный зум

Адаптивный зум — это изменение значения зума камеры при изменении разрешения экрана относительно первоначального разрешения, заданного в game.project.

Два распространённых подхода к адаптивному зуму:

  1. Максимальный зум — вычисляется так, чтобы контент, покрываемый изначальным разрешением, заполнял и выходил за границы экрана, возможно, скрывая часть контента по бокам или сверху/снизу.
  2. Минимальный зум — вычисляется так, чтобы контент изначального разрешения полностью помещался в экран, возможно, показывая дополнительный контент по бокам или сверху/снизу.

Пример:

local DISPLAY_WIDTH = sys.get_config_int("display.width")
local DISPLAY_HEIGHT = sys.get_config_int("display.height")

function init(self)
	local initial_zoom = go.get("#camera", "orthographic_zoom")
	local display_scale = window.get_display_scale()
	window.set_listener(function(self, event, data)
		if event == window.WINDOW_EVENT_RESIZED then
			local window_width = data.width
			local window_height = data.height
			local design_width = DISPLAY_WIDTH / initial_zoom
			local design_height = DISPLAY_HEIGHT / initial_zoom

			-- max zoom: контент изначального разрешения заполнит и выйдет за границы экрана
			local zoom = math.max(window_width / design_width, window_height / design_height) / display_scale

			-- min zoom: контент изначального разрешения полностью поместится в экран
			--local zoom = math.min(window_width / design_width, window_height / design_height) / display_scale
			
			go.set("#camera", "orthographic_zoom", zoom)
		end
	end)
end

Полный пример адаптивного зума доступен в этом примерном проекте.

Следование за игровым объектом

Камера может следовать за игровым объектом, если сделать игровой объект с компонентом камеры дочерним по отношению к объекту, за которым нужно следить:

follow game object

Альтернативный способ — обновлять позицию игрового объекта с компонентом камеры каждый кадр в соответствии с позицией объекта, за которым следят.

Преобразование мыши в мировые координаты

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

--- Преобразует экранные координаты в мировые с учётом
-- вида и проекции конкретной камеры
-- @param camera URL камеры для преобразования
-- @param screen_x экранная координата X
-- @param screen_y экранная координата Y
-- @param z опциональный Z для преобразования, по умолчанию 0
-- @return world_x мировая координата X
-- @return world_y мировая координата Y
-- @return world_z мировая координата Z
function M.screen_to_world(camera, screen_x, screen_y, z)
	local projection = go.get(camera, "projection")
	local view = go.get(camera, "view")
	local w, h = window.get_size()
	-- window.get_size() возвращает масштабированный размер окна,
	-- учитывая дисплейный масштаб (например, Retina на macOS).
	-- Нужно скорректировать размер с учётом масштаба.
	local scale = window.get_display_scale()
	w = w / scale
	h = h / scale

	-- https://defold.com/ru/manuals/camera/#converting-mouse-to-world-coordinates
    local inv = vmath.inv(projection * view)
    local x = (2 * screen_x / w) - 1
    local y = (2 * screen_y / h) - 1
    local x1 = x * inv.m00 + y * inv.m01 + z * inv.m02 + inv.m03
    local y1 = x * inv.m10 + y * inv.m11 + z * inv.m12 + inv.m13
    return x1, y1, z or 0
end

На странице Примеры показано использование преобразования экранных координат в мировые. Также есть примерный проект с демонстрацией этого процесса.

Сторонние решения для камеры предоставляют функции для преобразования координат между экраном и миром.

Манипуляции во время выполнения

Камеры можно изменять из кода с помощью различных сообщений и свойств (подробности в API документации).

Компонент камеры имеет следующие свойства, которые можно читать и изменять через go.get() и go.set():

fov
Угол обзора камеры (number).
near_z
Ближняя плоскость отсечения (number).
far_z
Дальняя плоскость отсечения (number).
orthographic_zoom
Масштаб ортографической камеры (number).
aspect_ratio
Добавлено в Defold 1.4.8. Соотношение ширины и высоты усечённой пирамиды. Используется при вычислении проекции перспективной камеры. (number).
view
Добавлено в Defold 1.4.8. Вычисленная матрица вида камеры. ТОЛЬКО ДЛЯ ЧТЕНИЯ. (matrix4).
projection
Добавлено в Defold 1.4.8. Вычисленная матрица проекции камеры. ТОЛЬКО ДЛЯ ЧТЕНИЯ. (matrix4).

Сторонние решения для камеры

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