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. 補足説明
コード解説
-
エッジ判定
-
edgeThreshold
: エッジの判定しきい値。この値より黒色に近いピクセルはエッジと判定されます。 -
edgeDistance
: 黒色の RGB 値との距離を計算します。 -
edgeFactor
:edgeDistance
をedgeThreshold
を使って滑らかに変化させ、エッジの強さを表す値を生成します。
-
-
ブラー処理
-
blurAmount
: ブラーの量。この値が小さいほど、ブラーが弱くなります。 - 4 つの
mix
関数を用いて、上下左右に少しずらしたテクスチャのサンプルを、元のピクセルと混ぜています。この処理によって、エッジ付近にぼかし効果がかかります。 -
edgeFactor
を使って、エッジ付近のピクセルにのみブラー効果を強く適用しています。
-
-
最終的な色
- 黒色の判定を行い、黒色であれば
discard
します。 - それ以外の場合は、アンチエイリアシング処理済みで、必要に応じてブラー処理された色を適用します。
- 黒色の判定を行い、黒色であれば
調整ポイント
-
edgeThreshold
: エッジ判定のしきい値です。この値を調整することで、エッジの判定範囲を変更できます。 -
blurAmount
: ブラーの量です。この値を調整することで、ブラーの強さを変更できます。
注意点
- このコードでは、
for
ループを使用していませんが、テクスチャサンプリングを 4 回行っているため、パフォーマンスへの影響はあります。 - ブラーの範囲が狭い場合は、
blurAmount
を小さくしてください。 - ブラーの強さは、シェーダーコードの他の部分や画像の性質によって調整する必要があります。
まとめ
この方法では、シェーダーを使用して、黒い背景の動画の黒の部分を透明にし、エッジにブラー効果を適用しました。 for
ループを使わずに、周辺のピクセルをサンプリングして平均化することで、シンプルなブラー効果を実現しました。
この技術を応用することで、様々なエフェクトや処理をシェーダーで実現できます。