Camera
The Camera object defines a view of the 3D world. In a running experience, each client has its own Camera object which resides in that client's local Workspace, accessible through the Workspace.CurrentCamera property.
The most important camera properties are:
Camera.CFrame which represents the position and orientation of the camera.
Camera.CameraType which is read by the experience's camera scripts and determines how the camera should update each frame.
Camera.CameraSubject which is read by the experience's camera scripts and determines what object the camera should follow.
Camera.FieldOfView which represents the visible extent of the observable world.
Camera.Focus which represents the point the camera is looking at. It's important this property is set, as certain visuals will be more detailed and will update more frequently depending on how close they are to the focus point.
See Customizing the Camera for more information on how to adjust and customize the camera's behavior.
Summary
Properties
The CFrame of the Camera, defining its position and orientation in the 3D world.
Specifies the Enum.CameraType to be read by the camera scripts.
Sets the angle of the camera's diagonal field of view.
Sets the angle of the camera's vertical field of view.
Determines the FOV value of the Camera that's invariant under viewport size changes.
Sets the area in 3D space that is prioritized by Roblox's graphical systems.
Toggles whether the camera will automatically track the head motion of a player using a VR device.
Sets the scale of the user's perspective of the world when using VR.
Sets the angle of the camera's field of view along the longest viewport axis.
Describes the negative Z offset, in studs, of the camera's near clipping plane.
Toggles whether to apply tilt and roll from the Camera.CFrame property while the player is using a VR device.
Describes the dimensions, in pixels, of the client's viewport.
Methods
Returns an array of BaseParts that are obscuring the lines of sight between the camera's Camera.CFrame and the cast points.
Returns the actual CFramewhere the Camera is being rendered, accounting for any roll applied and the impact of VR devices.
Returns in radians the current roll, or rotation around the camera's Z-axis, applied to the Camera using Camera:SetRoll().
Creates a unit Ray from a position on the screen (in pixels), at a set depth from the Camera orientated in the camera's direction. Accounts for the GUI inset.
Sets the current rotation applied around the camera's Z-axis.
Creates a unit Ray from a position on the viewport (in pixels), at a given depth from the Camera, orientated in the camera's direction. Does not account for the GUI inset.
Returns the screen location and depth of a Vector3 worldPoint and whether this point is within the bounds of the screen. Accounts for the GUI inset.
Returns the screen location and depth of a Vector3 worldPoint and whether this point is within the bounds of the screen. Does not account for the GUI inset.
Events
Fired when the Camera has finished interpolating usingCamera:Interpolate().
Properties
CFrame
This property is the CFrame of the Camera, defining its position and orientation in the 3D world. Note that some transformations, such as the rotation of the head when using VR devices, are not reflected in this property, so you should use GetRenderCFrame() to obtain the "true" CFrame of the camera.
You can move the camera by setting this property. However, the default camera scripts also set it, so you should either:
Set the camera Camera.CameraType to Enum.CameraType.Scriptable so that the default camera scripts will not update the camera's CFrame. This method is simplest and recommended in most cases.
Completely replace the default camera scripts with alternatives. This approach is only recommended if you do not need any default camera functionality.
The most intuitive way to position and orient the Camera is by using the CFrame.lookAt() constructor. In the following example, the Camera is positioned at Vector3.new(0, 10, 0) and is oriented to be looking towards Vector3.new(10, 0, 0).
local camera = workspace.CurrentCameracamera.CameraType = Enum.CameraType.Scriptablelocal pos = Vector3.new(0, 10, 0)local lookAtPos = Vector3.new(10, 0, 0)workspace.CurrentCamera.CFrame = CFrame.lookAt(pos, lookAtPos)
Although the camera can be placed in the manner demonstrated above, you may want to animate it to move smoothly from one CFrame to another. For this, you can either:
Set the camera's position/orientation every frame with RunService:BindToRenderStep() and the CFrame:Lerp() method.
Create and play a Tween that animates the position/orientation of the camera:
local Players = game:GetService("Players")local TweenService = game:GetService("TweenService")local camera = workspace.CurrentCameracamera.CameraType = Enum.CameraType.Scriptablelocal player = Players.LocalPlayerlocal character = player.Characterif not character or character.Parent == nil thencharacter = player.CharacterAdded:Wait()endlocal pos = camera.CFrame * Vector3.new(0, 20, 0)local lookAtPos = character.PrimaryPart.Positionlocal targetCFrame = CFrame.lookAt(pos, lookAtPos)local tween = TweenService:Create(camera, TweenInfo.new(2), {CFrame = targetCFrame})tween:Play()
CameraSubject
CameraSubject accepts a variety of Instances. The default camera scripts respond differently to the available settings:
By default, the camera scripts follow the local character's Humanoid, factoring in the humanoid's current state and Humanoid.CameraOffset.
When set to a BasePart, the camera scripts follow its position, with a vertical offset in the case of VehicleSeats.
CameraSubject cannot be set to nil. Attempting to do so will revert it to its previous value.
To restore CameraSubject to its default value, set it to the local character's Humanoid:
local Players = game:GetService("Players")
local localPlayer = Players.LocalPlayer
local function resetCameraSubject()
if workspace.CurrentCamera and localPlayer.Character then
local humanoid = localPlayer.Character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
workspace.CurrentCamera.CameraSubject = humanoid
end
end
end
CameraType
The default Roblox camera scripts have several built-in behaviors. Setting this property toggles between the various Enum.CameraType behaviors. Note that some camera types require a valid Camera.CameraSubject to work correctly.
The default camera scripts will not move or update the camera if CameraType is set to Enum.CameraType.Scriptable. For more information on positioning and orienting the camera manually, see Camera.CFrame.
For all CameraType settings except Enum.CameraType.Scriptable, the CameraSubject property represents the object whose position the camera's Camera.Focus is set to.
DiagonalFieldOfView
Sets how many degrees in the diagonal direction (from one corner of the viewport to its opposite corner) the camera can view. See FieldOfView for a more general explanation of field of view.
FieldOfView
The FieldOfView property sets how many degrees in the vertical direction the camera can view. This property is clamped between 1 and 120 degrees and defaults at 70. Very low or very high fields of view are not recommended as they can be disorientating to players.
Note that uniform scaling is enforced, meaning the vertical and horizontal field of view are always related by the aspect ratio of the screen.
Suggested uses for FieldOfView (FOV) include:
- Reducing FOV to give the impression of magnification, for example when using binoculars.
- Increasing FOV when the player is "sprinting" to give the impression of a lack of control.
FieldOfViewMode
The camera's field of view (FOV) must be updated to reflect ViewportSize changes. The value of FieldOfViewMode determines which FOV value will be kept constant.
For example, when this property is set to Enum.FieldOfViewMode.Vertical, the horizontal FOV is updated when the viewport is resized, but the vertical FOV is kept constant. If this property is set to Enum.FieldOfViewMode.Diagonal, both horizontal and vertical FOV might be changed to keep the diagonal FOV constant.
Focus
Certain graphical operations the engine performs, such as updating lighting, can take time or computational effort to complete. The camera's Focus property tells the engine which area in 3D space to prioritize when performing such operations. For example, dynamic lighting from objects such as PointLights may not render at distances far from the focus.
The default Roblox camera scripts automatically set Focus to follow the Camera.CameraSubject (usually a Humanoid). However, Focus will not automatically update when CameraType is set to Enum.CameraType.Scriptable or when the default camera scripts are not being used. In these cases, you should update Focus every frame, using RunService:BindToRenderStep() function at the Enum.RenderPriority.Camera priority.
Focus has no bearing on the position or orientation of the camera; see Camera.CFrame for this.
HeadLocked
Toggles whether the camera will automatically track the head motion of a player using a VR device. When true (default), the engine combines Camera.CFrame with the Enum.UserCFrame of the user's head to render the player's view with head tracking factored in. The view will be rendered at the following CFrame:
local UserInputService = game:GetService("UserInputService")local camera = workspace.CurrentCameralocal headCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head)headCFrame = headCFrame.Rotation + headCFrame.Position * camera.HeadScale-- This will be equivalent to Camera:GetRenderCFrame()local renderCFrame = camera.CFrame * headCFrame
It is recommended to not disable this property for the following reasons:
- Players may experience motion sickness if an equivalent head tracking solution is not added.
- The Roblox engine performs latency optimizations when HeadLocked is true.
See Also
- VRService:GetUserCFrame() which can be used to obtain the CFrame of the head.
- VRService:RecenterUserHeadCFrame() which is used to recenter the head to the current position and orientation of the VR device.
- The Camera:GetRenderCFrame() function which returns the Camera.CFrame combined with the CFrame of the user's head.
HeadScale
HeadScale is the scale of the user's perspective of the world when using VR.
The size of 1 stud in VR is 0.3 meters / HeadScale, meaning that larger HeadScale values equate to the world looking smaller from the user's perspective when using VR devices. For example, a part that's 1 stud tall appears to be 0.6 meters tall to a VR player with a HeadScale of 0.5.
This property is automatically controlled by VRService.AutomaticScaling to align the player's perspective with the size of their avatar. If you intend to control HeadScale yourself or use custom characters, toggle VRService.AutomaticScaling to Enum.VRScaling.Off.
This property should not be confused with Humanoid.HeadScale which is a NumberValue parented to a Humanoid to control its scaling.
MaxAxisFieldOfView
The MaxAxisFieldOfView property sets how many degrees along the longest viewport axis the camera can view.
When the longest axis is the vertical axis, this property will behave similar to the FieldOfView property. This is generally the case when a device is in a portrait orientation. In a landscape orientation, the longest axis will be the horizontal axis; in this case, the property describes the horizontal field of view of the Camera.
NearPlaneZ
The NearPlaneZ property describes how far away the camera's near clipping plane is, in studs. The near clipping plane is a geometric plane that sits in front of the camera's Camera.CFrame. Anything between this plane and the camera will not render, creating a cutaway view when viewing objects at very short distances. The value of NearPlaneZ varies across different platforms and is currently always between -0.1 and -0.5.
![Diagram showing how the NearPlaneZ clips (does not render) 3D content between the plane and the camera.](https://prod.docsiteassets.roblox.com/assets/engine-api/classes/Camera/NearPlaneZ.jpg)
VRTiltAndRollEnabled
This property toggles whether to apply tilt and roll from the Camera.CFrame property while the player is using a VR device.
To prevent motion sickness, the horizon should remain level. Tilting and rolling the player's view while using a VR device can cause a disconnect between the player's physical space and the virtual space they are viewing. Changing the apparent downwards direction can cause players to lose balance or experience dizziness.
For these reasons, it is generally advisable to leave this property disabled, unless you have extensively tested your experience for these effects. Even with tilt and roll enabled, you may want to ensure the player always has a stable reference frame, such as the interior of a vehicle or a floor that can help the player ground themselves in their physical space.
ViewportSize
ViewportSize describes the dimensions, in pixels, of the client's viewport.
This property ignores the GUI inset applied by the top bar, meaning the center of the screen can be found at precisely at 50% of the viewport in both directions. You can find the position of a Vector3 in the world on the viewport using Camera:WorldToViewportPoint().
Methods
GetPartsObscuringTarget
This method returns an array of BaseParts that are obscuring the lines of sight between the camera's Camera.CFrame and Vector3 positions in the castPoints array. Any Instances included in the ignoreList array will be ignored, along with their descendants.
The castPoints parameter is given as an array of Vector3 positions. Note that the array of BaseParts returned is in an arbitrary order, and no additional raycast data is provided. If you need data such as hit position, hit material, or surface normal, you should opt for the WorldRoot:Raycast() method.
local camera = workspace.CurrentCameralocal castPoints = {Vector3.new(0, 10, 0),Vector3.new(0, 15, 0)}local ignoreList = {}local partsObscuringTarget = camera:GetPartsObscuringTarget(castPoints, ignoreList)
If Terrain obscures a cast point, BaseParts obscuring the cast point between the obscuring Terrain and the cast point will not be returned.
Parameters
Returns
An array of BaseParts that obscure the lines of sight between the camera's Camera.CFrame and the castPoints.
Code Samples
local Workspace = game:GetService("Workspace")
local camera = Workspace.CurrentCamera
local function XRay(castPoints, ignoreList)
ignoreList = ignoreList or {}
local parts = camera:GetPartsObscuringTarget(castPoints, ignoreList)
for _, part in parts do
part.LocalTransparencyModifier = 0.75
for _, child in pairs(part:GetChildren()) do
if child:IsA("Decal") or child:IsA("Texture") then
child.LocalTransparencyModifier = 0.75
end
end
end
end
XRay({ Vector3.new() })
GetRenderCFrame
This function returns the actual CFrame of the Camera as it is rendered, including the impact of VR (VR head transformations are not applied to the Camera.CFrame property, so it is best practice to use Camera:GetRenderCFrame() to obtain the "true" CFrame of a player's view).
For example, when using VR, the Camera is actually rendered at the following CFrame:
local UserInputService = game:GetService("UserInputService")local camera = workspace.CurrentCameralocal headCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head)headCFrame = headCFrame.Rotation + headCFrame.Position * camera.HeadScalerenderCFrame = camera.CFrame * headCFrame
The camera's render CFrame will only be changed to account for the head when the Camera.HeadLocked property is true.
Returns
GetRoll
This function returns, in radians, the current roll applied to the Camera using Camera:SetRoll(). Roll is defined as rotation around the camera's Z-axis.
This function only returns roll applied using the Camera:SetRoll() function. Roll manually applied to the camera's Camera.CFrame is not accounted for. To obtain the actual roll of the Camera, including roll manually applied, you can use the following snippet:
local function getActualRoll()
local camera = workspace.CurrentCamera
local trueUp = Vector3.new(0, 1, 0)
local cameraUp = camera:GetRenderCFrame().upVector
return math.acos(trueUp:Dot(cameraUp))
end
Returns
The current roll applied by Camera:SetRoll(), in radians.
Code Samples
local currentRoll = math.deg(workspace.CurrentCamera:GetRoll()) -- Gets the current roll of the camera in degrees.
if currentRoll ~= 20 then
workspace.CurrentCamera:SetRoll(math.rad(20)) -- If the camera isn't at 20 degrees roll, the roll is set to 20 degrees.
end
ScreenPointToRay
This function creates a unit Ray from a 2D position on the screen (defined in pixels), accounting for the GUI inset. The Ray originates from the Vector3 equivalent of the 2D position in the world at the given depth (in studs) away from the Camera.
As this function acknowledges the GUI inset, the offset applied to GUI elements (such as from the top bar) is accounted for. This means the screen position specified will start in the top left corner below the top bar. For an otherwise identical function that does not account for the GUI offset, use Camera:ViewportPointToRay().
As the Ray created is a unit ray, it is only one stud long. To create a longer ray, you can do the following:
local camera = workspace.CurrentCameralocal length = 500local unitRay = camera:ScreenPointToRay(100, 100)local extendedRay = Ray.new(unitRay.Origin, unitRay.Direction * length)
This function only works for the current Workspace camera. Other cameras, such as those you create for a ViewportFrame, have an initial viewport size of (1, 1) and are only updated after you set them to Workspace.CurrentCamera. The mismatch in viewport size causes the camera to return a ray with an incorrect Ray.Direction.
Parameters
The position on the X axis, in pixels, of the screen point at which to originate the Ray. This position accounts for the GUI inset.
The position on the Y axis, in pixels, of the screen point at which to originate the Ray. This position accounts for the GUI inset.
Returns
SetRoll
This function is outdated and no longer considered best practice.
This function sets the current roll, in radians, of the Camera. The roll is applied after the Camera.CFrame and represents the rotation around the camera's Z-axis.
For example, the following would invert the Camera:
workspace.CurrentCamera:SetRoll(math.pi) -- math.pi radians = 180 degrees
SetRoll has no effect on any roll applied using the Camera.CFrame property. Roll applied using SetRoll is not reflected in the Camera.CFrame property but is reflected in the CFrame returned byCamera:GetRenderCFrame().
This function can only be used when the Camera.CameraType is set to 'Scriptable', regardless of whether the default camera scripts are being used. If it is used with any other Camera.CameraType a warning is given in the output.
Any roll applied using this function will be lost when the Camera.CameraType is changed from 'Scriptable'.
To obtain the roll set using this function use Camera:GetRoll().
As this function is outdated, you are advised to instead apply roll to the Camera using the Camera.CFrame property. For example:
local currentCFrame = workspace.CurrentCamera.CFramelocal rollCFrame = CFrame.Angles(0, 0, roll)workspace.CurrentCamera.CFrame = currentCFrame * rollCFrame
Parameters
Returns
ViewportPointToRay
This function creates a unit Ray from a 2D position on the viewport (defined in pixels). This position does not account for the GUI inset. The Ray originates from the Vector3 equivalent of the 2D position in the world at the given depth (in studs) away from the Camera.
As this function does not acknowledge the GUI inset, the viewport position given is not equivalent to the screen position used by GUI elements. If you are not using ScreenGui.IgnoreGuiInset and need an otherwise identical function that accounts for the GUI offset, use Camera:ScreenPointToRay().
This function can be used in conjunction with the Camera.ViewportSize property to create a ray from the centre of the screen, for example:
local camera = workspace.CurrentCameralocal viewportPoint = camera.ViewportSize / 2local unitRay = camera:ViewportPointToRay(viewportPoint.X, viewportPoint.Y, 0)
As the Ray created is a unit ray, it is only one stud long. To create a longer ray, you can do the following:
local camera = workspace.CurrentCameralocal length = 500local unitRay = camera:ScreenPointToRay(100, 100)local extendedRay = Ray.new(unitRay.Origin, unitRay.Direction * length)
This function only works for the current Workspace camera. Other cameras, such as those you create for a ViewportFrame, have an initial viewport size of (1, 1) and are only updated after you set them to Workspace.CurrentCamera. The mismatch in viewport size causes the camera to return a ray with an incorrect Ray.Direction.
Parameters
The position on the X axis, in pixels, of the viewport point at which to originate the Ray. This position does not account for the GUI inset.
The position on the Y axis, in pixels, of the viewport point at which to originate the Ray. This position does not account for the GUI inset.
Returns
WorldToScreenPoint
This function returns the screen location and depth of a Vector3 worldPoint and whether this point is within the bounds of the screen.
This function takes in account the current GUI inset, such as the space occupied by the top bar, meaning that the 2D position returned is in the same term as GUI positions and can be used to place GUI elements. For an otherwise identical function that ignores the GUI inset, see Camera:WorldToViewportPoint().
local camera = workspace.CurrentCameralocal worldPoint = Vector3.new(0, 10, 0)local vector, onScreen = camera:WorldToScreenPoint(worldPoint)local screenPoint = Vector2.new(vector.X, vector.Y)local depth = vector.Z
Note this function does not perform any raycasting and the boolean indicating whether worldPoint is within the bounds of the screen will be true regardless of whether the point is obscured by BaseParts or Terrain.
Parameters
Returns
A tuple containing, in order:
A boolean indicating if the worldPoint is within the bounds of the screen.
WorldToViewportPoint
This function returns the screen location and depth of a Vector3 worldPoint and whether this point is within the bounds of the screen.
This function does not take in account the current GUI inset, such as the space occupied by the top bar, meaning that the 2D position returned is taken from the top left corner of the viewport. Unless you are using ScreenGui.IgnoreGuiInset, this position is not appropriate for placing GUI elements.
For an otherwise identical function that accounts for the GUI inset, see Camera:WorldToScreenPoint().
local camera = workspace.CurrentCameralocal worldPoint = Vector3.new(0, 10, 0)local vector, onScreen = camera:WorldToViewportPoint(worldPoint)local viewportPoint = Vector2.new(vector.X, vector.Y)local depth = vector.Z
Note this function does not perform any raycasting and the boolean indicating whether worldPoint is within the bounds of the screen will be true regardless of whether the point is obscured by BaseParts or Terrain.
Parameters
Returns
A tuple containing, in order:
A boolean indicating if the worldPoint is within the bounds of the screen.
Events
InterpolationFinished
This event fires when the Camera has finished interpolating using the Camera:Interpolate() function.
This event will not fire if a tween is interrupted due to Camera:Interpolate() being called again.
You are advised to use TweenService to animate the Camera instead, as it is more reliable and provides more options for easing styles.