Three.js 3D 渲染

WebGL 與 Three.js 的 3D 場景開發、材質光影與互動效果。以下為使用 React Three Fiber 實作的互動展示。

幾何體展示台

使用 Float 實現漂浮動態,搭配多組 PointLight 產生彩色反射光影,OrbitControls 支援拖曳與自動旋轉。

載入場景中…

粒子波浪場

BufferGeometry 管理 3,600 個頂點,每幀透過正弦函數計算高度,並以滑鼠位置作為相位偏移輸入,效能優於每幀重建幾何體。

載入場景中…

實作筆記

BufferAttribute 直接操作頂點(粒子波浪)

避免每幀重建 Geometry 造成 GC 壓力。直接取出 position attribute,原地修改 Y 值後標記 needsUpdate = true,讓 Three.js 僅上傳變動的 buffer 至 GPU。

useFrame(({ clock }) => {
  const t = clock.getElapsedTime()
  const posAttr = meshRef.current.geometry.attributes.position

  for (let i = 0; i < GRID * GRID; i++) {
    const x = posAttr.getX(i)
    const z = posAttr.getZ(i)
    // 滑鼠位置(mouse.x/y)作為相位偏移,讓波浪跟隨游標
    const wave = Math.sin((x + mouse.x * 2) * 1.5 + t)
              * Math.cos((z + mouse.y * 2) * 1.5 + t) * 0.6
    posAttr.setY(i, wave)
  }
  posAttr.needsUpdate = true  // 僅通知 GPU 更新,不重新分配記憶體
})

Next.js SSR 相容:dynamic import + ssr: false

Three.js 直接存取 window / WebGL context,在 Node.js 環境會崩潰。透過 dynamic import 延遲至瀏覽器載入,並將 ssr: false 的呼叫包在 'use client' Client Component 中,避免 Next.js App Router 的限制。

// ThreeClientComponents.tsx  ('use client' 必要)
import dynamic from 'next/dynamic'

// ssr: false 只能在 Client Component 中使用
export const GeometryShowcaseDynamic = dynamic(
  () => import('./GeometryShowcase'),
  { ssr: false, loading: () => <div className="h-72 animate-pulse bg-neutral-900 rounded-2xl" /> }
)

// Server Component 直接 import 此檔案即可,無需感知 Three.js