Skip to content

Commit

Permalink
flowmap
Browse files Browse the repository at this point in the history
  • Loading branch information
clementroche committed Jan 20, 2025
1 parent dc25bf3 commit 4408564
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 131 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
},
"[javascriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
42 changes: 28 additions & 14 deletions components/animated-gradient/material.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
Vector2,
type WebGLProgramParametersWithUniforms,
} from 'three'
import type { Fluid } from '~/libs/webgl/utils/fluid'
import { NOISE } from '~/libs/webgl/utils/noise'
import type { Flowmap } from './../../libs/webgl/utils/flowmap'

export class AnimatedGradientMaterial extends MeshBasicMaterial {
private uniforms: {
Expand All @@ -18,7 +20,12 @@ export class AnimatedGradientMaterial extends MeshBasicMaterial {
uColorsTexture: { value: Texture | null }
uOffset: { value: number }
uQuantize: { value: number }
uFlowmap: { value: Texture | null }
uFlowmap:
| Flowmap
| Fluid
| {
value: null
}
uDpr: { value: number }
}

Expand All @@ -38,12 +45,22 @@ export class AnimatedGradientMaterial extends MeshBasicMaterial {
colorFrequency = 0.33,
quantize = 0,
radial = false,
flowmap = true,
} = {}) {
flowmap,
}: {
frequency?: number
amplitude?: number
colorAmplitude?: number
colorFrequency?: number
quantize?: number
radial?: boolean
flowmap?: Flowmap | Fluid
}) {
super({
transparent: true,
})

console.log(flowmap.uniform)

this.uniforms = {
uTime: { value: 0 },
uAmplitude: { value: amplitude },
Expand All @@ -55,12 +72,15 @@ export class AnimatedGradientMaterial extends MeshBasicMaterial {
uColorsTexture: { value: null },
uOffset: { value: radial ? Math.random() * 1000 : 0 },
uQuantize: { value: quantize },
uFlowmap: { value: null },
uFlowmap: flowmap?.uniform || {
value: null,
},
uDpr: { value: 1 },
}

this.defines = {
USE_RADIAL: radial,
USE_FLOWMAP: flowmap,
USE_FLOWMAP: !!flowmap,
USE_UV: true,
}

Expand Down Expand Up @@ -127,7 +147,7 @@ export class AnimatedGradientMaterial extends MeshBasicMaterial {
# ifdef USE_FLOWMAP
vec4 flow = texture2D(uFlowmap, fragCoord / (uResolution.xy * uDpr));
flow *= 0.00025;
flow *= 0.0025;
screenUV += flow.rg;
# endif
Expand Down Expand Up @@ -158,6 +178,8 @@ export class AnimatedGradientMaterial extends MeshBasicMaterial {
alpha = alpha - rand(fragCoord) * 0.05;
vec4 diffuseColor = vec4( color, alpha );
// diffuseColor = texture2D(uFlowmap, fragCoord / (uResolution.xy * uDpr));
`
)
}
Expand Down Expand Up @@ -221,12 +243,4 @@ export class AnimatedGradientMaterial extends MeshBasicMaterial {
set quantize(value) {
this.uniforms.uQuantize.value = value
}

get flowmap() {
return this.uniforms.uFlowmap.value
}

set flowmap(value) {
this.uniforms.uFlowmap.value = value
}
}
11 changes: 4 additions & 7 deletions components/animated-gradient/webgl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ export function WebGLAnimatedGradient({
colorFrequency = 0.33,
quantize = 0,
radial = false,
flowmap = true,
flowmap: hasFlowmap = true,
colors = ['#ff0000', '#000000'],
speed = 1,
}: WebGLAnimatedGradientProps) {
const flowmap = useFlowmap('fluid')

const [material] = useState(
() =>
new AnimatedGradientMaterial({
Expand All @@ -80,14 +82,10 @@ export function WebGLAnimatedGradient({
colorFrequency,
quantize,
radial,
flowmap,
flowmap: hasFlowmap && flowmap,
})
)

useFlowmap((texture) => {
material.flowmap = texture
})

const gradientTexture = useGradient(colors)

useEffect(() => {
Expand Down Expand Up @@ -129,7 +127,6 @@ export function WebGLAnimatedGradient({
const viewport = useThree((state) => state.viewport)

useEffect(() => {
console.log(viewport.dpr)
material.dpr = viewport.dpr
}, [material, viewport])

Expand Down
5 changes: 4 additions & 1 deletion libs/webgl/components/canvas/webgl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { OrthographicCamera } from '@react-three/drei'
import { Canvas } from '@react-three/fiber'
import { Suspense } from 'react'
import { SheetProvider } from '~/libs/theatre'
import { FlowmapProvider } from '../flowmap'
import { PostProcessing } from '../postprocessing'
Expand Down Expand Up @@ -54,7 +55,9 @@ export function WebGLCanvas({
<RAF render={render} />
<FlowmapProvider>
{postprocessing && <PostProcessing />}
<WebGLTunnel.Out />
<Suspense>
<WebGLTunnel.Out />
</Suspense>
</FlowmapProvider>
<Preload />
</SheetProvider>
Expand Down
116 changes: 42 additions & 74 deletions libs/webgl/components/flowmap/index.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,33 @@
import { useFrame, useThree } from '@react-three/fiber'
import { types } from '@theatre/core'
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
} from 'react'
import type { Texture } from 'three'
import { createContext, useContext, useMemo } from 'react'
import { useCurrentSheet } from '~/libs/theatre'
import { useTheatre } from '~/libs/theatre/hooks/use-theatre'
import FluidSimulation from '~/libs/webgl/utils/fluid-simulation'
import { Flowmap } from '~/libs/webgl/utils/flowmap'
import { Fluid } from '~/libs/webgl/utils/fluid'

type FlowmapContextType = {
addCallback: (callback: FlowmapCallback) => void
removeCallback: (callback: FlowmapCallback) => void
fluid: Fluid
flowmap: Flowmap
}

type FlowmapCallback = (texture: Texture) => void

export const FlowmapContext = createContext<FlowmapContextType>(
{} as FlowmapContextType
)

export function useFlowmap(callback: FlowmapCallback) {
const { addCallback, removeCallback } = useContext(FlowmapContext)

// biome-ignore lint/correctness/useExhaustiveDependencies: callback as deps can trigger infinite re-renders
useEffect(() => {
if (!callback) return
export function useFlowmap(type: 'fluid' | 'flowmap' = 'flowmap') {
const { fluid, flowmap } = useContext(FlowmapContext)

addCallback(callback)

return () => {
removeCallback(callback)
}
}, [addCallback, removeCallback])

return useContext(FlowmapContext)
if (type === 'fluid') return fluid
return flowmap
}

export function FlowmapProvider({ children }: { children: React.ReactNode }) {
const gl = useThree((state) => state.gl)

const fluidSimulation = useMemo(
() => new FluidSimulation({ renderer: gl, size: 128 }),
[gl]
)
const fluid = useMemo(() => new Fluid(gl, { size: 128 }), [gl])

const flowmap = useMemo(() => new Flowmap(gl, { size: 128 }), [gl])

const sheet = useCurrentSheet()

Expand Down Expand Up @@ -75,57 +55,45 @@ export function FlowmapProvider({ children }: { children: React.ReactNode }) {
curl: number
radius: number
}) => {
fluidSimulation.curlStrength = curl
fluidSimulation.densityDissipation = density
fluidSimulation.velocityDissipation = velocity
fluidSimulation.pressureDissipation = pressure
fluidSimulation.radius = radius
fluid.curlStrength = curl
fluid.densityDissipation = density
fluid.velocityDissipation = velocity
fluid.pressureDissipation = pressure
fluid.radius = radius
},
deps: [fluidSimulation],
deps: [fluid],
}
)

// const [texture, setTexture] = useState()

const textureRef = useRef()

// const getTexture = useCallback(() => textureRef.current, [])

const callbacksRefs = useRef<FlowmapCallback[]>([])

const addCallback = useCallback((callback: FlowmapCallback) => {
callbacksRefs.current.push(callback)
}, [])

const removeCallback = useCallback((callback: FlowmapCallback) => {
callbacksRefs.current = callbacksRefs.current.filter(
(ref) => ref !== callback
)
}, [])

const update = useCallback(() => {
for (const callback of callbacksRefs.current) {
callback(textureRef.current as unknown as Texture)
useTheatre(
sheet,
'flowmap',
{
falloff: types.number(0.2, { range: [0, 1], nudgeMultiplier: 0.01 }),
dissipation: types.number(0.98, { range: [0, 1], nudgeMultiplier: 0.01 }),
},
{
onValuesChange: ({
falloff,
dissipation,
}: {
falloff: number
dissipation: number
}) => {
flowmap.falloff = falloff
flowmap.dissipation = dissipation
},
deps: [flowmap],
}
}, [])

useFrame(({ gl }) => {
if (callbacksRefs.current.length === 0) return

textureRef.current = fluidSimulation.update()
update()
)

gl.setRenderTarget(null)
gl.clear()
useFrame(() => {
fluid.update()
flowmap.update()
}, -10)

return (
<FlowmapContext.Provider
value={{
addCallback,
removeCallback,
}}
>
<FlowmapContext.Provider value={{ fluid, flowmap }}>
{children}
</FlowmapContext.Provider>
)
Expand Down
13 changes: 13 additions & 0 deletions libs/webgl/utils/blend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,17 @@ export const BLEND = {
return (blendColorDodge(base, blend) * opacity + base * (1.0 - opacity));
}
`,
ADD: /* glsl */ `
float blendAdd(float base, float blend) {
return min(base+blend,1.0);
}
vec3 blendAdd(vec3 base, vec3 blend) {
return min(base+blend,vec3(1.0));
}
vec3 blendAdd(vec3 base, vec3 blend, float opacity) {
return (blendAdd(base, blend) * opacity + base * (1.0 - opacity));
}
`,
} as const
Loading

1 comment on commit 4408564

@github-actions
Copy link

Choose a reason for hiding this comment

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

⚡️ Lighthouse report for the changes in this commit:

🟢 Performance: 97
🟢 Accessibility: 90
🟢 Best practices: 96
🟠 SEO: 63

Lighthouse ran on https://satus-pi9godl3p-darkroom-engineering.vercel.app/

Please sign in to comment.