Three.jsでライト(AmbientLight以外)を使うと、凹凸のあるオブジェクトには影が表示されます。
が。他のオブジェクトに対しては影が落ちません。
他のオブジェクトに影を落とすためには、いろいろ設定が必要だったのでまとめておきます。
WebGLRenderer.shadowMapを有効にする
const renderer = new THREE.WebGLRenderer({ antialias : true }); renderer.shadowMap.enabled = true;
shadowMapのenabledをtrueにします。
ライトのcastShadowを有効にする
const light = new THREE.DirectionalLight(0xFFFFFF, 1); light.castShadow = true;
影に影響を与えたいlightのcastShadowをtrueにします。
ただし、AmbientLightは影に影響を与えないので、AmbientLight以外を使いましょう。
影を付けるオブジェクトのcastShadowを有効にする
object.castShadow = true;
影が映るオブジェクトのreceiveShadowを有効にする
const wall = new THREE.Mesh(geometry, material); wall.receiveShadow = true;
影を付けるオブジェクトのcastShadowと影を映すオブジェクトのreceiveShadowをそれぞれ有効にすればOKです。
が。よく見ると影がガビガビです。
影の大きさを設定する
const light = new THREE.DirectionalLight(0xFFFFFF, 1); light.castShadow = true; light.shadowMapWidth = 4096; light.shadowMapHeight = 4096;
デフォルトでは512が設定されているのですが、この値を大きくすると影が綺麗になります。
デフォルトが512なので、なんとなく16の倍数を設定してます。
一応、ソースを全部載せておきます。
同一階層にmodel.glbを置けば動くと思います。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>shadow</title> <style> * { margin: 0; padding: 0; } canvas { display: block; } </style> </head> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r127/three.min.js"></script> <script src="https://cdn.rawgit.com/mrdoob/three.js/r127/examples/js/loaders/GLTFLoader.js"></script> <script> const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 100 ); camera.position.set(0, 1, 3); scene.add(camera); const renderer = new THREE.WebGLRenderer({ antialias : true, alpha: true }); renderer.shadowMap.enabled = true; renderer.outputEncoding = THREE.GammaEncoding; renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); const loader = new THREE.GLTFLoader(); const url = './model.glb'; loader.load( url, (gltf) => { const model = gltf.scene; model.traverse((object) => { if (object.isMesh) { object.castShadow = true; } }); model.scale.set(1, 1, 1); model.position.set(0, 0, 0); scene.add(model); renderer.setAnimationLoop(tick); }, (err) => { console.error(err); } ); const light = new THREE.DirectionalLight(0xFFFFFF, 1); light.position.set(1, 0, 1); light.castShadow = true; light.shadowMapWidth = 4096; light.shadowMapHeight = 4096; scene.add(light); const geometry = new THREE.PlaneGeometry(16, 16, 1, 1); const material = new THREE.MeshStandardMaterial({ color: 0xFF0000 }); const wall = new THREE.Mesh(geometry, material); wall.position.set(0, 0, -4); wall.rotation.set(0, 0, 0); wall.receiveShadow = true; scene.add(wall); function tick() { renderer.render(scene, camera); } </script> </body> </html>