LoginSignup
6
1

Three.jsで黒い背景の動画の黒の部分を透明にする方法を、シェーダーを使って実現する方法を紹介します。今回は、for ループを使わずに、周辺のピクセルをサンプリングして平均化することで、エッジのみにブラーをかける方法を紹介します。

1. 準備

まず、Three.jsの環境を準備します。 HTMLファイルにThree.jsライブラリを読み込み、シーン、カメラ、レンダラーを作成します。

index.html

<!DOCTYPE html>
<html>
<head>
  <title>Three.js Black Background Transparency</title>
  <style>
    body { margin: 0; }
    canvas { display: block; }
  </style>
</head>
<body>
  <video id="myVideo" width="1280" height="720" loop muted>
    <source src="your_video.mp4" type="video/mp4">
  </video>
  <script src="https://cdn.jsdelivr.net/npm/three@0.147.0/build/three.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

2. 動画の読み込み

動画ファイルをHTMLに読み込みます。

<video id="myVideo" width="1280" height="720" loop muted>
  <source src="your_video.mp4" type="video/mp4">
</video>

3. シェーダーの作成

動画テクスチャを適用するメッシュを作成し、シェーダーマテリアルを適用します。 シェーダーコードは以下のように記述します。

script.js

// シーン、カメラ、レンダラーを作成
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 動画テクスチャの作成
const video = document.getElementById("myVideo");
const texture = new THREE.VideoTexture(video);
texture.format = THREE.RGBFormat;
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;

// シェーダーマテリアルの作成
const material = new THREE.ShaderMaterial({
  uniforms: {
    videoTexture: { value: texture },
  },
  vertexShader: `
    varying vec2 vUv;

    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    varying vec2 vUv;
    uniform sampler2D videoTexture;

    void main() {
      vec4 color = texture2D(videoTexture, vUv);

      // 黒のしきい値
      float blackThreshold = 0.1;

      // エッジ検出
      vec4 left = texture2D(videoTexture, vUv + vec2(-0.01, 0.0));
      vec4 right = texture2D(videoTexture, vUv + vec2(0.01, 0.0));
      vec4 top = texture2D(videoTexture, vUv + vec2(0.0, 0.01));
      vec4 bottom = texture2D(videoTexture, vUv + vec2(0.0, -0.01));
      float edgeStrength = abs(color.r - left.r) + abs(color.r - right.r) + abs(color.r - top.r) + abs(color.r - bottom.r);
      edgeStrength += abs(color.g - left.g) + abs(color.g - right.g) + abs(color.g - top.g) + abs(color.g - bottom.g);
      edgeStrength += abs(color.b - left.b) + abs(color.b - right.b) + abs(color.b - top.b) + abs(color.b - bottom.b);

      // ブラー処理
      vec4 blurredColor = (color + left + right + top + bottom) / 5.0; // 近傍のピクセルを平均化

      // 黒のしきい値より暗い場合は透明にする
      if (color.r < blackThreshold && color.g < blackThreshold && color.b < blackThreshold) {
        discard;
      } else {
        gl_FragColor = mix(color, blurredColor, edgeStrength * 0.1); // エッジ付近はブラー後の色を適用
      }
    }
  `
});

// メッシュの作成
const geometry = new THREE.PlaneGeometry(10, 10);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// 動画の再生
video.play();

// レンダリング
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

4. 実行

このコードを実行すると、黒い背景の動画の黒の部分が透明になり、エッジがぼかされた効果が得られます。

5. 補足説明

コード解説

  1. エッジ判定

    • edgeThreshold: エッジの判定しきい値。この値より黒色に近いピクセルはエッジと判定されます。
    • edgeDistance: 黒色の RGB 値との距離を計算します。
    • edgeFactor: edgeDistanceedgeThreshold を使って滑らかに変化させ、エッジの強さを表す値を生成します。
  2. ブラー処理

    • blurAmount: ブラーの量。この値が小さいほど、ブラーが弱くなります。
    • 4 つの mix 関数を用いて、上下左右に少しずらしたテクスチャのサンプルを、元のピクセルと混ぜています。この処理によって、エッジ付近にぼかし効果がかかります。
    • edgeFactor を使って、エッジ付近のピクセルにのみブラー効果を強く適用しています。
  3. 最終的な色

    • 黒色の判定を行い、黒色であれば discard します。
    • それ以外の場合は、アンチエイリアシング処理済みで、必要に応じてブラー処理された色を適用します。

調整ポイント

  • edgeThreshold: エッジ判定のしきい値です。この値を調整することで、エッジの判定範囲を変更できます。
  • blurAmount: ブラーの量です。この値を調整することで、ブラーの強さを変更できます。

注意点

  • このコードでは、for ループを使用していませんが、テクスチャサンプリングを 4 回行っているため、パフォーマンスへの影響はあります。
  • ブラーの範囲が狭い場合は、blurAmount を小さくしてください。
  • ブラーの強さは、シェーダーコードの他の部分や画像の性質によって調整する必要があります。

まとめ

この方法では、シェーダーを使用して、黒い背景の動画の黒の部分を透明にし、エッジにブラー効果を適用しました。 for ループを使わずに、周辺のピクセルをサンプリングして平均化することで、シンプルなブラー効果を実現しました。

この技術を応用することで、様々なエフェクトや処理をシェーダーで実現できます。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1