three.js概論#6

2024/6/11

Shadow

three.jsには、影を実装するための組み込みのソリューションが用意されている。

仕組み

three.jsは、1つのレンダリングを行う際、まず影を落とすと想定されるライトごとにレンダリングを行う。これらのレンダリングは、ライトの見え方をカメラのようにシミュレートする。これらのライトのレンダリング中に、MeshDepthMaterialがすべてのメッシュのマテリアルを置き換える。

結果はテクスチャとシャドウマップとして保存される。

シャドウマップは直接見ることはできないが、シャドウを受けるオブジェクトのマテリアルに適用され、ジオメトリに投影される。

シャドウマップのサンプル

影を有効にする

まず、renderershadowMapプロパティを有効にする。

renderer.shadowMap.enabled = true;

そして、影を落とすオブジェクトにcastShadowプロパティを、影を受けるオブジェクトにはreceiveShadowプロパティを設定する。

mesh.castShadow = true;
mesh.receiveShadow = true;

最後に、ライトのcastShadowプロパティを設定する。

PointLight, SpotLight, DirectionalLightの3つのライトのみが影をサポートしている。

directionalLight.castShadow = true;

シャドウマップの設定

three.jsは各ライトに対してシャドウマップを生成し、それを使用して影を描画する。

このシャドウマップには、ライトのshadowプロパティを使ってアクセスすることができる。

directionalLight.castShadow = true;
console.log(directionalLight.shadow);

レンダーサイズ

シャドウマップの解像度は、shadow.mapSizeプロパティのwidthheightプロパティで設定できる。

デフォルトは512x512で2のべき乗の値にする必要がある。

directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;

Near/Far

シャドウマップのレンダリングにはカメラ使っており、このカメラは他のカメラと同じプロパティを持つので、nearfarプロパティを使って影がどこまで表示されるかを設定できる。

また、CameraHelperを、影のカメラに適用することで、影のカメラの位置やnearfarを確認することができる。

// カメラヘルパーを作成
const directionalLightCameraHelper = new THREE.CameraHelper(
directionalLight.shadow.camera,
);
scene.add(directionalLightCameraHelper);
// カメラヘルパーを非表示にする場合
directionalLightCameraHelper.visible = false;
// シャドウマップのnear/farを設定
directionalLight.shadow.camera.near = 1;
directionalLight.shadow.camera.far = 6;

カメラの範囲

DirectionalLightのシャドウカメラは、デフォルトでOrthographicCameraを使用している。

そのため、left, right, top, bottomプロパティを使って、シャドウカメラの範囲を設定できる。

範囲が小さいほど、シャドウマップの解像度が高くなる。

directionalLight.shadow.camera.top = 2;
directionalLight.shadow.camera.right = 2;
directionalLight.shadow.camera.bottom = -2;
directionalLight.shadow.camera.left = -2;

ぼかし

radiusプロパティを使って、シャドウマップのぼかしを設定できる。

directionalLight.shadow.radius = 10;

シャドウマップのアルゴリズム

シャドウマップには異なる種類のアルゴリズムを適用することができる。

  • BasicShadowMap: デフォルトのシャドウマップ。速度が速いが、品質が低い。
  • PCFShadowMap: ピクセルごとのぼかしを適用することで、シャドウの品質を向上させる。
  • PCFSoftShadowMap: PCFShadowMapよりもぼかしを強くすることで、より柔らかい影を描画する。
  • VSMShadowMap: バリアンスシャドウマップ。シャドウマップの品質を向上させる。

変更するには、shadowMap.typeプロパティを設定する。

renderer.shadowMap.type = THREE.PCFSoftShadowMap;

Particle

three.jsにおけるパーティクルは、3Dグラフィックスのシーン内で小さな点や粒子のようなオブジェクトを大量に描画するために使用される。パーティクルは、煙、火花、星、雨などのエフェクトを表現するのに適しており、リアルなシミュレーションや視覚効果を作り出すために広く利用される。

パーティクルのメリットは、フレームレートを落とさずに画面上に何十万ものパーティクルを配置できること。

欠点は、各パーティクルを構成する平面が常にカメラに向かっているところ。

パーティクルの作成には、BufferGeometryPointsMaterialPointsを使用する。

Geometry

基本的なジオメトリを使用でき、この場合はジオメトリの各頂点がパーティクルになる。

const particlesGeometry = new THREE.SphereGeometry(1, 32, 32);

PointsMaterial

PointsMaterialは、パーティクルのサイズを制御するsizeや、パーティクルに遠近感を出すsizeAttenuationなどの、パーティクル専用の固有のプロパティが用意されている。

const particlesMaterial = new THREE.PointsMaterial({
size: 0.02,
sizeAttenuation: true,
});

Points

最後にMeshと同じ方法で、Pointsクラスを使用して、パーティクルを作成する。

const particles = new THREE.Points(particlesGeometry, particlesMaterial);
scene.add(particles);

Custom geometry

組み込みジオメトリではなく、カスタムジオメトリを作成するには、BufferGeometryを使用し、position属性を追加する。

const particlesGeometry = new THREE.BufferGeometry();
const count = 500;
const positions = new Float32Arry(count * 3);
for (let i = 0; i < count * 3; i++) {
//値が - 5.0から5.0になるように調整
positions[i] = (Math.random() - 0.5) * 10;
}
particlesGeometry.setAttribute(
"position",
new THREE.BufferAttribute(positions, 3),
);

Color, map, alpha map

PointsMaterialには、パーティクルの色を設定するcolorプロパティや、テクスチャを設定するmapプロパティ、透明度を設定するalphaMapプロパティなどがある。

// パーティクルの色を設定
PointsMaterial.color = new THREE.Color("#ff88cc");
// パーティクルにテクスチャを設定
const textureLoader = new THREE.TextureLoader();
const particleTexture = textureLoader.load("hoge.png");
particlesMaterial.transparent = true;
particlesMaterial.alphaMap = particleTexture;
// パーティクルの深度書き込みを無効にして、他のパーティクルの後ろに隠れないようにする
particlesMaterial.depthWrite = false;
// パーティクルのブレンディングを設定
particlesMaterial.blending = THREE.AdditiveBlending;

頂点カラー

各パーティクルに色を設定するには、color属性を使用する。

const colors = new Float32Array(count * 3);
for (let i = 0; i < count * 3; i++) {
colors[i] = Math.random();
}
particlesGeometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
// マテリアルの頂点カラーを有効にする
particlesMaterial.vertexColors = true;

パーティクルのアニメーション

Attributesを更新してアニメーションさせる

各頂点を更新するには、position属性を更新する。

for (let i = 0; i < count; i++) {
let i3 = i * 3;
const x = particlesGeometry.attributes.position.array[i3];
particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(
elapsedTime + x,
);
}
// ジオメトリの更新を通知
particlesGeometry.attributes.position.needsUpdate = true;
back