-
Notifications
You must be signed in to change notification settings - Fork 68
docs: restructure Cameras section into multi-page, workflow-agnostic docs #1041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5948358
docs: restructure Cameras section into multi-page, workflow-agnostic …
willeastcott 35b6f10
docs: move render target clearing from Cameras landing page to Multip…
willeastcott 044853c
docs: give render target clearing its own Cameras subpage
willeastcott 3ad2f08
docs: swap misplaced engine example embeds on camera pages
willeastcott 04b2e1c
docs: link engine constants to API reference in cameras prose
willeastcott 6d10cbd
docs: link CameraFrame note directly to CameraFrame docs
willeastcott File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| --- | ||
| title: Camera Controls | ||
| description: Add orbit, fly, and pan navigation to any camera with the engine's ready-made camera-controls script, with mouse, touch, and gamepad support. | ||
| --- | ||
|
|
||
| import Tabs from '@theme/Tabs'; | ||
| import TabItem from '@theme/TabItem'; | ||
|
|
||
| Most applications need some way for the user to move the camera. Rather than writing this from scratch, you can use the `CameraControls` script that ships with the engine at [`scripts/esm/camera-controls.mjs`](https://github.com/playcanvas/engine/blob/main/scripts/esm/camera-controls.mjs). It provides production-quality navigation with a single script: | ||
|
|
||
| * **Orbit** — left mouse drag rotates around a focus point, right mouse drag pans, and the mouse wheel zooms. | ||
| * **Fly** — WASD keys move the camera freely while the mouse looks around. | ||
| * **Touch and gamepad** — multi-touch gestures and gamepad input are supported out of the box. | ||
|
|
||
| Attach the script to a camera entity: | ||
|
|
||
| <Tabs groupId="workflow" defaultValue="engine"> | ||
| <TabItem value="engine" label="Engine"> | ||
|
|
||
| ```javascript | ||
| // Load the script (here from the CDN; you can also bundle it with your app) | ||
| const asset = new pc.Asset('camera-controls', 'script', { | ||
| url: 'https://cdn.jsdelivr.net/npm/playcanvas/scripts/esm/camera-controls.mjs' | ||
| }); | ||
| app.assets.add(asset); | ||
| app.assets.load(asset); | ||
|
|
||
| asset.ready(() => { | ||
| // Attach it to the camera entity | ||
| camera.addComponent('script'); | ||
| camera.script.create('cameraControls', { | ||
| properties: { | ||
| focusPoint: new pc.Vec3(0, 1, 0) | ||
| } | ||
| }); | ||
| }); | ||
| ``` | ||
|
|
||
| If you build your app with a bundler, you can import the script class directly instead: | ||
|
|
||
| ```javascript | ||
| import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; | ||
|
|
||
| camera.addComponent('script'); | ||
| camera.script.create(CameraControls); | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| <TabItem value="editor" label="Editor"> | ||
|
|
||
| Add `camera-controls.mjs` to your project as a script asset (copy it from the [engine repository](https://github.com/playcanvas/engine/blob/main/scripts/esm/camera-controls.mjs)). Then select your camera entity, add a [Script Component](/user-manual/editor/scenes/components/script) and add the **cameraControls** script to it. The script's attributes can then be tuned in the Inspector. | ||
|
|
||
| </TabItem> | ||
| <TabItem value="react" label="React"> | ||
|
|
||
| ```jsx | ||
| import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; | ||
| import { Script } from '@playcanvas/react/components'; | ||
|
|
||
| <Entity name="camera" position={[0, 1, 4]}> | ||
| <Camera /> | ||
| <Script script={CameraControls} /> | ||
| </Entity> | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| <TabItem value="web-components" label="Web Components"> | ||
|
|
||
| ```html | ||
| <pc-app> | ||
| <pc-asset src="https://cdn.jsdelivr.net/npm/playcanvas/scripts/esm/camera-controls.mjs"></pc-asset> | ||
| <pc-scene> | ||
| <pc-entity name="camera" position="0 1 4"> | ||
| <pc-camera></pc-camera> | ||
| <pc-scripts> | ||
| <pc-script name="cameraControls"></pc-script> | ||
| </pc-scripts> | ||
| </pc-entity> | ||
| </pc-scene> | ||
| </pc-app> | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| </Tabs> | ||
|
|
||
| ## Configuration {#configuration} | ||
|
|
||
| The script exposes a rich set of attributes. The most commonly used are: | ||
|
|
||
| | Attribute | Default | Description | | ||
| | --- | --- | --- | | ||
| | `enableOrbit` | `true` | Enable orbit controls | | ||
| | `enableFly` | `true` | Enable fly controls | | ||
| | `enablePan` | `true` | Enable panning | | ||
| | `focusPoint` | `[0, 0, 0]` | The point the camera orbits around | | ||
| | `rotateSpeed` | `0.2` | Rotation sensitivity | | ||
| | `moveSpeed` | `10` | Fly movement speed (with `moveFastSpeed` and `moveSlowSpeed` variants) | | ||
| | `zoomSpeed` | `0.001` | Zoom sensitivity | | ||
| | `pitchRange` | `[-360, 360]` | Limits for the camera's pitch angle in degrees | | ||
| | `zoomRange` | `[0.01, 0]` | Min/max zoom distance (a max of 0 means unlimited) | | ||
|
|
||
| Damping attributes (`rotateDamping`, `moveDamping`, `zoomDamping`, `focusDamping`, all defaulting to `0.98`) control how smoothly motion eases out — 0 stops instantly. To create a pure orbit camera, disable fly; for a pure fly camera, disable orbit. | ||
|
|
||
| ## Examples {#examples} | ||
|
|
||
| See the script in action in the engine examples: | ||
|
|
||
| <EngineExample id="camera/orbit" title="Orbit Camera" /> | ||
|
|
||
| <EngineExample id="camera/fly" title="Fly Camera" /> | ||
|
|
||
| <EngineExample id="camera/multi" title="Multi Camera" /> | ||
|
|
||
| For building your own custom camera logic instead, the [Orbit Camera tutorial](/tutorials/orbit-camera) walks through a complete implementation. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| --- | ||
| title: Clearing | ||
| description: Control how a camera clears its render target — set the background color, make the canvas transparent, or disable clearing entirely. | ||
| --- | ||
|
|
||
| Before a camera renders the scene, it clears its render target — the screen, unless a [render target](multiple-cameras.md#render-targets) is assigned. You can control what gets cleared and to what color: | ||
|
|
||
| ```javascript | ||
| camera.camera.clearColor = new pc.Color(0, 0, 0); | ||
|
|
||
| camera.camera.clearColorBuffer = true; // clear the color buffer (default: true) | ||
| camera.camera.clearDepthBuffer = true; // clear the depth buffer (default: true) | ||
| camera.camera.clearStencilBuffer = true; // clear the stencil buffer (default: true) | ||
| ``` | ||
|
|
||
| The clear color is effectively the background color of your scene — though if your scene has a skybox, it covers the clear color entirely. | ||
|
|
||
| ## Transparent Backgrounds {#transparent-backgrounds} | ||
|
|
||
| The clear color has an alpha channel, and the application's canvas supports transparency by default. This means a single camera can render the scene over the surrounding web page — useful for 3D product views, headers, and other embedded content: | ||
|
|
||
| ```javascript | ||
| // The web page shows through wherever nothing is drawn | ||
| camera.camera.clearColor = new pc.Color(0, 0, 0, 0); | ||
| ``` | ||
|
|
||
| ## Disabling Clearing {#disabling-clearing} | ||
|
|
||
| Disabling the clear flags keeps the existing contents of the render target, which is the building block for compositing several cameras into one image — see [Camera Stacking](multiple-cameras.md#camera-stacking). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,38 +1,82 @@ | ||
| --- | ||
| title: Cameras | ||
| description: Add cameras, choose orthographic or perspective projection, and configure viewports for split-screen and picture-in-picture. | ||
| description: Create cameras and explore projection, tone mapping, multi-camera rendering, camera controls, and coordinate conversion. | ||
| --- | ||
|
|
||
| Cameras are responsible for rendering a scene to the screen. You need at least one camera in your scene to see anything. When you create a new scene in PlayCanvas, it is automatically populated with a single camera (along with a directional light). | ||
| import Tabs from '@theme/Tabs'; | ||
| import TabItem from '@theme/TabItem'; | ||
|
|
||
| ## Creating a Camera | ||
| Cameras render your scene to the screen. A camera is simply an entity with a [CameraComponent](https://api.playcanvas.com/engine/classes/CameraComponent.html) attached — the scene is drawn from the entity's position and orientation, so you aim a camera by moving and rotating its entity just like any other. Cameras look down their local negative Z axis. | ||
|
|
||
| In the Editor's 3D View, an unselected camera is represented with the following icon: | ||
| You need at least one enabled camera in your scene to see anything. Beyond that single camera, there is a lot you can control: the [projection](projection.md) that maps the 3D scene to a 2D image, the [tone mapping](tone-mapping.md) that shapes the final colors, and how [multiple cameras](multiple-cameras.md) compose views for split-screen, overlays, and render-to-texture. | ||
|
|
||
|  | ||
| ## Creating a Camera {#creating-a-camera} | ||
|
|
||
| To create a new camera, simply create a new entity and add a camera component to it. For convenience, the Editor menu has an item that does this in a single step: | ||
| <Tabs groupId="workflow" defaultValue="engine"> | ||
| <TabItem value="engine" label="Engine"> | ||
|
|
||
| ```javascript | ||
| // Create an entity with a camera component | ||
| const camera = new pc.Entity('Camera'); | ||
| camera.addComponent('camera', { | ||
| clearColor: new pc.Color(0.3, 0.3, 0.7) | ||
| }); | ||
| app.root.addChild(camera); | ||
|
|
||
| // Aim the camera by transforming its entity | ||
| camera.setPosition(0, 5, 10); | ||
| camera.lookAt(0, 0, 0); | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| <TabItem value="editor" label="Editor"> | ||
|
|
||
| New scenes are automatically populated with a camera entity. To create another, use the Entity menu, which creates an entity with a [Camera Component](/user-manual/editor/scenes/components/camera) in a single step: | ||
|
|
||
|  | ||
|
|
||
| ## Orthographic vs Perspective Projection | ||
| All camera properties can then be edited in the Inspector. | ||
|
|
||
| </TabItem> | ||
| <TabItem value="react" label="React"> | ||
|
|
||
| Cameras can have one of two types of projection: orthographic or perspective. Orthographic cameras define a parallel projection and are often used for 2D or isometric games. | ||
| ```jsx | ||
| <Entity name="camera" position={[0, 5, 10]}> | ||
| <Camera clearColor="#4d4db3" /> | ||
| </Entity> | ||
| ``` | ||
|
|
||
|  | ||
| See the [`<Camera/>` component reference](/user-manual/react/api/camera) for all available props. | ||
|
|
||
| More commonly used is the perspective projection. It more closely mimics how our eyes or cameras work. | ||
| </TabItem> | ||
| <TabItem value="web-components" label="Web Components"> | ||
|
|
||
|  | ||
| ```html | ||
| <pc-entity name="camera" position="0 5 10"> | ||
| <pc-camera clear-color="0.3 0.3 0.7 1"></pc-camera> | ||
| </pc-entity> | ||
| ``` | ||
|
|
||
| ## Controlling the Viewport | ||
| See the [`<pc-camera>` tag reference](/user-manual/web-components/tags/pc-camera) for all available attributes. | ||
|
|
||
| By default, a camera will render to the full width and height of its render target. However, there are circumstances where you might want to change this behavior. For example, perhaps you are writing a game that has a local multiplayer mode that requires split-screen rendering to show each player's viewpoint. | ||
| </TabItem> | ||
| </Tabs> | ||
|
|
||
| For 2-player horizontal split screen, you would create two cameras and configure their viewports as follows: | ||
| ## In This Section | ||
|
|
||
|  | ||
| * [Projection](projection.md) — perspective vs orthographic projection, field of view, clip planes and frustum culling. | ||
| * [Clearing](clearing.md) — set the background color, make the canvas transparent, or disable clearing. | ||
| * [Tone Mapping & Exposure](tone-mapping.md) — map HDR scene lighting to your display, with optional physical exposure controls. | ||
| * [Multiple Cameras](multiple-cameras.md) — compose views with priorities, viewports, layers and render targets. | ||
| * [Camera Controls](camera-controls.md) — add orbit, fly and first-person navigation with the engine's ready-made script. | ||
| * [Screen and World Coordinates](screen-and-world.md) — convert between 2D screen positions and 3D world positions. | ||
| * [Scene Picker](scene-picker.md) — accurately select the objects under a screen coordinate. | ||
| * [Depth Layer](depth-layer.md) — give shaders access to the scene's color and depth buffers. | ||
|
|
||
| And for vertical split screen, you would configure the viewports as follows: | ||
| ## Going Further | ||
|
|
||
|  | ||
| * **Post-processing** — bloom, depth of field, SSAO, TAA, vignette and more are applied per camera. See [Post Effects](/user-manual/graphics/posteffects/). | ||
| * **AR and VR** — a camera can drive an immersive WebXR session via [`startXr()`](https://api.playcanvas.com/engine/classes/CameraComponent.html#startxr). See the [XR section](/user-manual/xr/). | ||
| * **Per-camera fog** — override the scene's fog settings on an individual camera with [`fog`](https://api.playcanvas.com/engine/classes/CameraComponent.html#fog). | ||
| * **Custom projections** — supply [`calculateProjection`](https://api.playcanvas.com/engine/classes/CameraComponent.html#calculateprojection) and [`calculateTransform`](https://api.playcanvas.com/engine/classes/CameraComponent.html#calculatetransform) callbacks for advanced effects such as oblique projections and planar reflections. | ||
| * **Tutorials** — try [Camera Following a Path](/tutorials/camera-following-a-path) and [Orbit Camera](/tutorials/orbit-camera). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| --- | ||
| title: Multiple Cameras | ||
| description: Compose views from several cameras using priorities, viewports, layers, and render targets for split-screen, overlays, and more. | ||
| --- | ||
|
|
||
| import Tabs from '@theme/Tabs'; | ||
| import TabItem from '@theme/TabItem'; | ||
|
|
||
| A scene can contain any number of cameras, and they compose into the final image according to a simple model: every enabled camera renders its [layers](#layers) into its [viewport](#viewports) of its render target (the screen, unless a [render target](#render-targets) is set), in order of `priority` — lower values render first. | ||
|
|
||
| This model supports a wide range of setups: split-screen multiplayer, picture-in-picture overlays such as minimaps and rear-view mirrors, UI rendered over the 3D scene, and live render-to-texture surfaces like security monitors and portals. | ||
|
|
||
| <EngineExample id="graphics/multi-view" title="Multi View" /> | ||
|
|
||
| ## Viewports {#viewports} | ||
|
|
||
| By default, a camera renders to the full width and height of its render target. The `rect` property restricts rendering to a rectangle, specified as `[x, y, width, height]` in normalized 0–1 coordinates (the origin is the bottom-left corner). | ||
|
|
||
| For 2-player horizontal split-screen, two cameras each take half the screen: | ||
|
|
||
|  | ||
|
|
||
| <Tabs groupId="workflow" defaultValue="engine"> | ||
| <TabItem value="engine" label="Engine"> | ||
|
|
||
| ```javascript | ||
| // Player 1: left half of the screen | ||
| camera1.camera.rect = new pc.Vec4(0, 0, 0.5, 1); | ||
|
|
||
| // Player 2: right half of the screen, rendered after camera1 | ||
| camera2.camera.rect = new pc.Vec4(0.5, 0, 0.5, 1); | ||
| camera2.camera.priority = 1; | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| <TabItem value="editor" label="Editor"> | ||
|
|
||
| Select each camera in the Hierarchy and set its **Viewport** (X, Y, Width, Height) and **Priority** in the [Camera Component](/user-manual/editor/scenes/components/camera). | ||
|
|
||
| </TabItem> | ||
| <TabItem value="react" label="React"> | ||
|
|
||
| ```jsx | ||
| <Entity name="player1Camera"> | ||
| <Camera rect={[0, 0, 0.5, 1]} /> | ||
| </Entity> | ||
| <Entity name="player2Camera"> | ||
| <Camera rect={[0.5, 0, 0.5, 1]} priority={1} /> | ||
| </Entity> | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| <TabItem value="web-components" label="Web Components"> | ||
|
|
||
| ```html | ||
| <pc-entity name="player1-camera"> | ||
| <pc-camera rect="0 0 0.5 1"></pc-camera> | ||
| </pc-entity> | ||
| <pc-entity name="player2-camera"> | ||
| <pc-camera rect="0.5 0 0.5 1" priority="1"></pc-camera> | ||
| </pc-entity> | ||
| ``` | ||
|
|
||
| </TabItem> | ||
| </Tabs> | ||
|
|
||
| For vertical split-screen, stack the viewports instead — `[0, 0.5, 1, 0.5]` on top and `[0, 0, 1, 0.5]` below: | ||
|
|
||
|  | ||
|
|
||
| A related property, `scissorRect`, clips rendering to a rectangle in the same normalized format without changing how the image is projected into the viewport. | ||
|
|
||
| ## Layers {#layers} | ||
|
|
||
| Each camera renders only the [layers](/user-manual/graphics/layers) listed in its `layers` property, so different cameras can see entirely different subsets of the scene. Typical uses include a UI camera that renders only a UI layer over the game, a minimap camera that skips effects layers, and first-person weapon rendering. See the [Camera Model Masking tutorial](/tutorials/camera-model-masking) for a worked example. | ||
|
|
||
| ## Camera Stacking {#camera-stacking} | ||
|
|
||
| When one camera renders on top of another — a picture-in-picture overlay, or a full-screen camera drawing a different set of layers — the later camera (higher `priority`) must not wipe out the earlier camera's image. Disable its [clear flags](clearing.md) as appropriate: | ||
|
|
||
| ```javascript | ||
| // Render an overlay camera on top of the main view, in the bottom-right corner | ||
| overlay.camera.priority = 1; | ||
| overlay.camera.rect = new pc.Vec4(0.7, 0, 0.3, 0.3); | ||
| overlay.camera.clearColorBuffer = true; // overlay has its own background | ||
| overlay.camera.clearDepthBuffer = true; // don't depth-test against the main view | ||
|
|
||
| // For a full-screen overlay that composites over the main view instead: | ||
| // overlay.camera.clearColorBuffer = false; | ||
| ``` | ||
|
|
||
| ## Render Targets {#render-targets} | ||
|
|
||
| Instead of the screen, a camera can render into an offscreen texture by assigning a [RenderTarget](https://api.playcanvas.com/engine/classes/RenderTarget.html) to its `renderTarget` property. The resulting texture can then be applied to a material — for in-world screens, mirrors and portals — or processed further. See the engine's render-to-texture example: | ||
|
|
||
| <EngineExample id="graphics/render-to-texture" title="Render to Texture" /> | ||
|
|
||
| ## Performance Considerations {#performance-considerations} | ||
|
|
||
| * Every enabled camera renders its layers again — draw calls scale with the number of cameras. Restrict each camera's `layers` to the minimum it actually needs. | ||
| * Reducing a camera's `rect` reduces the pixels it fills, but not the per-draw-call CPU cost of the objects it renders. | ||
| * Per-camera [post-processing](/user-manual/graphics/posteffects/) runs once per camera, so effects on split-screen views multiply their GPU cost. | ||
| * Render targets that are only needed occasionally (e.g. a static mirror) don't have to be updated every frame — disable the camera and enable it on demand. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.