每條游來游去的小魚,都是正在瀏覽這一頁的訪客,有一條是你自己 ( ´ ▽ ` )ノ 覺得干擾閱讀的話,可以把小魚關掉。
Starry Sea
bg前陣子看《超時空輝耀姬!》aka 早見沙織演唱會,其中八千代演唱 Starry Sea 時的背景效果真的美翻天,決定來嘗試重現看看 (*´∀`)~♥
甚麼?你還沒看過?還不趕快去看!⎝(・ω´・⎝)
好多好多小魚結隊蜿蜒上升 ◝( •ω• )◟
| 名稱 | 描述 |
|---|---|
| Canvas Shader | 使用 GLSL 開發,直接在 GPU 上執行,比 Canvas 2D API 更快,但也更難 |
| Noise | 比 Math.random 更自然隨機效果,常用於地形、雲朵、材質等 |
| WebGL2 Instanced Rendering | 透過 WebGL2 的 Instanced Drawing 一次繪製大量相同幾何體,大幅減少 draw call |
| Simplex Noise | 改良版 Perlin Noise,計算更快且無方向性偏差,常用於程序化生成 |
| SDF (Signed Distance Field) | 有號距離場,用數學函式描述形狀輪廓,常用於 Shader 中繪製平滑圖形 |
<template> <div> <div class="grid grid-cols-2 gap-x-6 gap-y-2"> <base-checkbox v-model="enable" :label="t('enable')" class="example-ctrl col-span-2" />
<base-input v-model="options.fishSize" :label="`${t('fishSize')}: ${options.fishSize}`" type="range" :min="5" :max="60" :step="1" />
<base-input v-model="options.spread" :label="`${t('spread')}: ${options.spread}`" type="range" :min="0.02" :max="0.5" :step="0.01" />
<base-input v-model="options.riseSpeed" :label="`${t('riseSpeed')}: ${options.riseSpeed}`" type="range" :min="0" :max="0.002" :step="0.0001" />
<base-input v-model="options.meanderStrength" :label="`${t('meanderStrength')}: ${options.meanderStrength}`" type="range" :min="0" :max="0.01" :step="0.0005" />
<base-input v-model="options.followSpeed" :label="`${t('followSpeed')}: ${options.followSpeed}`" type="range" :min="0.005" :max="0.15" :step="0.005" />
<base-input v-model="options.turnRate" :label="`${t('turnRate')}: ${options.turnRate}`" type="range" :min="0.01" :max="0.2" :step="0.01" />
<base-input v-model="options.spreadCurve" :label="`${t('spreadCurve')}: ${options.spreadCurve}`" type="range" :min="0.5" :max="5" :step="0.5" /> </div>
<bg-starry-sea v-if="enable" class="pointer-events-none inset-0 z-[99999] !fixed" :fish-size="Number(options.fishSize)" :spread="Number(options.spread)" :rise-speed="Number(options.riseSpeed)" :meander-strength="Number(options.meanderStrength)" :follow-speed="Number(options.followSpeed)" :turn-rate="Number(options.turnRate)" :spread-curve="Number(options.spreadCurve)" /> </div></template>
<script setup lang="ts">import { useMediaQuery } from '@vueuse/core'import { onMounted, onUnmounted, ref, watch } from 'vue'import { useI18n } from 'vue-i18n'import { useSiteDark } from '../../../composables/use-site-dark'import BaseCheckbox from '../../base-checkbox.vue'import BaseInput from '../../base-input.vue'import BgStarrySea from '../bg-starry-sea.vue'
const { t } = useI18n()
const enable = ref(false)
const isMobile = useMediaQuery('(max-width: 768px)')
const options = ref({ fishSize: 18, spread: 0.18, riseSpeed: 0.0005, meanderStrength: 0.003, followSpeed: 0.03, turnRate: 0.04, spreadCurve: 2,})
// 掛載後才依螢幕寬度調整,否則伺服器端渲染的數值與手機上不同,水合會對不上onMounted(() => { if (isMobile.value) options.value.fishSize = 10})
const isDark = useSiteDark()
const oriValue = isDark.value
watch(enable, (value) => { isDark.value = value})
onUnmounted(() => { isDark.value = oriValue})</script>- 長龍路徑系統:以 Simplex Noise 驅動多條蜿蜒路徑,魚群沿路徑歷史依序排列,形成長龍隊伍
- WebGL2 Instanced Rendering:所有小魚共用同一組頂點,透過 instance attribute 傳入位置、角度、顏色與深度,單次 draw call 完成繪製,效能極佳,實現同時繪製一萬隻小魚也不會卡!(ゝ∀・)b
- SDF 魚形:在 fragment shader 中以橢圓與圓角三角形的 SDF 組合出魚的輪廓,搭配同色光暈效果
- 透視深度:路徑帶有 Z 軸深度變化,遠處的魚尺寸縮小、間距壓縮、速度減慢,並以背景色霧化產生空氣感
- 深度排序:每幀依深度排序 instance data,確保近處的魚繪製在遠處之上
interface Props { /** 魚的數量。@default 10000 */ fishCount?: number;
/** 魚的大小(px)。@default 18 */ fishSize?: number;
/** 長龍路徑數量。@default 6 */ trailCount?: number;
/** 路徑歷史步數,越長龍身越長。@default 2000 */ trailLength?: number;
/** 魚群散佈寬度(正規化空間)。@default 0.18 */ spread?: number;
/** 上升速度。@default 0.0005 */ riseSpeed?: number;
/** 路徑蜿蜒幅度。@default 0.003 */ meanderStrength?: number;
/** 魚跟隨路徑的平滑速度,0~1,越大越緊跟。@default 0.03 */ followSpeed?: number;
/** 路徑轉彎頻率,越小轉彎越平緩。@default 0.04 */ turnRate?: number;
/** 散佈集中度,越大魚群越集中在路徑中心,偶有離群魚。@default 2 */ spreadCurve?: number;}interface Slots { default?: () => unknown;}