2022-09-14

Skiaでぼんやり光るライトを表現する

react-native-skiaでぼんやり光るライトを表現してみたいと思います。

円がぼんやり光る状態を表現

ぼんやり光る状態をBlurをつかってぼかして表現してみます。本体の円を配置しその裏にぼかしたサイズ違いの円を何枚か重ねます。外側が自然に薄くなっていくようにRadialGradientを使って透明度を徐々に薄くしていっています。

const blurredCircles = [
  { radius: 40, blur: 40 },
  { radius: 50, blur: 60 },
  { radius: 60, blur: 80 },
  { radius: 70, blur: 100 },
]

<Canvas ...>
  {blurredCircles.map((c, i) => (
    <Circle key={i} cx={center.x} cy={center.y} r={c.radius}>
      <RadialGradient
        c={center}
        r={c.radius}
        colors={[color, colorAlpha]}
      />
      <Blur blur={c.blur} mode="decal" />
    </Circle>
  ))}
  <Circle cx={center.x} cy={center.y} r={30} color={color}>
    <Blur blur={0.7} mode="decal" />
  </Circle>
</Canvas>

裏の円のサイズとぼかしの値、サイズはあくまで見た感覚を元に調整しています。

Loading Skia..

光のオンオフのアニメーションを設定してみる

これにアニメーションを設定してみます。タップするとON/OFFが切り替わります。

Loading Skia..

タップした際にアニメーションValue(progress)を変化させ、その値に応じて裏側の円の半径を変更していきます。合わせて本体の円の不透明度も変化させていきます。

const progress = useSharedValue(0)

const gesture = Gesture.Tap()
  .onStart(() => {
    if (progress.value === 0) {
      progress.value = withTiming(1, { duration: 350 })
    } else {
      progress.value = withTiming(0, { duration: 350 })
    }
  })

<GestureDetector gesture={gesture}>
  <Canvas
    ...
  >
    <Group color={color}>
      {circles.map((c, i) => (
        <Circle
          key={i}
          cx={center.x}
          cy={center.y}
          r={useDerivedValue(() => {
            return progress.value * c.radius
          }, [])}
        >
          <RadialGradient
            c={center}
            r={c.radius}
            colors={[color, colorAlpha]}
          />
          <Blur blur={c.blur} mode="decal" />
        </Circle>
      ))}
      <Circle
        cx={center.x}
        cy={center.y}
        r={30}
        color={color}
        opacity={useDerivedValue(() => {
          return 0.4 + (progress.value * 0.6)
        }, [])}
      >
        <Blur blur={0.7} mode="decal" />
      </Circle>
    </Group>
  </Canvas>
</GestureDetector>

終わりに

光の範囲や円の周囲の見た目など、更に調整すればもっと自然な形にできそうです。またSkiaを使った場合他にもっとよい表現方法があるかもしれません。

完成形のソースコードは こちらで確認できます。

最終更新: 2025-03-16 02:06
筆者: @gaishimo 主にReact Nativeでのアプリ開発を行っています。
© 2021 Omoidasu, Inc. All rights reserved.