From ddc8a4e4a5911d2d76b77569d70dfe1be589cf09 Mon Sep 17 00:00:00 2001 From: Antoine BERNIER Date: Tue, 25 Jul 2023 14:11:50 +0200 Subject: [PATCH] feat: add Example effect --- .storybook/stories/Example.stories.tsx | 48 ++++++++++++++++ src/effects/Example.tsx | 77 ++++++++++++++++++++++++++ src/index.tsx | 1 + 3 files changed, 126 insertions(+) create mode 100644 .storybook/stories/Example.stories.tsx create mode 100644 src/effects/Example.tsx diff --git a/.storybook/stories/Example.stories.tsx b/.storybook/stories/Example.stories.tsx new file mode 100644 index 00000000..abb4b933 --- /dev/null +++ b/.storybook/stories/Example.stories.tsx @@ -0,0 +1,48 @@ +import React, { memo } from 'react' +import * as THREE from 'three' +import type { Meta, StoryObj } from '@storybook/react' +import { Box, useTexture } from '@react-three/drei' + +import { Setup } from '../Setup' +import { EffectComposer, Example } from '../../src' +import { BlendFunction } from 'postprocessing' + +// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction +const meta = { + title: 'Effect/Example', + component: Example, + decorators: [(Story) => {Story()}], + tags: ['autodocs'], + argTypes: { + blendFunction: { + control: 'select', + options: Object.keys(BlendFunction), + mapping: Object.keys(BlendFunction).reduce((acc, k) => { + acc[k] = BlendFunction[k] + return acc + }, {}), + }, + opacity: { control: { type: 'range', min: 0, max: 1, step: 0.001 } }, + color: { control: { type: 'color' } }, + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args +export const Primary: Story = { + render: ({ color, ...args }) => ( + <> + + + + + + + ), + args: { + blendFunction: BlendFunction.ADD, + color: 'red' as unknown as THREE.Color, + }, +} diff --git a/src/effects/Example.tsx b/src/effects/Example.tsx new file mode 100644 index 00000000..b3ef27b0 --- /dev/null +++ b/src/effects/Example.tsx @@ -0,0 +1,77 @@ +import * as THREE from 'three' +import { useRef } from 'react' +import { useFrame, useThree } from '@react-three/fiber' +import { BlendFunction, Effect } from 'postprocessing' + +import { wrapEffect } from '../util' + +// +// Effect +// + +const ExampleShader = { + fragment: ` + uniform vec3 color; + uniform float time; + + void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) { + outputColor = vec4(color, 0.5 + (cos(time) / 2.0 + 0.5)); + } + `, +} + +type ExampleEffectOptions = { + /** The color for this effect */ + color: THREE.Color + /** The blend function of this effect */ + blendFunction?: BlendFunction +} + +export class ExampleEffect extends Effect { + constructor({ color, blendFunction }: ExampleEffectOptions) { + super('LensFlareEffect', ExampleShader.fragment, { + blendFunction, + uniforms: new Map([ + ['color', new THREE.Uniform(color)], + ['time', new THREE.Uniform(0)], + ]), + }) + } + + update(_renderer: any, _inputBuffer: any, deltaTime: number) { + const time = this.uniforms.get('time') + if (time) { + time.value += deltaTime + } + } +} + +// +// Component +// + +const ExampleWrapped = wrapEffect(ExampleEffect) + +type ExampleProps = React.ComponentPropsWithoutRef & { + /** mouse */ + mouse?: boolean +} + +export const Example = ({ mouse = false, ...props }: ExampleProps) => { + const pointer = useThree(({ pointer }) => pointer) + + const ref = useRef(null) + + useFrame(() => { + if (!mouse) return + if (!ref?.current) return + + const uColor = ref.current.uniforms.get('color') + if (!uColor) return + + uColor.value.r = pointer.x / 2.0 + 0.5 + uColor.value.g = pointer.y / 2.0 + 0.5 + }) + + return +} diff --git a/src/index.tsx b/src/index.tsx index c13a02f5..71816ee4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -12,6 +12,7 @@ export * from './effects/ColorDepth' export * from './effects/Depth' export * from './effects/DepthOfField' export * from './effects/DotScreen' +export * from './effects/Example' export * from './effects/Glitch' export * from './effects/GodRays' export * from './effects/Grid'