diff --git a/.storybook/stories/Grid.stories.tsx b/.storybook/stories/Grid.stories.tsx
new file mode 100644
index 000000000..47563592f
--- /dev/null
+++ b/.storybook/stories/Grid.stories.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react'
+import { Vector3 } from 'three'
+
+import { Setup } from '../Setup'
+import { Grid, Box } from '../../src'
+
+export default {
+ title: 'Gizmos/Grid',
+ component: Grid,
+ decorators: [(storyFn) => {storyFn()}],
+}
+
+function UseGridScene() {
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export const UseGridSceneSt = () =>
+UseGridSceneSt.story = {
+ name: 'Default',
+}
diff --git a/README.md b/README.md
index 6384943e3..3bea7de9d 100644
--- a/README.md
+++ b/README.md
@@ -56,6 +56,7 @@ The `native` route of the library **does not** export `Html` or `Loader`. The de
GizmoHelper
PivotControls
TransformControls
+ Grid
useHelper
Abstractions
@@ -647,6 +648,50 @@ If you are using other controls (Orbit, Trackball, etc), you will notice how the
```
+#### Grid
+
+[![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/gizmos-grid--use-grid-scene-st)
+
+
+
+
+
+A y-up oriented, shader-based grid implementation.
+
+```tsx
+export type GridMaterialType = {
+ /** Cell size, default: 0.5 */
+ cellSize?: number
+ /** Cell thickness, default: 0.5 */
+ cellThickness?: number
+ /** Cell color, default: black */
+ cellColor?: THREE.ColorRepresentation
+ /** Section size, default: 1 */
+ sectionSize?: number
+ /** Section thickness, default: 1 */
+ sectionThickness?: number
+ /** Section color, default: #2080ff */
+ sectionColor?: THREE.ColorRepresentation
+ /** Follow camera, default: false */
+ followCamera?: boolean
+ /** Display the grid infinitely, default: false */
+ infiniteGrid?: boolean
+ /** Fade distance, default: 100 */
+ fadeDistance?: number
+ /** Fade strength, default: 1 */
+ fadeStrength?: number
+}
+
+export type GridProps = GridMaterialType & {
+ /** Default plane-geometry arguments */
+ args?: ConstructorParameters
+}
+```
+
+```jsx
+
+```
+
#### useHelper
[![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-usehelper--default-story)
diff --git a/src/core/Grid.tsx b/src/core/Grid.tsx
new file mode 100644
index 000000000..9cbea70ae
--- /dev/null
+++ b/src/core/Grid.tsx
@@ -0,0 +1,126 @@
+/** Original grid component https://github.com/threlte/threlte/blob/main/packages/extras/src/lib/components/Grid/Grid.svelte
+ * By https://github.com/grischaerbe and https://github.com/jerzakm
+ */
+
+import * as React from 'react'
+import * as THREE from 'three'
+import { extend } from '@react-three/fiber'
+import { shaderMaterial } from './shaderMaterial'
+
+export type GridMaterialType = {
+ /** Cell size, default: 0.5 */
+ cellSize?: number
+ /** Cell thickness, default: 0.5 */
+ cellThickness?: number
+ /** Cell color, default: black */
+ cellColor?: THREE.ColorRepresentation
+ /** Section size, default: 1 */
+ sectionSize?: number
+ /** Section thickness, default: 1 */
+ sectionThickness?: number
+ /** Section color, default: #2080ff */
+ sectionColor?: THREE.ColorRepresentation
+ /** Follow camera, default: false */
+ followCamera?: boolean
+ /** Display the grid infinitely, default: false */
+ infiniteGrid?: boolean
+ /** Fade distance, default: 100 */
+ fadeDistance?: number
+ /** Fade strength, default: 1 */
+ fadeStrength?: number
+}
+
+export type GridProps = GridMaterialType & {
+ /** Default plane-geometry arguments */
+ args?: ConstructorParameters
+}
+
+declare global {
+ namespace JSX {
+ interface IntrinsicElements {
+ gridMaterial: JSX.IntrinsicElements['shaderMaterial'] & GridMaterialType
+ }
+ }
+}
+
+const GridMaterial = shaderMaterial(
+ {
+ cellSize: 0.5,
+ sectionSize: 1,
+ fadeDistance: 100,
+ fadeStrength: 1,
+ cellThickness: 0.5,
+ sectionThickness: 1,
+ cellColor: new THREE.Color(),
+ sectionColor: new THREE.Color(),
+ infiniteGrid: 0,
+ followCamera: 0,
+ },
+ `varying vec3 worldPosition;
+ uniform float fadeDistance;
+ uniform float infiniteGrid;
+ uniform float followCamera;
+ void main() {
+ vec3 pos = position.xzy * (1. + fadeDistance * infiniteGrid);
+ pos.xz += (cameraPosition.xz * followCamera);
+ worldPosition = pos;
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
+ }`,
+ `varying vec3 worldPosition;
+ uniform float cellSize;
+ uniform float sectionSize;
+ uniform vec3 cellColor;
+ uniform vec3 sectionColor;
+ uniform float fadeDistance;
+ uniform float fadeStrength;
+ uniform float cellThickness;
+ uniform float sectionThickness;
+ uniform float infiniteGrid;
+ float getGrid(float size, float thickness) {
+ vec2 r = worldPosition.xz / size;
+ vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r);
+ float line = min(grid.x, grid.y) + 1. - thickness;
+ return 1.0 - min(line, 1.);
+ }
+ void main() {
+ float g1 = getGrid(cellSize, cellThickness);
+ float g2 = getGrid(sectionSize, sectionThickness);
+ float d = 1.0 - min(distance(cameraPosition.xz, worldPosition.xz) / fadeDistance, 1.);
+ vec3 color = mix(cellColor, sectionColor, min(1.,sectionThickness * g2));
+ gl_FragColor = vec4(color, (g1 + g2) * pow(d,fadeStrength));
+ gl_FragColor.a = mix(0.75 * gl_FragColor.a, gl_FragColor.a, g2);
+ if (gl_FragColor.a <= 0.0) discard;
+ #include
+ #include
+ }`
+)
+
+export const Grid = React.forwardRef(
+ (
+ {
+ args,
+ cellColor = '#000000',
+ sectionColor = '#2080ff',
+ cellSize = 0.5,
+ sectionSize = 1,
+ followCamera = false,
+ infiniteGrid = false,
+ fadeDistance = 100,
+ fadeStrength = 1,
+ cellThickness = 0.5,
+ sectionThickness = 1,
+ ...props
+ }: Omit & GridProps,
+ fRef: React.ForwardedRef
+ ) => {
+ extend({ GridMaterial })
+ const uniforms1 = { cellSize, sectionSize, cellColor, sectionColor, cellThickness, sectionThickness }
+ const uniforms2 = { fadeDistance, fadeStrength, infiniteGrid, followCamera }
+ return (
+
+
+
+
+ )
+ }
+)
diff --git a/src/core/index.ts b/src/core/index.ts
index 9d511b0f1..3f9dd3a27 100644
--- a/src/core/index.ts
+++ b/src/core/index.ts
@@ -41,6 +41,7 @@ export * from './FirstPersonControls'
export * from './GizmoHelper'
export * from './GizmoViewcube'
export * from './GizmoViewport'
+export * from './Grid'
// Loaders
export * from './useCubeTexture'
diff --git a/yarn.lock b/yarn.lock
index f1f9a5d76..1053910ab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8684,7 +8684,7 @@ lodash.merge@^4.6.2:
lodash.omit@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
- integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=
+ integrity sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==
lodash.pick@^4.4.0:
version "4.4.0"