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 единиц будет отображаться того же размера, что и объект прямо перед камерой.
Чтобы создать камеру, кликните правой кнопкой мыши по игровому объекту и выберите Add Component ▸ Camera. Также можно создать файл компонента камеры в иерархии проекта и добавить его к игровому объекту.
Компонент камеры имеет следующие свойства, определяющие усечённую пирамиду камеры:
Все камеры по умолчанию включены и обновляются каждый кадр, а 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
для доступа к камере из другой коллекции или рендер-скрипта.
-- Доступ к камере из скрипта в той же коллекции:
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
Компонент камеры предоставляет рендер-скрипту матрицу проекции перспективной или ортографической камеры в зависимости от свойства 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.
Два распространённых подхода к адаптивному зуму:
Пример:
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
Полный пример адаптивного зума доступен в этом примерном проекте.
Камера может следовать за игровым объектом, если сделать игровой объект с компонентом камеры дочерним по отношению к объекту, за которым нужно следить:
Альтернативный способ — обновлять позицию игрового объекта с компонентом камеры каждый кадр в соответствии с позицией объекта, за которым следят.
Когда камера смещена, масштабирована или изменена проекция с дефолтной ортографической 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
number
).view
matrix4
).projection
matrix4
).Существуют решения сообщества, которые реализуют распространённые функции, такие как тряска экрана, следование за объектами, преобразование экранных координат в мировые и многое другое. Их можно скачать с портала Defold Asset Portal:
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB