T07▸3D007▸three
Noise Background
噪聲背景
難度 ★★★★★標籤 shader · noise · glsl3 min read
效果簡述
shader 內手寫 hash + value noise,產生有機流動感的背景。比一般動態漸層 有層次。是進入 shader 世界的第二站。
Claude Code Prompt
參考:3D007 noise background
技術:fragment shader 內寫 hash-based noise
具體行為:
- float hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }
- float noise(vec2 p) { 雙線性內插 4 個 hash 點 }
- 主程式 noise(uv*4 + uTime*0.15) 混兩色
限制:
- noise 函式效能 ok,但 fBM (多層疊加) 開始重,2~3 層上限
- 中文字 / 內文壓在上面要確保對比度
- 沒必要時不用 Perlin,hash-noise 已夠用完整程式碼
'use client'
import { Canvas, useFrame } from '@react-three/fiber'
import { useMemo, useRef } from 'react'
import * as THREE from 'three'
const vert = `varying vec2 vUv; void main(){ vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }`
const frag = `uniform float uTime; varying vec2 vUv;
float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1,311.7))) * 43758.5453); }
float noise(vec2 p){
vec2 i = floor(p); vec2 f = fract(p);
f = f*f*(3.0-2.0*f);
return mix(
mix(hash(i), hash(i+vec2(1,0)), f.x),
mix(hash(i+vec2(0,1)), hash(i+vec2(1,1)), f.x), f.y
);
}
void main(){
float n = noise(vUv * 4.0 + uTime * 0.15);
vec3 col = mix(vec3(0.05,0.05,0.08), vec3(0.76,0.25,0.05), n);
gl_FragColor = vec4(col, 1.0);
}`
function NoisePlane() {
const ref = useRef<THREE.ShaderMaterial>(null)
const uniforms = useMemo(() => ({ uTime: { value: 0 } }), [])
useFrame((s) => { if (ref.current) ref.current.uniforms.uTime.value = s.clock.getElapsedTime() })
return (
<mesh>
<planeGeometry args={[6,4]} />
<shaderMaterial ref={ref} vertexShader={vert} fragmentShader={frag} uniforms={uniforms} />
</mesh>
)
}
export function NoiseBackground() {
return (
<Canvas camera={{ position: [0,0,3], fov: 55 }} dpr={[1,2]}>
<NoisePlane />
</Canvas>
)
}何時用
- ✅ 高級感 Hero 背景
- ✅ 跟漸層搭配做「有機光感」
- ✅ Art / 設計工作室站
何時別用
- ❌ 內文背景(讀者眼睛累)
- ❌ 對比度沒處理(前景文字看不清)
- ❌ 一頁多塊 noise
我踩過的坑
-
hash 系數對結果影響大:127.1 / 311.7 / 43758.5453 是社群驗證 過的「亂得剛好」的數字。別亂改。
-
多層 fBM 行動裝置卡:1~2 層 noise 就好。
-
混色太接近看不出來:兩端色差要夠大才有層次。
相關效果
- T06 Shader Gradient — shader 入門