diff --git a/src/components/three/NetTest.tsx b/src/components/three/NetTest.tsx new file mode 100644 index 0000000..3b4726b --- /dev/null +++ b/src/components/three/NetTest.tsx @@ -0,0 +1,25 @@ +import { useRef } from "react"; +import { useFrame } from "@react-three/fiber"; +import * as THREE from "three"; +import { createNetShader } from "@/shaders/NetShader"; + +export function NetTest(): React.JSX.Element { + const materialRef = useRef(null); + + useFrame((_, delta) => { + if (materialRef.current) { + materialRef.current.uniforms.uTime.value += delta; + } + }); + + return ( + + + + + ); +} diff --git a/src/shaders/NetShader.ts b/src/shaders/NetShader.ts new file mode 100644 index 0000000..9605902 --- /dev/null +++ b/src/shaders/NetShader.ts @@ -0,0 +1,62 @@ +import { ShaderMaterial } from "three"; + +export const createNetShader = (): ShaderMaterial => { + return new ShaderMaterial({ + transparent: true, + depthWrite: false, + uniforms: { + uTime: { value: 0 }, + uGridScale: { value: 15.0 }, + uPincushionStrength: { value: 0.4 }, + uBloomIntensity: { value: 0.8 }, + uGridThickness: { value: 0.05 }, + }, + vertexShader: ` + varying vec2 vUv; + + void main() { + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + } + `, + fragmentShader: ` + uniform float uTime; + uniform float uGridScale; + uniform float uPincushionStrength; + uniform float uBloomIntensity; + uniform float uGridThickness; + + varying vec2 vUv; + + vec2 applyPincushion(vec2 uv, float strength) { + vec2 center = uv - 0.5; + float dist = length(center); + float distortion = 1.0 + dist * dist * strength; + return center * distortion + 0.5; + } + + float grid(vec2 uv, float scale, float thickness) { + vec2 gridUV = fract(uv * scale); + + float edgeX = step(gridUV.x, thickness) + step(1.0 - thickness, gridUV.x); + float edgeY = step(gridUV.y, thickness) + step(1.0 - thickness, gridUV.y); + + float line = min(edgeX + edgeY, 1.0); + + return line; + } + + void main() { + vec2 uv = applyPincushion(vUv, uPincushionStrength); + + float gridPattern = grid(uv, uGridScale, uGridThickness); + + vec3 gridColor = vec3(1.0, 0.4, 0.7); + float bloom = gridPattern * uBloomIntensity; + vec3 col = gridColor * (0.3 + bloom); + + gl_FragColor = vec4(col, gridPattern * 0.95); + } + `, + }); +}; diff --git a/src/world/World.tsx b/src/world/World.tsx index bad4fc2..9bda20f 100644 --- a/src/world/World.tsx +++ b/src/world/World.tsx @@ -28,6 +28,7 @@ import { GameMap } from "@/world/GameMap"; import { GameStageContent } from "@/world/GameStageContent"; import { Player } from "@/world/player/Player"; import { TestMap } from "@/world/debug/TestMap"; +import { NetTest } from "@/components/three/NetTest"; import type { SceneLoadingChangeHandler } from "@/types/world/sceneLoading"; interface WorldProps { @@ -98,7 +99,10 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element { ) : null} ) : ( - + <> + + + )} {sceneMode !== "game" && spawnPlayer ? (