こんにちは、はっちゃんです。
今回も張り切って太陽系を進化させていきましょう!
前回までで、太陽系をランダムに置くところまでやりました。 three.jsの基本をおさらいしてみよう!〜基礎の基礎編〜 three.jsで地球を作ってみよう!〜基礎の基礎編2〜 three.jsで、太陽系をつくってみよう!〜ちょっと応用編〜
しかし、通常であれば、星と星が重なったとき、後ろの星には前の星の影が映るはずですよね。前回までの太陽系ではそれが再現できていません。
不自然ですね…。
今回のゴールは、下記のように、土台とそれぞれのメッシュに影が投影されることです。
それでは、メッシュと土台に影を投影する設定(シャドウマッピング)を加えて、さらにリアルにしていきましょう。
シャドウマッピングとは
シャドウマッピングは,ライト方向の深度値を格納したシャドウマップと呼ばれるテクスチャを使用してシーンに影を付加して描画を行う手法です。 シャドウマップの長所としては物体の形によらず影がかけることです。 短所としては,テクスチャを使用するためテクスチャの解像度が低いとジャギーがでてしまい影が汚くなってしまうという点です。
簡単に言うと、影の設定ですね。
three.jsでは、
- レンダリング時、影を使用するかどうか
- 光源が影を作るかどうか
- 物体が影を作るかどうか
- 物体が影を受けるかどうか
などが簡単に設定できます。
renderer.shadowMap.enabled = true; //レンダリング時、影を使用するかどうか
light.castShadow = true; //光源が影を作るかどうか
mesh.castShadow = true; //物体が影を作るかどうか
mesh.receiveShadow = true; //物体が影を受けるかどうか
宇宙空間をまっさらな土台に変更
まず、宇宙空間のサイズのままだと大きすぎて影ができないので、サイズを小さくします。合わせて、影を分かりやすくするため、宇宙空間を単色(グレー)に変更します。
■サイズ変更
universe = planetFactory(textureUniverse, 10000, 20, 20, 'isUniverse');
↓
universe = planetFactory(textureUniverse, 950, 20, 20, 'isUniverse');
controls.maxDistance = 9900; //遠ざかれる距離の最大値
↓
controls.maxDistance = 940; //遠ざかれる距離の最大値
■素材変更
new THREE.MeshLambertMaterial({ // 材質
map: texture,
side: THREE.DoubleSide // 裏からも見えるようにする
})
↓
new THREE.MeshLambertMaterial({ // 材質
color: 0x444444,
side: THREE.DoubleSide // 裏からも見えるようにする
})
シャドウマッピングの設定
レンダラーと光源の設定
まず、レンダラーに下記コードで影を使用する命令を書きます。
renderer.shadowMap.enabled = true;
次に、光源から発した光でメッシュに影を投影する設定をします。
デフォルトだと光が当たる範囲がとても狭く設定されているので、その値も変更します。
light.castShadow = true;
light.shadow.camera.left = -200;
light.shadow.camera.right = 200;
light.shadow.camera.top = 200;
light.shadow.camera.bottom = -200;
この2つが、シャドウマッピングの大前提になるので、しっかり設定しておきましょう。
メッシュの設定
■宇宙
宇宙は影を作る必要がないので、receiveShadowのみ設定します。
sphere = new THREE.Mesh(
new THREE.SphereGeometry(radius, widthSegments, heightSegments), // 形状
new THREE.MeshLambertMaterial({ // 材質
color: 0x444444,
side: THREE.DoubleSide // 裏からも見えるようにする
})
);
sphere.position.set(0, 0, 0);
sphere.receiveShadow = true;
■太陽
太陽は光源の上にかぶさっているだけのメッシュなので、影の設定はせずに、MeshBasicMaterialで作るだけでOKです。
sphere = new THREE.Mesh(
new THREE.SphereGeometry(radius, widthSegments, heightSegments), // 形状
new THREE.MeshBasicMaterial({ // 材質
map: texture,
side: THREE.DoubleSide // 裏からも見えるようにする
})
);
sphere.position.set(0, 0, 0);
■その他の惑星
その他の惑星は、影を作る・受ける両方の設定が必要なので、receiveShadowとcastShadowを設定します。
sphere = new THREE.Mesh(
new THREE.SphereGeometry(radius, widthSegments, heightSegments), // 形状
new THREE.MeshLambertMaterial({ // 材質
map: texture
})
);
sphere.position.set(
Math.random() * 500 - 250,
Math.random() * 500 - 250,
Math.random() * 500 - 250
);
sphere.castShadow = true;
sphere.receiveShadow = true;
これでシャドウマッピングができました。
shadow helperを置いてみる
シャドウマッピングにもhelperが存在します。
点光源のhelperは、なぜか一方向の光の広がりしか可視化できないのですが、光の当たる範囲などが分かるので、参考にして光の強さや範囲を調整しましょう。
shadowHelper = new THREE.CameraHelper(light.shadow.camera);
scene.add(shadowHelper);
こんな見た目になります。
完成
シャドーマッピングが正しく設定できると、以下のようになります(視認性を高めるため、helperはコメントアウトしております)。
See the Pen April Blog Shadow by k_hatsushi (@hatsushi_kazuya) on CodePen.
宇宙空間と各惑星に影が投影されているのが分かるかと思います。
まとめ
いかがでしたでしたか?
影の描画は、リアルな表現をするのに非常に重要なので、ぜひ覚えておきましょう!
次回は土星と天王星に輪を作ろうと思います。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。