Skip to content

Commit

Permalink
feat: grid (#1186)
Browse files Browse the repository at this point in the history
* feat: grid

* chore: cleanup

* fix: axes seems unnecessary if we can just rotate it

* chore: cleanup

* chore: cleanup

* chore: add story
  • Loading branch information
drcmda committed Dec 17, 2022
1 parent 16f1caf commit d8c2d84
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 1 deletion.
28 changes: 28 additions & 0 deletions .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) => <Setup cameraPosition={new Vector3(-5, 5, 10)}>{storyFn()}</Setup>],
}

function UseGridScene() {
return (
<React.Suspense fallback={null}>
<Grid cellColor="white" args={[10, 10]} />
<Box position={[0, 0.5, 0]}>
<meshStandardMaterial />
</Box>
<directionalLight position={[10, 10, 5]} />
</React.Suspense>
)
}

export const UseGridSceneSt = () => <UseGridScene />
UseGridSceneSt.story = {
name: 'Default',
}
45 changes: 45 additions & 0 deletions README.md
Expand Up @@ -56,6 +56,7 @@ The `native` route of the library **does not** export `Html` or `Loader`. The de
<li><a href="#gizmohelper">GizmoHelper</a></li>
<li><a href="#pivotcontrols">PivotControls</a></li>
<li><a href="#transformcontrols">TransformControls</a></li>
<li><a href="#grid">Grid</a></li>
<li><a href="#usehelper">useHelper</a></li>
</ul>
<li><a href="#abstractions">Abstractions</a></li>
Expand Down Expand Up @@ -647,6 +648,50 @@ If you are using other controls (Orbit, Trackball, etc), you will notice how the
<OrbitControls makeDefault />
```

#### Grid

[![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/gizmos-grid--use-grid-scene-st)

<p>
<a href="https://codesandbox.io/s/imreeu"><img width="20%" src="https://codesandbox.io/api/v1/sandboxes/imreeu/screenshot.png" alt="Demo"/></a>
</p>

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<typeof THREE.PlaneGeometry>
}
```

```jsx
<Grid />
```

#### useHelper

[![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-usehelper--default-story)
Expand Down
126 changes: 126 additions & 0 deletions 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<typeof THREE.PlaneGeometry>
}

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 <tonemapping_fragment>
#include <encodings_fragment>
}`
)

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<JSX.IntrinsicElements['mesh'], 'args'> & GridProps,
fRef: React.ForwardedRef<THREE.Mesh>
) => {
extend({ GridMaterial })
const uniforms1 = { cellSize, sectionSize, cellColor, sectionColor, cellThickness, sectionThickness }
const uniforms2 = { fadeDistance, fadeStrength, infiniteGrid, followCamera }
return (
<mesh ref={fRef} rotation-x={Math.PI} frustumCulled={false} {...props}>
<gridMaterial transparent extensions-derivatives {...uniforms1} {...uniforms2} />
<planeGeometry args={args} />
</mesh>
)
}
)
1 change: 1 addition & 0 deletions src/core/index.ts
Expand Up @@ -41,6 +41,7 @@ export * from './FirstPersonControls'
export * from './GizmoHelper'
export * from './GizmoViewcube'
export * from './GizmoViewport'
export * from './Grid'

// Loaders
export * from './useCubeTexture'
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Expand Up @@ -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"
Expand Down

1 comment on commit d8c2d84

@vercel
Copy link

@vercel vercel bot commented on d8c2d84 Dec 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.