From 6cd3339d01fb0a88696df54dfe1e6c70ba2a9e68 Mon Sep 17 00:00:00 2001 From: msafdev Date: Tue, 22 Jul 2025 10:00:24 +0700 Subject: [PATCH] feat: optimize dither backgrounds --- src/content/Backgrounds/Dither/Dither.jsx | 61 +++++++++++------ src/tailwind/Backgrounds/Dither/Dither.jsx | 59 ++++++++++------ src/ts-default/Backgrounds/Dither/Dither.tsx | 68 +++++++++++-------- src/ts-tailwind/Backgrounds/Dither/Dither.tsx | 49 +++++++------ 4 files changed, 148 insertions(+), 89 deletions(-) diff --git a/src/content/Backgrounds/Dither/Dither.jsx b/src/content/Backgrounds/Dither/Dither.jsx index 5ffda434..e879f2fe 100644 --- a/src/content/Backgrounds/Dither/Dither.jsx +++ b/src/content/Backgrounds/Dither/Dither.jsx @@ -1,11 +1,11 @@ /* eslint-disable react/no-unknown-property */ -import { useRef, useState, useEffect, forwardRef } from "react"; +import { useRef, useEffect, forwardRef } from "react"; import { Canvas, useFrame, useThree } from "@react-three/fiber"; import { EffectComposer, wrapEffect } from "@react-three/postprocessing"; import { Effect } from "postprocessing"; import * as THREE from "three"; -import './Dither.css'; +import "./Dither.css"; const waveVertexShader = ` precision highp float; @@ -63,7 +63,7 @@ float cnoise(vec2 P) { return 2.3 * mix(n_x.x, n_x.y, fade_xy.y); } -const int OCTAVES = 8; +const int OCTAVES = 4; float fbm(vec2 p) { float value = 0.0; float amp = 1.0; @@ -78,7 +78,7 @@ float fbm(vec2 p) { float pattern(vec2 p) { vec2 p2 = p - time * waveSpeed; - return fbm(p - fbm(p + fbm(p2))); + return fbm(p + fbm(p2)); } void main() { @@ -143,10 +143,18 @@ class RetroEffectImpl extends Effect { super("RetroEffect", ditherFragmentShader, { uniforms }); this.uniforms = uniforms; } - set colorNum(v) { this.uniforms.get("colorNum").value = v; } - get colorNum() { return this.uniforms.get("colorNum").value; } - set pixelSize(v) { this.uniforms.get("pixelSize").value = v; } - get pixelSize() { return this.uniforms.get("pixelSize").value; } + set colorNum(v) { + this.uniforms.get("colorNum").value = v; + } + get colorNum() { + return this.uniforms.get("colorNum").value; + } + set pixelSize(v) { + this.uniforms.get("pixelSize").value = v; + } + get pixelSize() { + return this.uniforms.get("pixelSize").value; + } } const WrappedRetro = wrapEffect(RetroEffectImpl); @@ -169,7 +177,7 @@ function DitheredWaves({ mouseRadius, }) { const mesh = useRef(null); - const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); + const mouseRef = useRef(new THREE.Vector2()); const { viewport, size, gl } = useThree(); const waveUniformsRef = useRef({ @@ -194,17 +202,30 @@ function DitheredWaves({ } }, [size, gl]); + const prevColor = useRef([...waveColor]); useFrame(({ clock }) => { const u = waveUniformsRef.current; - if (!disableAnimation) u.time.value = clock.getElapsedTime(); - u.waveSpeed.value = waveSpeed; - u.waveFrequency.value = waveFrequency; - u.waveAmplitude.value = waveAmplitude; - u.waveColor.value.set(...waveColor); + + if (!disableAnimation) { + u.time.value = clock.getElapsedTime(); + } + + if (u.waveSpeed.value !== waveSpeed) u.waveSpeed.value = waveSpeed; + if (u.waveFrequency.value !== waveFrequency) + u.waveFrequency.value = waveFrequency; + if (u.waveAmplitude.value !== waveAmplitude) + u.waveAmplitude.value = waveAmplitude; + + if (!prevColor.current.every((v, i) => v === waveColor[i])) { + u.waveColor.value.set(...waveColor); + prevColor.current = [...waveColor]; + } + u.enableMouseInteraction.value = enableMouseInteraction ? 1 : 0; u.mouseRadius.value = mouseRadius; + if (enableMouseInteraction) { - u.mousePos.value.set(mousePos.x, mousePos.y); + u.mousePos.value.copy(mouseRef.current); } }); @@ -212,10 +233,10 @@ function DitheredWaves({ if (!enableMouseInteraction) return; const rect = gl.domElement.getBoundingClientRect(); const dpr = gl.getPixelRatio(); - setMousePos({ - x: (e.clientX - rect.left) * dpr, - y: (e.clientY - rect.top) * dpr, - }); + mouseRef.current.set( + (e.clientX - rect.left) * dpr, + (e.clientY - rect.top) * dpr + ); }; return ( @@ -277,4 +298,4 @@ export default function Dither({ /> ); -} \ No newline at end of file +} diff --git a/src/tailwind/Backgrounds/Dither/Dither.jsx b/src/tailwind/Backgrounds/Dither/Dither.jsx index 80f92779..3e794678 100644 --- a/src/tailwind/Backgrounds/Dither/Dither.jsx +++ b/src/tailwind/Backgrounds/Dither/Dither.jsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-unknown-property */ -import { useRef, useState, useEffect, forwardRef } from "react"; +import { useRef, useEffect, forwardRef } from "react"; import { Canvas, useFrame, useThree } from "@react-three/fiber"; import { EffectComposer, wrapEffect } from "@react-three/postprocessing"; import { Effect } from "postprocessing"; @@ -61,7 +61,7 @@ float cnoise(vec2 P) { return 2.3 * mix(n_x.x, n_x.y, fade_xy.y); } -const int OCTAVES = 8; +const int OCTAVES = 4; float fbm(vec2 p) { float value = 0.0; float amp = 1.0; @@ -76,7 +76,7 @@ float fbm(vec2 p) { float pattern(vec2 p) { vec2 p2 = p - time * waveSpeed; - return fbm(p - fbm(p + fbm(p2))); + return fbm(p + fbm(p2)); } void main() { @@ -141,10 +141,18 @@ class RetroEffectImpl extends Effect { super("RetroEffect", ditherFragmentShader, { uniforms }); this.uniforms = uniforms; } - set colorNum(v) { this.uniforms.get("colorNum").value = v; } - get colorNum() { return this.uniforms.get("colorNum").value; } - set pixelSize(v) { this.uniforms.get("pixelSize").value = v; } - get pixelSize() { return this.uniforms.get("pixelSize").value; } + set colorNum(v) { + this.uniforms.get("colorNum").value = v; + } + get colorNum() { + return this.uniforms.get("colorNum").value; + } + set pixelSize(v) { + this.uniforms.get("pixelSize").value = v; + } + get pixelSize() { + return this.uniforms.get("pixelSize").value; + } } const WrappedRetro = wrapEffect(RetroEffectImpl); @@ -167,7 +175,7 @@ function DitheredWaves({ mouseRadius, }) { const mesh = useRef(null); - const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); + const mouseRef = useRef(new THREE.Vector2()); const { viewport, size, gl } = useThree(); const waveUniformsRef = useRef({ @@ -192,17 +200,30 @@ function DitheredWaves({ } }, [size, gl]); + const prevColor = useRef([...waveColor]); useFrame(({ clock }) => { const u = waveUniformsRef.current; - if (!disableAnimation) u.time.value = clock.getElapsedTime(); - u.waveSpeed.value = waveSpeed; - u.waveFrequency.value = waveFrequency; - u.waveAmplitude.value = waveAmplitude; - u.waveColor.value.set(...waveColor); + + if (!disableAnimation) { + u.time.value = clock.getElapsedTime(); + } + + if (u.waveSpeed.value !== waveSpeed) u.waveSpeed.value = waveSpeed; + if (u.waveFrequency.value !== waveFrequency) + u.waveFrequency.value = waveFrequency; + if (u.waveAmplitude.value !== waveAmplitude) + u.waveAmplitude.value = waveAmplitude; + + if (!prevColor.current.every((v, i) => v === waveColor[i])) { + u.waveColor.value.set(...waveColor); + prevColor.current = [...waveColor]; + } + u.enableMouseInteraction.value = enableMouseInteraction ? 1 : 0; u.mouseRadius.value = mouseRadius; + if (enableMouseInteraction) { - u.mousePos.value.set(mousePos.x, mousePos.y); + u.mousePos.value.copy(mouseRef.current); } }); @@ -210,10 +231,10 @@ function DitheredWaves({ if (!enableMouseInteraction) return; const rect = gl.domElement.getBoundingClientRect(); const dpr = gl.getPixelRatio(); - setMousePos({ - x: (e.clientX - rect.left) * dpr, - y: (e.clientY - rect.top) * dpr, - }); + mouseRef.current.set( + (e.clientX - rect.left) * dpr, + (e.clientY - rect.top) * dpr + ); }; return ( @@ -275,4 +296,4 @@ export default function Dither({ /> ); -} \ No newline at end of file +} diff --git a/src/ts-default/Backgrounds/Dither/Dither.tsx b/src/ts-default/Backgrounds/Dither/Dither.tsx index 86235ecf..25a9bf30 100644 --- a/src/ts-default/Backgrounds/Dither/Dither.tsx +++ b/src/ts-default/Backgrounds/Dither/Dither.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-unknown-property */ -import { useRef, useState, useEffect } from "react"; +import { useRef, useEffect, forwardRef } from "react"; import { Canvas, useFrame, useThree, ThreeEvent } from "@react-three/fiber"; import { EffectComposer, wrapEffect } from "@react-three/postprocessing"; import { Effect } from "postprocessing"; @@ -63,7 +63,7 @@ float cnoise(vec2 P) { return 2.3 * mix(n_x.x, n_x.y, fade_xy.y); } -const int OCTAVES = 8; +const int OCTAVES = 4; float fbm(vec2 p) { float value = 0.0; float amp = 1.0; @@ -78,7 +78,7 @@ float fbm(vec2 p) { float pattern(vec2 p) { vec2 p2 = p - time * waveSpeed; - return fbm(p - fbm(p + fbm(p2))); + return fbm(p + fbm(p2)); } void main() { @@ -158,17 +158,18 @@ class RetroEffectImpl extends Effect { } } -import { forwardRef } from 'react'; - -const RetroEffect = forwardRef( - (props, ref) => { - const { colorNum, pixelSize } = props; - const WrappedRetroEffect = wrapEffect(RetroEffectImpl); - return ; - } -); +const RetroEffect = forwardRef< + RetroEffectImpl, + { colorNum: number; pixelSize: number } +>((props, ref) => { + const { colorNum, pixelSize } = props; + const WrappedRetroEffect = wrapEffect(RetroEffectImpl); + return ( + + ); +}); -RetroEffect.displayName = 'RetroEffect'; +RetroEffect.displayName = "RetroEffect"; interface WaveUniforms { [key: string]: THREE.Uniform; @@ -207,10 +208,7 @@ function DitheredWaves({ mouseRadius, }: DitheredWavesProps) { const mesh = useRef(null); - const [mousePos, setMousePos] = useState<{ x: number; y: number }>({ - x: 0, - y: 0, - }); + const mouseRef = useRef(new THREE.Vector2()); const { viewport, size, gl } = useThree(); const waveUniformsRef = useRef({ @@ -235,19 +233,30 @@ function DitheredWaves({ } }, [size, gl]); + const prevColor = useRef([...waveColor]); useFrame(({ clock }) => { + const u = waveUniformsRef.current; + if (!disableAnimation) { - waveUniformsRef.current.time.value = clock.getElapsedTime(); + u.time.value = clock.getElapsedTime(); + } + + if (u.waveSpeed.value !== waveSpeed) u.waveSpeed.value = waveSpeed; + if (u.waveFrequency.value !== waveFrequency) + u.waveFrequency.value = waveFrequency; + if (u.waveAmplitude.value !== waveAmplitude) + u.waveAmplitude.value = waveAmplitude; + + if (!prevColor.current.every((v, i) => v === waveColor[i])) { + u.waveColor.value.set(...waveColor); + prevColor.current = [...waveColor]; } - waveUniformsRef.current.waveSpeed.value = waveSpeed; - waveUniformsRef.current.waveFrequency.value = waveFrequency; - waveUniformsRef.current.waveAmplitude.value = waveAmplitude; - waveUniformsRef.current.waveColor.value.set(...waveColor); - waveUniformsRef.current.enableMouseInteraction.value = - enableMouseInteraction ? 1 : 0; - waveUniformsRef.current.mouseRadius.value = mouseRadius; + + u.enableMouseInteraction.value = enableMouseInteraction ? 1 : 0; + u.mouseRadius.value = mouseRadius; + if (enableMouseInteraction) { - waveUniformsRef.current.mousePos.value.set(mousePos.x, mousePos.y); + u.mousePos.value.copy(mouseRef.current); } }); @@ -255,9 +264,10 @@ function DitheredWaves({ if (!enableMouseInteraction) return; const rect = gl.domElement.getBoundingClientRect(); const dpr = gl.getPixelRatio(); - const x = (e.clientX - rect.left) * dpr; - const y = (e.clientY - rect.top) * dpr; - setMousePos({ x, y }); + mouseRef.current.set( + (e.clientX - rect.left) * dpr, + (e.clientY - rect.top) * dpr + ); }; return ( diff --git a/src/ts-tailwind/Backgrounds/Dither/Dither.tsx b/src/ts-tailwind/Backgrounds/Dither/Dither.tsx index eefc165a..e1e0662e 100644 --- a/src/ts-tailwind/Backgrounds/Dither/Dither.tsx +++ b/src/ts-tailwind/Backgrounds/Dither/Dither.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-unknown-property */ -import { useRef, useState, useEffect } from "react"; +import { useRef, useState, useEffect, forwardRef } from "react"; import { Canvas, useFrame, useThree, ThreeEvent } from "@react-three/fiber"; import { EffectComposer, wrapEffect } from "@react-three/postprocessing"; import { Effect } from "postprocessing"; @@ -61,7 +61,7 @@ float cnoise(vec2 P) { return 2.3 * mix(n_x.x, n_x.y, fade_xy.y); } -const int OCTAVES = 8; +const int OCTAVES = 4; float fbm(vec2 p) { float value = 0.0; float amp = 1.0; @@ -76,7 +76,7 @@ float fbm(vec2 p) { float pattern(vec2 p) { vec2 p2 = p - time * waveSpeed; - return fbm(p - fbm(p + fbm(p2))); + return fbm(p + fbm(p2)); } void main() { @@ -156,8 +156,6 @@ class RetroEffectImpl extends Effect { } } -import { forwardRef } from "react"; - const RetroEffect = forwardRef< RetroEffectImpl, { colorNum: number; pixelSize: number } @@ -208,10 +206,7 @@ function DitheredWaves({ mouseRadius, }: DitheredWavesProps) { const mesh = useRef(null); - const [mousePos, setMousePos] = useState<{ x: number; y: number }>({ - x: 0, - y: 0, - }); + const mouseRef = useRef(new THREE.Vector2()); const { viewport, size, gl } = useThree(); const waveUniformsRef = useRef({ @@ -236,19 +231,30 @@ function DitheredWaves({ } }, [size, gl]); + const prevColor = useRef([...waveColor]); useFrame(({ clock }) => { + const u = waveUniformsRef.current; + if (!disableAnimation) { - waveUniformsRef.current.time.value = clock.getElapsedTime(); + u.time.value = clock.getElapsedTime(); + } + + if (u.waveSpeed.value !== waveSpeed) u.waveSpeed.value = waveSpeed; + if (u.waveFrequency.value !== waveFrequency) + u.waveFrequency.value = waveFrequency; + if (u.waveAmplitude.value !== waveAmplitude) + u.waveAmplitude.value = waveAmplitude; + + if (!prevColor.current.every((v, i) => v === waveColor[i])) { + u.waveColor.value.set(...waveColor); + prevColor.current = [...waveColor]; } - waveUniformsRef.current.waveSpeed.value = waveSpeed; - waveUniformsRef.current.waveFrequency.value = waveFrequency; - waveUniformsRef.current.waveAmplitude.value = waveAmplitude; - waveUniformsRef.current.waveColor.value.set(...waveColor); - waveUniformsRef.current.enableMouseInteraction.value = - enableMouseInteraction ? 1 : 0; - waveUniformsRef.current.mouseRadius.value = mouseRadius; + + u.enableMouseInteraction.value = enableMouseInteraction ? 1 : 0; + u.mouseRadius.value = mouseRadius; + if (enableMouseInteraction) { - waveUniformsRef.current.mousePos.value.set(mousePos.x, mousePos.y); + u.mousePos.value.copy(mouseRef.current); } }); @@ -256,9 +262,10 @@ function DitheredWaves({ if (!enableMouseInteraction) return; const rect = gl.domElement.getBoundingClientRect(); const dpr = gl.getPixelRatio(); - const x = (e.clientX - rect.left) * dpr; - const y = (e.clientY - rect.top) * dpr; - setMousePos({ x, y }); + mouseRef.current.set( + (e.clientX - rect.left) * dpr, + (e.clientY - rect.top) * dpr + ); }; return (