JSPM

  • Created
  • Published
  • Downloads 170
  • Score
    100M100P100Q74864F
  • License MIT

postprocessing wrapper for React and react-three-fiber

Package Exports

  • react-postprocessing

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-postprocessing) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

react-postprocessing

npm npm

postprocessing wrapper for React.

Why

Instead of manually initializing the composer and adding required passes you can import the effects as components and put them inside <EffectComposer />.

Installation

yarn add postprocessing react-postprocessing

Effects

For a list of effects, examples and props usage, check effects.md.

Getting Started

Effect composer

Passing effects

All effects are consumed by effect composer, EffectComposer, that creates passes and other things required for compositor to work.

You can pass effects using children:

import React, { useState } from 'react'
import { EffectComposer, Glitch } from 'react-postprocessing'
import { Canvas } from 'react-three-fiber'

const App = () => {
  const [isTriggered, setTriggered] = useState(false)

  return (
    <Canvas>
      <mesh onClick={() => setTriggered(!isTriggered)}>
        <boxGeometry args={[1, 1, 1]} />
        <meshBasicMaterial color="red" />
      </mesh>
      <Suspense>
        <EffectComposer>
          <Glitch active={isTriggered} />
        </EffectComposer>
      </Suspense>
    </Canvas>
  )
}

SMAA

By default, SMAA is enabled in EffectComposer. When enabled, you can pass additional properties for configuring SMAA, such as edgeDetection, which sets edge detection threshold.

<Suspense fallback={null}>
  <EffectComposer smaa edgeDetection={0.3}>
    <Glitch />
  </EffectComposer>
</Suspense>

Adding effects

When you want to add a new effect your react-three-fiber component you first need to import the effect and then put it in children.

import React from 'react'
import { EffectComposer, Scanline } from 'react-postprocessing'
import { Canvas } from 'react-three-fiber'

const App = () => (
  <Canvas>
    <mesh>
      <boxGeometry args={[1, 1, 1]} />
      <meshBasicMaterial color="red" />
    </mesh>
    <Suspense>
      <EffectComposer>
        <Scanline />
      </EffectComposer>
    </Suspense>
  </Canvas>
)

Effects settings

Every effect inherits all the props from original postprocessing class, for example:

import React from 'react'
import { EffectComposer, Glitch } from 'react-postprocessing'
import { Canvas } from 'react-three-fiber'

const App = () => (
  <Canvas>
    <mesh>
      <boxGeometry args={[1, 1, 1]} />
      <meshBasicMaterial color="red" />
    </mesh>
    <Suspense>
      <EffectComposer>
          {/* min and max duration */}
        <Glitch duration={[1, 2]} />
      </EffectComposer>
    </Suspense>
  </Canvas>
)

Custom effects

Currently not all of the effects are wrapped, so if you require some effects that isn't wrapped yet you cand add them manually.

Using wrapEffect

There is an utility function in react-postprocessing which wraps the postprocessing effect in React component. You can use it to quickly make a component out of effect:

import React from 'react'
import { EffectComposer, wrapEffect } from 'react-postprocessing'
import { NoiseEffect } from 'postprocessing'
import { Canvas } from 'react-three-fiber'

const Noise = wrapEffect(NoiseEffect)

const App = () => (
  <Canvas>
    <mesh>
      <boxGeometry args={[1, 1, 1]} />
      <meshBasicMaterial color="red" />
    </mesh>
    <Suspense>
      <EffectComposer>
        <Noise />
      </EffectComposer>
    </Suspense>
  </Canvas>
)

Currently types aren't being passed properly in wrapEffect, it returns RefWithExoticComponent<any> where instead of any should be the effect class. Feel free to submit a PR to fix it!

From scratch

If the effect doesn't use object literals for props, PixelationEffect for instance, you can wrap your own component using forwardRef and useImperativeHandle and define your own props:

import { forwardRef, useImperativeHandle, useMemo } from 'react'
import { PixelationEffect } from 'postprocessing'

export const Pixelation = forwardRef(({ granularity = 5 }, ref) => {
  const effect = useMemo(() => new PixelationEffect(granularity), [granularity])

  useImperativeHandle(ref, () => effect, [effect])

  return null
})

In case you want to do add a custom prop that isn't inherited from postprocessing you should watch this prop with useLayoutEffect:

import { forwardRef, useMemo, useImperativeHandle, useLayoutEffect } from 'react'
import { useThree, ReactThreeFiber } from 'react-three-fiber'
import { DepthOfFieldEffect } from 'postprocessing'
import { Texture } from 'three'

export const DepthOfField = forwardRef(({ target, depthTexture, ...props }, ref) => {
  const { camera } = useThree()

  const effect = useMemo(() => new DepthOfFieldEffect(camera, props), [props])

  // custom `depthTexture` prop
  useLayoutEffect(() => {
    if (depthTexture) {
      effect.setDepthTexture(depthTexture.texture, depthTexture.packing)
    }
  }, [depthTexture])

  useImperativeHandle(ref, () => effect, [effect])
  return null
})