314 lines
8.8 KiB
TypeScript
314 lines
8.8 KiB
TypeScript
"use client";
|
|
|
|
import { Canvas, useFrame, useThree } from "@react-three/fiber";
|
|
import { useMemo, useRef } from "react";
|
|
import * as THREE from "three";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface ShaderPlaneProps {
|
|
fragmentShader: string;
|
|
vertexShader: string;
|
|
uniforms: Record<string, THREE.IUniform>;
|
|
renderTarget?: THREE.WebGLRenderTarget;
|
|
onRender?: (texture: THREE.Texture) => void;
|
|
}
|
|
|
|
const ShaderPlane = ({
|
|
fragmentShader,
|
|
vertexShader,
|
|
uniforms,
|
|
renderTarget,
|
|
onRender,
|
|
}: ShaderPlaneProps) => {
|
|
const meshRef = useRef<THREE.Mesh>(null);
|
|
const { size, gl } = useThree();
|
|
|
|
useFrame((state) => {
|
|
if (meshRef.current) {
|
|
const material = meshRef.current.material as THREE.ShaderMaterial;
|
|
material.uniforms.u_time.value = state.clock.elapsedTime;
|
|
material.uniforms.u_resolution.value.set(size.width, size.height, 1.0);
|
|
|
|
if (renderTarget) {
|
|
gl.setRenderTarget(renderTarget);
|
|
gl.render(meshRef.current, state.camera);
|
|
gl.setRenderTarget(null);
|
|
onRender?.(renderTarget.texture);
|
|
}
|
|
}
|
|
});
|
|
|
|
return (
|
|
<mesh ref={meshRef}>
|
|
<planeGeometry args={[2, 2]} />
|
|
<shaderMaterial
|
|
vertexShader={vertexShader}
|
|
fragmentShader={fragmentShader}
|
|
uniforms={uniforms}
|
|
depthTest={false}
|
|
depthWrite={false}
|
|
/>
|
|
</mesh>
|
|
);
|
|
};
|
|
|
|
interface ShaderBackgroundProps {
|
|
className?: string;
|
|
backgroundColor?: THREE.ColorRepresentation;
|
|
color?: THREE.ColorRepresentation;
|
|
}
|
|
|
|
const Shader14 = ({
|
|
className = "absolute inset-0 w-full h-screen",
|
|
backgroundColor = "#000000",
|
|
color = "#f0f0f0",
|
|
}: ShaderBackgroundProps) => {
|
|
const vertexShader = `
|
|
varying vec2 vUv;
|
|
void main() {
|
|
vUv = uv;
|
|
gl_Position = vec4(position, 1.0);
|
|
}
|
|
`;
|
|
|
|
const fragmentShaderA = `
|
|
precision mediump float;
|
|
varying vec2 vUv;
|
|
uniform float u_time;
|
|
uniform vec3 u_resolution;
|
|
uniform vec3 u_backgroundColor;
|
|
uniform vec3 u_color;
|
|
|
|
#define TWOPI 6.28318530718
|
|
|
|
vec3 mod289(vec3 x){return x-floor(x*(1.0/289.0))*289.0;}
|
|
vec4 mod289(vec4 x){return x-floor(x*(1.0/289.0))*289.0;}
|
|
vec4 permute(vec4 x){return mod289(((x*34.0)+10.0)*x);}
|
|
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159-0.85373472095314*r;}
|
|
|
|
float snoise(vec3 v){
|
|
const vec2 C=vec2(1.0/6.0,1.0/3.0);
|
|
const vec4 D=vec4(0.0,0.5,1.0,2.0);
|
|
vec3 i=floor(v+dot(v,C.yyy));
|
|
vec3 x0=v-i+dot(i,C.xxx);
|
|
vec3 g=step(x0.yzx,x0.xyz);
|
|
vec3 l=vec3(1.0)-g;
|
|
vec3 i1=min(g.xyz,l.zxy);
|
|
vec3 i2=max(g.xyz,l.zxy);
|
|
vec3 x1=x0-i1+C.xxx;
|
|
vec3 x2=x0-i2+C.yyy;
|
|
vec3 x3=x0-D.yyy;
|
|
i=mod289(i);
|
|
vec4 p=permute(permute(permute(i.z+vec4(0.0,i1.z,i2.z,1.0))+i.y+vec4(0.0,i1.y,i2.y,1.0))+i.x+vec4(0.0,i1.x,i2.x,1.0));
|
|
float n_=0.142857142857;
|
|
vec3 ns=n_*D.wyz-D.xzx;
|
|
vec4 j=p-49.0*floor(p*ns.z*ns.z);
|
|
vec4 x_=floor(j*ns.z);
|
|
vec4 y_=floor(j-7.0*x_);
|
|
vec4 x=x_*ns.x+ns.yyyy;
|
|
vec4 y=y_*ns.x+ns.yyyy;
|
|
vec4 h=vec4(1.0)-abs(x)-abs(y);
|
|
vec4 b0=vec4(x.xy,y.xy);
|
|
vec4 b1=vec4(x.zw,y.zw);
|
|
vec4 s0=floor(b0)*2.0+1.0;
|
|
vec4 s1=floor(b1)*2.0+1.0;
|
|
vec4 sh=-step(h,vec4(0.0));
|
|
vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;
|
|
vec4 a1=b1.xzyw+s1.xzyw*sh.zzww;
|
|
vec3 p0=vec3(a0.xy,h.x);
|
|
vec3 p1=vec3(a0.zw,h.y);
|
|
vec3 p2=vec3(a1.xy,h.z);
|
|
vec3 p3=vec3(a1.zw,h.w);
|
|
vec4 norm=taylorInvSqrt(vec4(dot(p0,p0),dot(p1,p1),dot(p2,p2),dot(p3,p3)));
|
|
p0*=norm.x;p1*=norm.y;p2*=norm.z;p3*=norm.w;
|
|
vec4 m=max(0.5-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.0);
|
|
m=m*m;
|
|
return 55.0*dot(m*m,vec4(dot(p0,x0),dot(p1,x1),dot(p2,x2),dot(p3,x3)));
|
|
}
|
|
|
|
void mainImage(out vec4 fragColor,in vec2 fragCoord){
|
|
vec3 c;
|
|
float l,z=u_time;
|
|
vec2 r=u_resolution.xy;
|
|
vec2 uv0=fragCoord.xy/r;
|
|
float noiseStrength=0.16;
|
|
float noiseScale=0.001;
|
|
float speed=0.1;
|
|
float noiseTime=u_time*speed;
|
|
float noise=snoise(vec3(
|
|
(fragCoord.x-r.x/2.)*noiseScale,
|
|
(fragCoord.y-r.y/2.)*noiseScale,
|
|
noiseTime));
|
|
uv0.x=fract(uv0).x+noiseStrength*sin(noise*TWOPI);
|
|
uv0.y=fract(uv0).y+noiseStrength*cos(noise*TWOPI);
|
|
for(int i=0;i<3;i++){
|
|
vec2 uv,p=uv0;
|
|
uv=p;
|
|
p-=.5;
|
|
p.x*=r.x/r.y;
|
|
z+=.03;
|
|
l=length(p);
|
|
uv+=p/l*(sin(z)+1.)*abs(sin(l*9.-z-z));
|
|
c[i]=.05/length(mod(uv,1.)-.5);
|
|
}
|
|
fragColor=vec4(c/l,1.0);
|
|
}
|
|
|
|
void main(){
|
|
vec4 fragColor;
|
|
vec2 fragCoord=vUv*u_resolution.xy;
|
|
mainImage(fragColor,fragCoord);
|
|
|
|
vec3 pattern = fragColor.rgb * u_color;
|
|
fragColor.rgb = mix(u_backgroundColor, pattern, 0.6);
|
|
|
|
gl_FragColor=fragColor;
|
|
}
|
|
`;
|
|
|
|
const fragmentShaderImage = `
|
|
precision mediump float;
|
|
varying vec2 vUv;
|
|
uniform float u_time;
|
|
uniform vec3 u_resolution;
|
|
uniform sampler2D u_channel0;
|
|
|
|
float character(int n, vec2 p){
|
|
p=floor(p*vec2(-4.0,4.0)+2.5);
|
|
if(clamp(p.x,0.0,4.0)==p.x){
|
|
if(clamp(p.y,0.0,4.0)==p.y){
|
|
int a=int(round(p.x)+5.0*round(p.y));
|
|
if(((n>>a)&1)==1)return 1.0;
|
|
}
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
void mainImage(out vec4 fragColor,in vec2 fragCoord){
|
|
vec2 pix=fragCoord.xy;
|
|
vec3 col=texture2D(u_channel0,floor(pix/16.0)*16.0/u_resolution.xy).rgb;
|
|
float gray=0.3*col.r+0.59*col.g+0.11*col.b;
|
|
int n=4096;
|
|
if(gray>0.1)n=4096;
|
|
if(gray>0.1064)n=131200;
|
|
if(gray>0.1096)n=4329476;
|
|
if(gray>0.1130)n=459200;
|
|
if(gray>0.1263)n=4591748;
|
|
if(gray>0.1395)n=12652620;
|
|
if(gray>0.1628)n=14749828;
|
|
if(gray>0.1860)n=18393220;
|
|
if(gray>0.2093)n=15239300;
|
|
if(gray>0.2326)n=17318431;
|
|
if(gray>0.2558)n=32641156;
|
|
if(gray>0.2791)n=18393412;
|
|
if(gray>0.3023)n=18157905;
|
|
if(gray>0.3256)n=17463428;
|
|
if(gray>0.3488)n=14954572;
|
|
if(gray>0.3721)n=13177118;
|
|
if(gray>0.3953)n=6566222;
|
|
if(gray>0.4186)n=16269839;
|
|
if(gray>0.4419)n=18444881;
|
|
if(gray>0.4651)n=18400814;
|
|
if(gray>0.4884)n=33061392;
|
|
if(gray>0.5116)n=15255086;
|
|
if(gray>0.5349)n=32045584;
|
|
if(gray>0.5581)n=18405034;
|
|
if(gray>0.5814)n=15022158;
|
|
if(gray>0.6047)n=15018318;
|
|
if(gray>0.6279)n=16272942;
|
|
if(gray>0.6512)n=18415153;
|
|
if(gray>0.6744)n=32641183;
|
|
if(gray>0.6977)n=32540207;
|
|
if(gray>0.7209)n=18732593;
|
|
if(gray>0.7442)n=18667121;
|
|
if(gray>0.7674)n=16267326;
|
|
if(gray>0.7907)n=32575775;
|
|
if(gray>0.8140)n=15022414;
|
|
if(gray>0.8372)n=15255537;
|
|
if(gray>0.8605)n=32032318;
|
|
if(gray>0.8837)n=32045617;
|
|
if(gray>0.9070)n=33081316;
|
|
if(gray>0.9302)n=32045630;
|
|
if(gray>0.9535)n=33061407;
|
|
if(gray>0.9767)n=11512810;
|
|
|
|
vec2 p=mod(pix/8.0,2.0)-vec2(1.0);
|
|
vec3 finalCol=col*character(n,p);
|
|
fragColor=vec4(finalCol,1.0);
|
|
}
|
|
|
|
void main(){
|
|
vec4 fragColor;
|
|
vec2 fragCoord=vUv*u_resolution.xy;
|
|
mainImage(fragColor,fragCoord);
|
|
gl_FragColor=fragColor;
|
|
}
|
|
`;
|
|
|
|
const backgroundColorValue = useMemo(
|
|
() => new THREE.Color(backgroundColor),
|
|
[backgroundColor],
|
|
);
|
|
const colorValue = useMemo(() => new THREE.Color(color), [color]);
|
|
|
|
const renderTarget = useMemo(() => {
|
|
if (typeof window === "undefined") return null;
|
|
return new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, {
|
|
minFilter: THREE.LinearFilter,
|
|
magFilter: THREE.LinearFilter,
|
|
format: THREE.RGBAFormat,
|
|
});
|
|
}, []);
|
|
|
|
const uniformsA = useMemo<Record<string, THREE.IUniform>>(
|
|
() => ({
|
|
u_time: { value: 0 },
|
|
u_resolution: { value: new THREE.Vector3(1, 1, 1) },
|
|
u_backgroundColor: { value: backgroundColorValue },
|
|
u_color: { value: colorValue },
|
|
}),
|
|
[backgroundColorValue, colorValue],
|
|
);
|
|
|
|
const uniformsImage = useMemo<Record<string, THREE.IUniform>>(() => {
|
|
if (!renderTarget) {
|
|
return {
|
|
u_time: { value: 0 },
|
|
u_resolution: { value: new THREE.Vector3(1, 1, 1) },
|
|
u_channel0: { value: null },
|
|
};
|
|
}
|
|
|
|
return {
|
|
u_time: { value: 0 },
|
|
u_resolution: { value: new THREE.Vector3(1, 1, 1) },
|
|
u_channel0: { value: renderTarget.texture },
|
|
};
|
|
}, [renderTarget]);
|
|
|
|
return (
|
|
<section className={cn(className, "absolute inset-0 h-screen w-full")}>
|
|
<Canvas>
|
|
{renderTarget && (
|
|
<>
|
|
<ShaderPlane
|
|
vertexShader={vertexShader}
|
|
fragmentShader={fragmentShaderA}
|
|
uniforms={uniformsA}
|
|
renderTarget={renderTarget}
|
|
/>
|
|
<ShaderPlane
|
|
vertexShader={vertexShader}
|
|
fragmentShader={fragmentShaderImage}
|
|
uniforms={uniformsImage}
|
|
/>
|
|
</>
|
|
)}
|
|
</Canvas>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Shader14 };
|