# Depth of Field

A Suzanne model staged with drei's Stage helper, focused with @react-three/postprocessing's DepthOfField effect.

Demo: https://pmndrs.github.io/examples/examples/depth-of-field
Source: https://github.com/pmndrs/examples/tree/main/examples/depth-of-field
Scaffold: npx degit pmndrs/examples/examples/depth-of-field
Authors: Sara Vieira
Tags: postprocessing, dof
Ported from: https://codesandbox.io/p/sandbox/bu796
Dependencies: @react-three/drei@10.7.8, @react-three/fiber@9.8.1, @react-three/postprocessing@^3.1.2, leva@^0.10.1, react@19.2.8, react-dom@19.2.8, three@0.186.0
Binary files, in the repository but not below: src/suzanne.gltf

## src/App.tsx

```tsx
import { CameraControls, Stage } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { DepthOfField, EffectComposer } from "@react-three/postprocessing";
import { useControls } from "leva";
import { Suspense } from "react";
import Model from "./Model";

const row = [
  { x: -4, z: 6 },
  { x: -2, z: 3 },
  { x: 0, z: 0 },
  { x: 2, z: -3 },
  { x: 4, z: -6 },
];

export default function App() {
  const { focusDistance, focusRange, bokehScale } = useControls({
    focusDistance: { value: 0.58, min: 0, max: 1, step: 0.01 },
    focusRange: { value: 0.1, min: 0, max: 1, step: 0.01 },
    bokehScale: { value: 5, min: 0, max: 10, step: 0.1 },
  });

  return (
    <Canvas
      shadows
      dpr={[1, 2]}
      camera={{ fov: 50, near: 1, far: 20, position: [0, 1.5, 12] }}
    >
      <color attach="background" args={["#111318"]} />
      <Suspense fallback={null}>
        <Stage
          preset="rembrandt"
          intensity={Math.PI}
          environment="city"
          adjustCamera={false}
        >
          {row.map(({ x, z }) => (
            <Model key={z} position={[x, 0, z]} />
          ))}
        </Stage>
        <EffectComposer autoClear={false}>
          <DepthOfField
            focusDistance={focusDistance}
            focusRange={focusRange}
            bokehScale={bokehScale}
          />
        </EffectComposer>
      </Suspense>
      <CameraControls makeDefault />
    </Canvas>
  );
}
```

## src/Model.tsx

```tsx
import { useRef } from "react";
import * as THREE from "three";
import { type GLTF } from "three-stdlib";
import { type ThreeElements } from "@react-three/fiber";
import { useGLTF } from "@react-three/drei";

import suzanneModel from "./suzanne.gltf?url";

type GLTFResult = GLTF & {
  nodes: {
    Suzanne: THREE.Mesh;
  };
};

export default function Model(props: ThreeElements["group"]) {
  const group = useRef<THREE.Group>(null!);
  const { nodes } = useGLTF(suzanneModel) as unknown as GLTFResult;

  return (
    <group ref={group} {...props} dispose={null}>
      <mesh
        castShadow
        receiveShadow
        geometry={nodes.Suzanne.geometry}
        material={nodes.Suzanne.material}
        material-color="#3b6df7"
        position={[0, 0.19, -0.04]}
      />
    </group>
  );
}

useGLTF.preload(suzanneModel);
```

## src/index.tsx

```tsx
import { createRoot } from "react-dom/client";
import "./styles.css";
import App from "./App";

createRoot(document.getElementById("root")!).render(<App />);
```

## src/styles.css

```css
* {
  box-sizing: border-box;
}

html,
body,
#root {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  background: #202020;
}
```

## src/vite-env.d.ts

```ts
/// <reference types="vite/client" />
```
