three.js初学者です。
「床面と球体を表示して、球体の影を床面に表示する」というだけのことをするつもりが、えらく手こずってしまいました。
まずは以下の記事を参考に試しました。
https://qiita.com/edo_m18/items/44b4292e2970912eafa3
カメラやシーンを設定し、PlaneGeometryで床面を作り、SphereGeometryで球体を作って、castShadowやreceiveShadowを設定した... のですが、うまくいきません。
他のWebページを参考に、shadow.camera.far や shadow.camera.top を変えて試してみても、一向に解決しません。光源の位置や球体と床面のいち関係を変えてもやはりダメ。
参考にしたWebページ:
http://gupuru.hatenablog.jp/entry/2013/12/16/210348
http://ginneko-atelier.com/blogs/tips/threejs-4/
で、なんとなくマテリアルの定義箇所なんかをいじってみたら... これでうまくいきました。
床面に適用するマテリアルを MeshBasicMaterial から MeshPhongMaterial に変更することで解決しました。
この点、他のサイトで触れていない(少なくとも、検索しても見つからなかった)ところを見ると、おそらくは非常に基礎的な内容なのでしょうね。
そもそもMeshBasicMaterialは実際には使われないものなのか... ?
なんにせよ、私同様の初学者がつまづくことを防ぐべく、Quiitaに書かせていただきました。
以下、ソース全文。(Github上のソース置き場:https://github.com/gimmickdock/threejs_training/blob/master/dropShadowTest.html )
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>
<script>
// ページの読み込みを待つ
window.addEventListener('load', init);
const FIELD_SIZE = 1000;
const CANVAS_WIDTH = 540;
const CANVAS_HEIGHT = 540;
function init() {
// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#myCanvas'),
antialias: true
});
renderer.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
renderer.shadowMap.enabled = true;
// シーンを作成
const scene = new THREE.Scene();
// カメラを作成
const camera = new THREE.PerspectiveCamera(45, CANVAS_WIDTH / CANVAS_HEIGHT, 0.01, FIELD_SIZE);
camera.position.set(0, 100, 0);
// 平行光源を作成
const directionalLight = new THREE.DirectionalLight(0xFFFFFF);
directionalLight.position.set(200, 300, 200);
directionalLight.shadow.camera.near = 100;
directionalLight.shadow.camera.far = FIELD_SIZE;
directionalLight.shadow.camera.top = FIELD_SIZE;
directionalLight.shadow.camera.bottom = FIELD_SIZE * (-1);
directionalLight.shadow.camera.left = FIELD_SIZE;
directionalLight.shadow.camera.right = FIELD_SIZE * (-1);
directionalLight.castShadow = true;
scene.add(directionalLight);
// 2つの床面を作成
const planeGeometry = new THREE.PlaneGeometry( 199, 1200, 32 );
const planeColor = 0xCCCCCC;
const planeMaterials = [
new THREE.MeshBasicMaterial( {color: planeColor} ),
new THREE.MeshPhongMaterial( {color: planeColor} )
];
const planePositions = [
{x: -100, y: 0, z: 0},
{x: 100, y: 0, z: 0}
];
for(let i=0; i < 2; i++){
const plane = new THREE.Mesh( planeGeometry, planeMaterials[i] );
plane.position.set(planePositions[i].x, planePositions[i].y, planePositions[i].z);
plane.rotation.x = Math.PI / 2 * (-1);
plane.receiveShadow = true;
scene.add( plane );
}
// 2つの球体を配置
const ballSize = 20;
const ballPositions = [
{x: -100, y: ballSize, z: -500},
{x: 100, y: ballSize, z: -500}
];
const ballGeometry = new THREE.SphereGeometry(ballSize, 100);
for (let j = 0; j < 2; j++) {
const ballMaterial = new THREE.MeshPhongMaterial( { color: 0x88ccff } );
const ball = new THREE.Mesh( ballGeometry, ballMaterial );
ball.position.set( ballPositions[j].x, ballPositions[j].y, ballPositions[j].z);
ball.castShadow = true;
scene.add(ball);
}
renderer.render(scene, camera);
}
</script>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>