Skip to content

Exports components and utilities to implement flexible shader passes using react-three-fiber

Notifications You must be signed in to change notification settings

theCocoonStudio/react-three-shader-passes

Repository files navigation

react-three-shader-passes (DRAFT)

Note: react-three-shader-passes (R3SP) is currently still in pre-release stages.

This library is designed for Three.js/React apps built on react-three-fiber (R3F). Check out and support the ecosystem and @pmndrs.

→ Easily chain shader passes, using the rendered texture from one scene as a uniform type input to any other shader pass

→ Ideal for raw physics simulations and for effects, post processing, optimization, and complex shader-based logic

→ Use output textures of any scene or shader as an FBO input to another without cumbersome, hierarchical JSX code or complex ref-based code design

→ Use chaining capabilities as a GPGPU solution that's fully hooked into your React app, or as a simple framework for modular shader logic

→ Fully declarative API and implementation for a turnkey R3F integration

→ Exports additional utilities and helpers for even more R3F syntactic sugar

→ Fully managed objects/components implemented on top of R3F ecosystem; you have full control of all objects but do not have to worry about memory if you don't need to

Usage

Use with react-three-fiber to create chained, modular shader passes.

npm i [TODO]

ShaderPass is just a wrapper of RenderTexture under the hood. You place instances of it in a ShaderPassesTexture to easily use the output texture of any other ShaderPass render.

This is best illustrated with an example. The code below renders two scenes in a portal using RenderTexture and accepts all props that RenderTexture does.

In addition to accepting the same children as RenderTexture, ShaderPass optionally takes as children a function, (fbos) => children. fbos contains refs to each scene's FBO texture output, keyed by the name prop of the corresponding ShaderPass.

The code snippet below shows an invisible scene being rendered and its output being used as an input uniform FBO texture to the fragment shader of a THREE.RawShaderMaterial used in a second invisible scene. The output of the second scene is then attached as the map to a material in a third, visible scene.

// Example
<mesh>
  <Geometry />
  <meshStandardMaterial>
    <ShaderPassesTexture>
      <ShaderPass name="firstPass">
        <Camera />
        <mesh>
          <Geometry/>
          <ShaderMaterial {...uniforms} />
        </mesh>
      </ShaderPass>
      <ShaderPass name="secondPass" attach="map">
        {(fbos) => (
          <>
            <Camera2 />
            <mesh>
              <Geometry/>
              <ShaderMaterial2
                {
                ...uniforms2,
                inputFbo: fbos?.firstPass.current
                }
              />
            </mesh>
          </>
        )}
      </ShaderPass>
    </ShaderPassesTexture>
  </meshStandardMaterial>
</mesh>

Exports

  1. ShaderPassesTexture
  2. ShaderPass
  3. GetParent & withParent

import { ShaderPassesTexture } from 'react-three-shader-passes'

Wraps any number of ShaderPass components among its props.children and registers their output textures to pass through to ShaderPass instances that need to use them (e.g., as a shader uniform input for further calculations).

prop type description
children React.ReactNode | React.ReactNode[] ShaderPass instances can be rendered at any level in the children tree.

To benefit from this API, at least one of these ShaderPass instances should utilize the function-as-children pattern to access another ShaderPass's output.

Otherwise, use RenderTexture instead of ShaderPass and omit this component.

Behaves exactly as RenderTexture, which it renders at the top level.

The only difference is that ShaderPass must be rendered as a descendent of ShaderPassesTexture and can, in addition to a React.ReactNode, optionally take a single function (fbos) => React.ReactNode as children.

import { ShaderPass } from 'react-three-shader-passes'
prop type description
children React.ReactNode | (fbos) => React.ReactNode As plain JSX, identical to @pmndrs/drei/RenderTexture's props.children.

Alternatively, a function that returns the above. It will be called with one argument: an object containing the textures from any other ShaderPass in the same ShaderPassesTexture, keyed by props.name.
<ShaderPass name="somePass">
  ...
</ShaderPass>
<ShaderPass name="someOtherPass" />
  {
    ({ somePass }) => 
      <>
        ...
        <ShaderMaterial someUniform={somePass.current}/>
        ...
      </>
  }
</ShaderPass>
      
name string Required. In the object passed as argument to any props.children in function form, this will be used as a property name referencing the texture returned from the underlying RenderTexture
...RenderTextureProps Object Props that go into a RenderTexture. E.g., setting props.renderPriority allows you to control the rendering order of the shader passes.
import { getParent, withParent } from 'react-three-shader-passes'

An alternative to using instance.__r3f.parent (see useInstanceHandle here).

Provides a React ref to the parent of non-Object3D primitives (e.g. materials). Unlike Object3D instances, these do not have a built-in (.parent) reference to the containing object in the scene graph.

Using inside a component:

function MaterialWithParentInternal(props) {
  const parent = useRef()
  useEffect(() => {
    console.log(parent.current), [parent]
  })
  return (
    <>
      <meshStandardMaterial {...props} />
      <GetParent ref={parent} />
    </>
  )
}

Using inside the component and exposing to parent:

forwardRef(function MaterialWithParentInternalAndExternal(props, ref) {
  const internal = useRef()
  const parent = useRef()
  useImperativeHandle(ref, () => ({ ...internal.current, parent: parent.current }))
  return (
    <>
      <meshStandardMaterial ref={internal} {...props} />
      <GetParent ref={parent} />
    </>
  )
})

Only exposing to parent (ref will include added .parent property):

const MyMaterialWithParentExternal = withParent(MyMaterial)
const Anscestor = () => {
  const descendentParent = useRef()
  useEffect(() => {
    console.log(descendentParent.current.parent)
  }, [])
  return <MyMaterialWithParentExternal ref={descendentParent} />
}

Optional custom parent key:

const MyMaterialWithParentExternal = withParent(MyMaterial, 'parentKey')
const Anscestor = () => {
  const descendentParent = useRef()
  useEffect(() => {
    console.log(descendentParent.current.parentKey)
  }, [])
  return <MyMaterialWithParentExternal ref={descendantParent} />
}

About

Exports components and utilities to implement flexible shader passes using react-three-fiber

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published