three.js概論#6
2024/6/11
Shadow
three.jsには、影を実装するための組み込みのソリューションが用意されている。
仕組み
three.jsは、1つのレンダリングを行う際、まず影を落とすと想定されるライトごとにレンダリングを行う。これらのレンダリングは、ライトの見え方をカメラのようにシミュレートする。これらのライトのレンダリング中に、MeshDepthMaterialがすべてのメッシュのマテリアルを置き換える。
結果はテクスチャとシャドウマップとして保存される。
シャドウマップは直接見ることはできないが、シャドウを受けるオブジェクトのマテリアルに適用され、ジオメトリに投影される。
シャドウマップのサンプル影を有効にする
まず、rendererのshadowMapプロパティを有効にする。
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プロパティのwidthとheightプロパティで設定できる。
デフォルトは512x512で2のべき乗の値にする必要がある。
directionalLight.shadow.mapSize.width = 1024;directionalLight.shadow.mapSize.height = 1024;Near/Far
シャドウマップのレンダリングにはカメラ使っており、このカメラは他のカメラと同じプロパティを持つので、nearとfarプロパティを使って影がどこまで表示されるかを設定できる。
また、CameraHelperを、影のカメラに適用することで、影のカメラの位置やnear、farを確認することができる。
// カメラヘルパーを作成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グラフィックスのシーン内で小さな点や粒子のようなオブジェクトを大量に描画するために使用される。パーティクルは、煙、火花、星、雨などのエフェクトを表現するのに適しており、リアルなシミュレーションや視覚効果を作り出すために広く利用される。
パーティクルのメリットは、フレームレートを落とさずに画面上に何十万ものパーティクルを配置できること。
欠点は、各パーティクルを構成する平面が常にカメラに向かっているところ。
パーティクルの作成には、BufferGeometry、PointsMaterial、Pointsを使用する。
Geometry
基本的なジオメトリを使用でき、この場合はジオメトリの各頂点がパーティクルになる。
const particlesGeometry = new THREE.SphereGeometry(1, 32, 32);PointsMaterial
- 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;