--- title: Компонент Camera brief: В данном руководстве описаны функциональные возможности компонента Camera в Defold. --- # Камеры Камера в Defold — это компонент, который изменяет область просмотра (viewport) и проекцию игрового мира. Компонент камеры определяет базовую перспективную или ортографическую камеру, которая предоставляет матрицы вида и проекции в рендер-скрипт. Перспективная камера обычно используется для 3D-игр, где вид камеры и размер и перспектива объектов основаны на усечённой пирамиде (view frustum) и расстоянии и угле обзора от камеры до объектов в игре. Для 2D-игр часто предпочтительно использовать ортографическую проекцию. Это означает, что вид камеры больше не определяется усечённой пирамидой, а ограничен параллелепипедом. Ортографическая проекция нереалистична, так как не изменяет размер объектов в зависимости от расстояния. Объект на расстоянии 1000 единиц будет отображаться того же размера, что и объект прямо перед камерой. ![projections](images/camera/projections.png) ## Создание камеры Чтобы создать камеру, кликните правой кнопкой мыши по игровому объекту и выберите Add Component ▸ Camera. Также можно создать файл компонента камеры в иерархии проекта и добавить его к игровому объекту. ![create camera component](images/camera/create.png) Компонент камеры имеет следующие свойства, определяющие *усечённую пирамиду* камеры: ![camera settings](images/camera/settings.png) 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 = отдаление). Orthographic Mode : (**Только для ортографической камеры**) — управляет тем, как ортографическая камера определяет зум относительно размера окна и ваших значений дизайна (`game.project` → `display.width/height`). - `Fixed` (постоянный зум): используется текущее значение `Orthographic Zoom`. - `Auto Fit` (вписать): автоматически подбирает зум так, чтобы вся дизайн-область помещалась в окно. Возможен дополнительный контент по бокам/сверху/снизу. - `Auto Cover` (заполнить): автоматически подбирает зум так, чтобы дизайн-область заполняла окно целиком. Возможна обрезка по бокам/сверху/снизу. Доступно только при включённой `Orthographic Projection`. ## Использование камеры Все камеры по умолчанию включены и обновляются каждый кадр, а Lua-модуль `camera` доступен во всех скриптовых контекстах. Начиная с Defold 1.8.1, больше не нужно явно включать камеру через отправку сообщения `acquire_camera_focus` компоненту камеры. Старые сообщения acquire и release всё ещё поддерживаются, но рекомендуется использовать сообщения `enable` и `disable`, как для любого другого компонента, который нужно включать или выключать: ```lua msg.post("#camera", "disable") msg.post("#camera", "enable") ``` Чтобы получить список всех доступных камер, используйте функцию `camera.get_cameras()`: ```lua -- Внимание: вызовы 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 документации](/ref/camera/): ```lua camera.get_aspect_ratio(camera) -- получить соотношение сторон camera.get_far_z(camera) -- получить дальнюю плоскость отсечения camera.get_fov(camera) -- получить угол обзора camera.get_orthographic_mode(camera) -- получить ортографический режим (одно из camera.ORTHO_MODE_*) camera.set_aspect_ratio(camera, ratio) -- установить соотношение сторон camera.set_far_z(camera, far_z) -- установить дальнюю плоскость отсечения camera.set_near_z(camera, near_z) -- установить ближнюю плоскость отсечения camera.set_orthographic_mode(camera, camera.ORTHO_MODE_AUTO_FIT) -- установить ортографический режим ... и другие ``` Камера идентифицируется URL, который представляет полный путь к компоненту в сцене, включая коллекцию, игровой объект и id компонента. В примере используйте URL `/go#camera` для доступа к компоненту камеры из той же коллекции, и `main:/go#camera` для доступа к камере из другой коллекции или рендер-скрипта. ![create camera component](images/camera/create.png) ```lua -- Доступ к камере из скрипта в той же коллекции: camera.get_fov("/go#camera") -- Доступ к камере из скрипта в другой коллекции: camera.get_fov("main:/go#camera") -- Доступ к камере из рендер-скрипта: render.set_camera("main:/go#camera") ``` Каждый кадр компонент камеры с текущим фокусом камеры отправляет сообщение `set_view_projection` на сокет "@render": ```lua -- 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` рендереру, чтобы уведомить его об использовании матриц камеры. Сейчас это не обязательно, но для обратной совместимости можно продолжать использовать. Также можно явно задать конкретную камеру для рендеринга в рендер-скрипте. Это полезно, например, в многопользовательских играх для точного контроля, какая камера используется. ```lua -- render.set_camera автоматически применит матрицы вида и проекции -- для всего рендеринга, пока не будет вызван render.set_camera() без аргументов. render.set_camera("main:/my_go#camera") ``` Чтобы проверить, включена ли камера, используйте функцию `get_enabled` из [Camera API](https://defold.com/ref/alpha/camera/#camera.get_enabled:camera): ```lua if camera.get_enabled("main:/my_go#camera") then -- камера включена, используем её для рендеринга render.set_camera("main:/my_go#camera") end ``` ::: sidenote Чтобы использовать `set_camera` вместе с отсечением по усечённой пирамиде (frustum culling), передайте опцию: `render.set_camera("main:/my_go#camera", {use_frustum = true})` ::: ### Панорамирование камеры Перемещайте камеру по игровому миру, перемещая игровой объект, к которому прикреплён компонент камеры. Компонент автоматически отправит обновлённую матрицу вида на основе текущих координат по осям X и Y. ### Масштабирование камеры Для перспективной камеры масштабирование происходит перемещением игрового объекта по оси Z. Компонент камеры автоматически обновит матрицу вида с учётом текущей позиции по Z. Для ортографической камеры масштабирование выполняется изменением свойства *Orthographic Zoom*: ```lua go.set("#camera", "orthographic_zoom", 2) ``` Также для ортографической камеры можно выбрать способ определения зума с помощью параметра `Orthographic Mode` или из кода: ```lua -- текущий режим (одно из: camera.ORTHO_MODE_FIXED, _AUTO_FIT, _AUTO_COVER) local mode = camera.get_orthographic_mode("#camera") -- включить режим "вписать" (contain), чтобы дизайн-область всегда полностью помещалась в окно camera.set_orthographic_mode("#camera", camera.ORTHO_MODE_AUTO_FIT) -- включить режим "заполнить" (cover), чтобы окно всегда было заполнено -- camera.set_orthographic_mode("#camera", camera.ORTHO_MODE_AUTO_COVER) -- вернуть "фиксированный" режим и управлять масштабом вручную через orthographic_zoom -- camera.set_orthographic_mode("#camera", camera.ORTHO_MODE_FIXED) ``` ### Адаптивный зум Адаптивный зум — это изменение значения зума камеры при изменении разрешения экрана относительно первоначального разрешения, заданного в *game.project*. Два распространённых подхода к адаптивному зуму: 1. Максимальный зум — вычисляется так, чтобы контент, покрываемый изначальным разрешением, заполнял и выходил за границы экрана, возможно, скрывая часть контента по бокам или сверху/снизу. 2. Минимальный зум — вычисляется так, чтобы контент изначального разрешения полностью помещался в экран, возможно, показывая дополнительный контент по бокам или сверху/снизу. Пример: ```lua 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 ``` Полный пример адаптивного зума доступен в [этом примерном проекте](https://github.com/defold/sample-adaptive-zoom). Примечание: Для ортографической камеры типичное поведение «вписать/заполнить» можно получить без пользовательского кода, установив `Orthographic Mode` в `Auto Fit` (вписать) или `Auto Cover` (заполнить). В этих режимах эффективный зум рассчитывается автоматически на основе размера окна и заданного разрешения дизайна. ### Следование за игровым объектом Камера может следовать за игровым объектом, если сделать игровой объект с компонентом камеры дочерним по отношению к объекту, за которым нужно следить: ![follow game object](images/camera/follow.png) Альтернативный способ — обновлять позицию игрового объекта с компонентом камеры каждый кадр в соответствии с позицией объекта, за которым следят. ### Преобразование мыши в мировые координаты Когда камера смещена, масштабирована или изменена проекция с дефолтной ортографической Stretch-проекцией, координаты мыши, получаемые в функции `on_input()`, больше не совпадают с мировыми координатами игровых объектов. Нужно вручную учитывать изменения вида и проекции. Код для преобразования экранных координат в мировые выглядит так: ```lua --- Преобразует экранные координаты в мировые с учётом -- вида и проекции конкретной камеры -- @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() -- https://defold.com/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 ``` Имейте в виду, что значения `action.screen_x` и `action.screen_y` из `on_input()` должны использоваться как аргументы для этой функции. На странице [Примеры](https://defold.com/examples/render/screen_to_world/) показано использование преобразования экранных координат в мировые. Также есть [примерный проект](https://github.com/defold/sample-screen-to-world-coordinates/) с демонстрацией этого процесса. ::: sidenote [Сторонние решения для камеры](/manuals/camera/#third-party-camera-solutions) предоставляют функции для преобразования координат между экраном и миром. ::: ## Манипуляции во время выполнения Камеры можно изменять из кода с помощью различных сообщений и свойств (подробности в [API документации](/ref/camera/)). Компонент камеры имеет следующие свойства, которые можно читать и изменять через `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: - [Orthographic camera](https://defold.com/assets/orthographic/) (только 2D) от Бьёрна Ритцля. - [Defold Rendy](https://defold.com/assets/defold-rendy/) (2D и 3D) от Клейтона Ковальски.