Skip to main content
Three.js Course · Camera Fundamentals

Three.js Camera Masterclass: Understand PerspectiveCamera

Learn how field of view, aspect ratio, clipping planes, position, and lookAt() work together to create the view of your 3D scene.

Perspective camera viewing frustum containing a cube and other 3D objects

A camera is the viewer's eye inside a Three.js world. The scene may contain perfect lighting, materials, and models, but nothing reaches the canvas until a camera defines the viewpoint and the renderer uses it. For most 3D websites and games, that viewpoint begins with THREE.PerspectiveCamera.

This guide turns the supplied Camera Masterclass course into a structured blog lesson. You will create a camera, understand all four constructor values, make it responsive, position it in 3D space, aim it at a target, and diagnose the most common visibility problems.

Learning goal: By the end, you will be able to read new THREE.PerspectiveCamera(75, aspect, 0.1, 1000) and explain exactly what every value does.

1. What a camera does in Three.js

The camera does not draw objects and is not normally visible inside the scene. Instead, it creates a projection: it takes the portion of 3D space inside its viewing volume and maps that view onto the renderer's 2D canvas.

Position

Where the viewer stands in 3D space.

Projection

How wide and deep the visible area is.

Direction

Which point the viewer faces.

A perspective camera makes distant objects appear smaller, similar to human vision and a physical camera lens. An orthographic camera keeps an object's apparent size constant regardless of distance, which is useful for maps, diagrams, and some interface-like scenes. This lesson focuses on perspective projection.

2. Create a PerspectiveCamera

The constructor accepts four values in a fixed order: vertical field of view, aspect ratio, near clipping distance, and far clipping distance.

JavaScript
const camera = new THREE.PerspectiveCamera(
  75,                                    // Field of view
  window.innerWidth / window.innerHeight, // Aspect ratio
  0.1,                                   // Near clipping plane
  1000                                   // Far clipping plane
)

camera.position.z = 3
renderer.render(scene, camera)

Moving the camera on the z-axis is important in a typical starter scene. A new camera and a new mesh are often both placed at the origin, so the camera may begin inside the mesh. Moving it to z = 3 creates enough distance to see an object centered at (0, 0, 0).

3. Field of view: how wide the camera sees

Field of view, or FOV, is the camera's vertical viewing angle in degrees. A lower FOV creates a narrow, zoomed-in composition. A higher FOV includes more of the scene but exaggerates perspective near the edges.

FOVVisual effectPossible use
30–45°Narrow and compressedProduct detail or focused shot
50–60°Natural perspectiveGeneral 3D experiences
70–90°Wide and energeticGames, rooms, landscapes
Above 100°Strong edge distortionStylized or special-purpose views

Start near 60 or 75, then frame the subject by changing the camera's position. Treat very high FOV values as an intentional effect, not a shortcut for fitting everything into the frame.

FOV examples
const portraitCamera = new THREE.PerspectiveCamera(35, aspect, 0.1, 100)
const generalCamera = new THREE.PerspectiveCamera(60, aspect, 0.1, 100)
const wideCamera = new THREE.PerspectiveCamera(85, aspect, 0.1, 100)

4. Aspect ratio: prevent a stretched scene

The aspect ratio is the width of the canvas divided by its height. It must describe the renderer's actual drawing area. If the ratio is wrong, circles look oval and cubes appear stretched.

Responsive camera
function resizeScene() {
  const width = window.innerWidth
  const height = window.innerHeight

  camera.aspect = width / height
  camera.updateProjectionMatrix()

  renderer.setSize(width, height)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
}

window.addEventListener('resize', resizeScene)
resizeScene()

Changing camera.aspect only changes the stored property. Calling camera.updateProjectionMatrix() rebuilds the projection so the new value affects rendering. Limiting pixel ratio can also prevent unnecessarily expensive rendering on very dense screens.

5. Near and far clipping planes

The near and far values define the visible depth range. Anything closer than near or farther away than far is clipped and does not appear.

CameraNear 0.1Visible sceneFar 1000

Near clipping plane

A near value of 0.1 is a useful default for many human-scale scenes. Setting it too large makes nearby objects disappear. Setting it extremely close to zero can reduce depth-buffer precision and contribute to flickering surfaces known as z-fighting.

Far clipping plane

The far value should reach the most distant content that must remain visible. A small room may need only 50 or 100; a city or landscape may need much more. Avoid choosing an enormous number without a reason.

Precision rule: Keep the near plane as far from zero as the scene allows, keep the far plane as close as the scene allows, and avoid an unnecessarily huge far-to-near ratio.

6. Position the camera in 3D space

Like other Three.js objects, a camera has a position with x, y, and z coordinates. Positive x moves right, positive y moves up, and positive z usually moves toward the viewer in the default coordinate setup.

Camera position
camera.position.set(2, 1.5, 5)

// These assignments are equivalent to changing one axis at a time:
camera.position.x = 2
camera.position.y = 1.5
camera.position.z = 5

position.set() is concise when all three values are known. Individual properties are convenient for animation or controls. Moving the camera does not automatically point it toward your subject, so the next step is to set its direction.

7. Aim the camera with lookAt()

camera.lookAt() rotates the camera so its viewing direction points toward a coordinate or vector. It is the quickest way to frame an object from a new position.

Target an object
const target = new THREE.Vector3(0, 0, 0)

camera.position.set(4, 2, 5)
camera.lookAt(target)

// You can also target a mesh directly:
camera.lookAt(cube.position)

For a simple orbit, calculate a circular x/z position on every frame and keep the camera looking at the center:

Orbit animation
function animate(time) {
  const angle = time * 0.0005

  camera.position.x = Math.cos(angle) * 5
  camera.position.z = Math.sin(angle) * 5
  camera.lookAt(0, 0, 0)

  renderer.render(scene, camera)
  requestAnimationFrame(animate)
}

requestAnimationFrame(animate)

8. Complete responsive camera example

This compact setup combines the important ideas into one camera that starts in a useful position, faces the scene, and stays correct when the viewport changes.

Complete setup
const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 100)
camera.position.set(3, 2, 5)
camera.lookAt(0, 0, 0)
scene.add(camera)

function resize() {
  const width = window.innerWidth
  const height = window.innerHeight

  camera.aspect = width / height
  camera.updateProjectionMatrix()
  renderer.setSize(width, height)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
}

window.addEventListener('resize', resize)
resize()

function animate() {
  renderer.render(scene, camera)
  requestAnimationFrame(animate)
}

animate()

9. Troubleshooting checklist

ProblemWhat to check
Blank canvasConfirm the camera is passed to renderer.render(scene, camera) and is not inside the mesh.
Object disappears up closeReduce the near value slightly or move the camera back.
Distant object disappearsIncrease the far value only as much as the scene needs.
Scene looks stretchedMatch camera.aspect to the canvas and call updateProjectionMatrix().
Camera is in the right place but sees nothingCall lookAt() or correct the camera rotation.
Surfaces flickerImprove depth precision by increasing near, reducing far, or fixing overlapping geometry.

10. Quick reference

SettingMeaningPractical starting point
fovVertical viewing angle50–75
aspectCanvas width divided by heightwidth / height
nearClosest visible distance0.1
farFarthest visible distance100 or 1000
position.set(x, y, z)Moves the viewpointDepends on the subject
lookAt(x, y, z)Points at a target0, 0, 0

Frequently asked questions

What does a camera do in Three.js?

A camera defines the point of view used to render a scene. It controls what is visible and how 3D space is projected onto the 2D canvas.

What is a good field of view for a Three.js camera?

A vertical field of view between 50 and 75 degrees is a practical starting point for many scenes. Lower values feel zoomed in, while higher values produce a wider and more distorted view.

Why must the camera aspect ratio be updated on resize?

The aspect ratio must match the canvas width divided by its height. Updating it and calling updateProjectionMatrix prevents the scene from looking stretched after the viewport changes.

What should I use for the near and far clipping planes?

Use the smallest useful range for the scene. A common starting point is 0.1 for near and 100 or 1000 for far, then adjust them to the actual scale of your world.

Why is my Three.js object not visible?

Check that the camera is not inside the object, the object lies between the near and far clipping planes, the camera faces the object, and the renderer is using the expected camera.

You are ready to frame a Three.js scene

A reliable perspective camera comes down to five decisions: choose an intentional FOV, match the aspect ratio to the canvas, keep the clipping range sensible, place the camera outside the subject, and point it at the part of the world that matters. Once these fundamentals feel natural, camera controls, cinematic movement, and scroll-driven 3D scenes become much easier to build.

Building an interactive 3D website?

NavTech Solution creates responsive web experiences with modern JavaScript, animation, and production-minded performance.

Discuss your project