import React, { useRef, useMemo } from 'react'; import { Canvas, useFrame } from '@react-three/fiber'; import { OrbitControls, Sky } from '@react-three/drei'; import { useControls } from 'leva'; import * as THREE from 'three'; function ShaderMesh() { const meshRef = useRef(); const { thresholdX, thresholdY, displacement, baseColor, highlightColor, wireframe, transparent, autoRotate } = useControls({ thresholdX: { value: 0.5, min: 0, max: 1, step: 0.01 }, thresholdY: { value: 0.5, min: 0, max: 1, step: 0.01 }, displacement: { value: 0.1, min: 0, max: 1, step: 0.01 }, baseColor: '#d8d5d5', highlightColor: '#00ff00', wireframe: true, transparent: true, autoRotate: false }); const material = useMemo(() => { return new THREE.ShaderMaterial({ vertexShader: ` uniform float uThresholdX; uniform float uThresholdY; uniform float uDisplacement; varying vec2 vUv; void main() { vec3 newPosition = position; if (uv.x > uThresholdX && uv.y > uThresholdY) { newPosition.z += uDisplacement; } gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); vUv = uv; } `, fragmentShader: ` uniform float uThresholdX; uniform float uThresholdY; uniform vec3 uBaseColor; uniform vec3 uHighlightColor; varying vec2 vUv; void main() { vec3 color = uBaseColor; if (vUv.x > uThresholdX && vUv.y > uThresholdY) { color = uHighlightColor; } gl_FragColor = vec4(color, 1.0); } `, uniforms: { uThresholdX: { value: thresholdX }, uThresholdY: { value: thresholdY }, uDisplacement: { value: displacement }, uBaseColor: { value: new THREE.Color(baseColor) }, uHighlightColor: { value: new THREE.Color(highlightColor) } }, side: THREE.DoubleSide, wireframe, transparent }); }, [thresholdX, thresholdY, displacement, baseColor, highlightColor, wireframe, transparent]); useFrame((state) => { if (meshRef.current && autoRotate) { meshRef.current.rotation.x = state.clock.elapsedTime * 0.3; meshRef.current.rotation.y = state.clock.elapsedTime * 0.2; } // Update uniforms if (material.uniforms) { material.uniforms.uThresholdX.value = thresholdX; material.uniforms.uThresholdY.value = thresholdY; material.uniforms.uDisplacement.value = displacement; material.uniforms.uBaseColor.value.set(baseColor); material.uniforms.uHighlightColor.value.set(highlightColor); } }); return ( <mesh ref={meshRef} material={material}> <planeGeometry args={[3, 3, 32, 32]} /> </mesh> ); } function Scene() { return ( <Canvas camera={{ position: [0, 0, 4], fov: 50 }} style={{ height: '90vh' }}> <ambientLight intensity={0.5} /> <pointLight position={[10, 10, 10]} /> <Sky sunPosition={[0, 1, 0]} /> <OrbitControls enableDamping dampingFactor={0.05} /> <ShaderMesh /> </Canvas> ); } export default function App() { return ( <div className="w-full h-screen bg-gray-900 relative"> <Scene /> <div className="absolute top-4 left-4 text-white"> <h1 className="text-xl font-bold mb-2">Interactive Shader Demo</h1> </div> </div> ); }
Comments (0)
Loading comments...