🎸

CSSでステージ照明を作る技術

2024/08/15に公開

ここに完成品があります

https://www.youtube.com/watch?v=cIifQZDbyI4

conic-gradient を応用することで、スポットライトの様な照明演出を実装することができます。

const backgroundColor = '#130a3e';
const spotLightColor = `#ff00fe`;
const light = `
    ${backgroundColor}00 0turn, //始点。背景色を透明度を0で設定
    ${backgroundColor}66 0.4turn, //背景色の透明度を下げることでスポットライトとの境界をボカす
    ${spotLightColor}66 0.5turn, //光軸(円周の中央)
    ${backgroundColor}66 0.6turn, //終点に向かって背景とスポットライトとの境界をボカす
    ${backgroundColor}00 1turn`; //終点。背景色を透明度を0で設定

const lightProgress = 0; //この値がincrementされることでアニメーションする
const cos = Math.cos(lightProgress);
const sin = Math.sin(lightProgress);
const tan = Math.tan(lightProgress);
<div
    style={{
    background: `
        conic-gradient(from ${-10 * tan}deg at 35% -20%, ${light}), //1.ステージ中央。フラッシュ効果を兼ねる
        conic-gradient(from ${10 * tan}deg at 65% -20%, ${light}),  //2.同上
        conic-gradient(from ${40 * sin}deg at 10% -10%, ${light}),  //3.ステージ左上
        conic-gradient(from ${-40 * sin}deg at 90% -10%, ${light}), //4.ステージ右上
        conic-gradient(from ${180 * cos}deg at 45% 110%, ${light}), //5.ステージ左下
        conic-gradient(from ${-180 * cos}deg at 55% 110%, ${light}), //6.ステージ右下
        ${backgroundColor} //ベースを背景色とする
    `,
    }}
>
</div>

詳細

分かりやすいように、 1. の conic-gradient だけを有効にしてどの様に描画をコントロールできるか確認してみましょう

degによる方向の制御

照明を指す方向の制御には conic-gradient の角度指定 from [n]deg を用います

真下方向を指す照明

    <div
      style={{
        background: `conic-gradient(from 0deg at 50% 50%, ${light})`,
      }}
    >
    </div>

真上方向を指す照明

    <div
      style={{
        background: `conic-gradient(from 180deg at 50% 50%, ${light})`,
      }}
    >
    </div>

色経由点による照射範囲の制御

照射範囲(=光の広がり)の制御には conic-gradient に指定する色経由点の範囲指定を利用します。

狭め

  const narrowLight = `
    ${backgroundColor}00 0turn,
    ${backgroundColor}66 0.45turn,
    ${spotLightColor}66 0.5turn,
    ${backgroundColor}66 0.55turn,
    ${backgroundColor}00 1turn`;

標準

  const defaultLight = `
    ${backgroundColor}00 0turn,
    ${backgroundColor}66 0.4turn,
    ${spotLightColor}66 0.5turn,
    ${backgroundColor}66 0.6turn,
    ${backgroundColor}00 1turn`;

広め

  const wideLight = `
    ${backgroundColor}00 0turn,
    ${backgroundColor}66 0.2turn,
    ${spotLightColor}66 0.5turn,
    ${backgroundColor}66 0.8turn,
    ${backgroundColor}00 1turn`;

透明度の操作による照度の制御

光軸に相当する色経由点 ${spotLightColor}nn の透明度を上げ下げすることで照度を制御します。

暗め

  const darkentLight = `
    ${backgroundColor}00 0turn,
    ${backgroundColor}22 0.4turn,
    ${spotLightColor}44 0.5turn,
    ${backgroundColor}22 0.6turn,
    ${backgroundColor}00 1turn`;

標準

  const defaultLight = `
    ${backgroundColor}00 0turn,
    ${backgroundColor}66 0.4turn,
    ${spotLightColor}66 0.5turn,
    ${backgroundColor}66 0.6turn,
    ${backgroundColor}00 1turn`;

明るめ

  const defaultLight = `
    ${backgroundColor}00 0turn,
    ${backgroundColor}66 0.4turn,
    ${spotLightColor}dd 0.5turn,
    ${backgroundColor}66 0.6turn,
    ${backgroundColor}00 1turn`;

conic-gradientの複数指定と座標指定による配置の制御

ここまでは分かりやすい様に単一の照明だけを扱っていましたが、ステージ照明の演出を再現するため複数の照明を配置したいと思います。
数を増やすには conic-gradient を複数指定し、照明が重ならないように各照明の座標を調整します。
中心点をステージ領域内に配置すると悪目立ちしてしまうので、中心点が領域の外となるように配置するのがオススメです。

background: `
conic-gradient(from ${0}deg at 35% -20%, ${light}),   //1
conic-gradient(from ${0}deg at 65% -20%, ${light}),   //2
conic-gradient(from ${0}deg at 10% -10%, ${light}),   //3
conic-gradient(from ${0}deg at 90% -10%, ${light}),   //4
conic-gradient(from ${180}deg at 45% 110%, ${light}), //5
conic-gradient(from ${180}deg at 55% 110%, ${light})  //6
`,

またご覧のように同一の ${light} を指定すると、描画時に光の強弱の差が生まれてしまいます。
これは background プロパティに複数の値をセットした場合は先頭のものが優先される「先勝ち」でレンダリングされる仕様のため、 不透明領域の重なりによって偏りが出てしまうためです。

どうしても差異が気になる場合は多少面倒ですが同一の照明設定を用いずに、視覚調整を行いながら各個に光軸に相当する色経由点の透明度を調整すると良いでしょう。


視覚調整しながら個別に設定したもの

三角関数で照明をグルングルン回す

ここまでで一通り照明の配置が完了しました。
最後にステージ照明の演出として肝となるアニメーションの実装となります。
lightProgress には 適当なsetIntervalやコンテンツの再生などに応じて線形でインクリメントされる値をお好きに代入してください。

Math.sin(正弦波)

  const lightProgress = 0;
  const sin = Math.sin(lightProgress);
    <div
      style={{
        background: `
        conic-gradient(from ${40 * sin}deg at 10% -10%, ${light}),
        conic-gradient(from ${-40 * sin}deg at 90% -10%, ${light})
        `,
      }}
    >
    </div>

https://youtu.be/Oi0SWtxwYXI

Math.cos(余弦波)

  const lightProgress = 0;
  const cos = Math.cos(lightProgress);
    <div
      style={{
        background: `
        conic-gradient(from ${180 * cos}deg at 45% 110%, ${light}),
        conic-gradient(from ${-180 * cos}deg at 55% 110%, ${light})
        `,
      }}
    >
    </div>

https://youtu.be/CD8zB7wo-yM

Math.tan(正接波)

正接波は90度周期で -∞ を行き来する際にイカした挙動をするので、応用してフラッシュ照明演出に使用できます。

  const lightProgress = 0;
  const tan = Math.tan(lightProgress);
    <div
      style={{
        background: `
        conic-gradient(from ${-10 * tan}deg at 35% -20%, ${light}),
        conic-gradient(from ${10 * tan}deg at 65% -20%, ${light})
        `,
      }}
    >
    </div>

https://youtu.be/XFOX5RbNxUg

Discussion