LoginSignup
1
0

More than 5 years have passed since last update.

three.jsで、MeshBasicMaterialでは影が表示されない

Posted at

three.js初学者です。

「床面と球体を表示して、球体の影を床面に表示する」というだけのことをするつもりが、えらく手こずってしまいました。

まずは以下の記事を参考に試しました。
https://qiita.com/edo_m18/items/44b4292e2970912eafa3

カメラやシーンを設定し、PlaneGeometryで床面を作り、SphereGeometryで球体を作って、castShadowやreceiveShadowを設定した... のですが、うまくいきません。

shadow_2.png

他の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/

で、なんとなくマテリアルの定義箇所なんかをいじってみたら... これでうまくいきました。

shadow_1.png

床面に適用するマテリアルを 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>
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0