
どうも!かけちまるです!
Three.jsを少し触れるようになると、様々な図形を描画できると思います。
その図形をスクロールによって動かす方法を解説します。
この記事では、
がわかります。
次のコードを元にスクロールアニメーションを加えていきます。
ディレクトリ構成index.html css/ -style.css js/ -main.js
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="./css/style.css"> <script async src="https://unpkg.com/es-module-shims@1.5.8/dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@0.142.0/build/three.module.js" } } </script> <script src="./js/main.js" type="module"></script> </head> <body> <section class="section">main</section> <section class="section">about</section> <section class="section">works</section> <section class="section">contact</section> </body> </html>
style.css*{ margin: 0; padding: 0; box-sizing: border-box; } html, body{ height: 100%; } canvas{ position: fixed; top: 0; left: 0; z-index: -1; } .section{ color: #fff; display: flex; align-items: center; justify-content: center; font-size: 32px; width: 100%; height: 100%; }
main.jsimport * as THREE from 'three'; /** * シーン・カメラ・レンダラーを用意する */ const fov = 50; const fovRad = (fov / 2) * (Math.PI / 180); // 視野角をラジアンに変換 let distance = (window.innerHeight / 2) / Math.tan(fovRad); // カメラ距離を求める const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.z = distance; const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); document.body.appendChild(renderer.domElement); /** * ジオメトリ+マテリアル=メッシュを用意する */ const coneGeometry = new THREE.ConeGeometry( 100, 200, 64 ); const lambertMaterial = new THREE.MeshPhysicalMaterial({ reflectivity: 0, roughness: 0.2, metalness: 0, clearcoat: 0.3, clearcoatRoughness: 0.25, color: new THREE.Color(0x3da8e6), ior: 1.2, thickness: 10.0, }); let coneMesh = new THREE.Mesh(coneGeometry, lambertMaterial); coneMesh.rotation.x = -0.1; coneMesh.rotation.z = -0.2; scene.add(coneMesh); /** * ライトを追加する */ let pointLight = new THREE.PointLight(0xffffff, 2, 0, 0.1); pointLight.position.set(200, 100, 300); scene.add(pointLight); let pointLight02 = new THREE.PointLight(0xffffff, 2, 0, 0.1); pointLight02.position.set(-300, 300, -300); scene.add(pointLight02); // アニメーション function animate() { renderer.render(scene, camera); requestAnimationFrame(animate); } animate(); // ブラウザのリサイズに対応させる window.addEventListener('resize', onWindowResize); function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; distance = (window.innerHeight / 2) / Math.tan(fovRad); camera.position.z = distance; camera.updateProjectionMatrix(); }
ここまで次のようになっていればオッケーです。
ここまで何をやっているかよくわからない人はこちらの記事が参考になると思います。
5〜7行目はwindowサイズとカメラの画角を合わせメッシュ位置の指定などをpx
で指定できるようにカメラの距離を求めています。
詳細は次の記事で解説しています。
ブラウザを読み込んだ時にメッシュの位置を維持するためにスクロール量をy
座標に設定します。(13行目)
スクロールしたときにスクロール量をy
座標に設定することでメッシュを動かします。(14~16行目)
main.js・・・ // ブラウザのリサイズに対応させる window.addEventListener('resize', onWindowResize); function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; distance = (window.innerHeight / 2) / Math.tan(fovRad); camera.position.z = distance; camera.updateProjectionMatrix(); } coneMesh.position.y = window.pageYOffset; window.addEventListener('scroll', () => { coneMesh.position.y = window.pageYOffset; });
こんな感じになったらOKです。
慣性をつけるには、スクロール量に任意の値をかけてあげればできます。0
に近づくほどスクロール量より少なく動きます。1
より大きくなるとスクロール量より大きく動きます。
main.jsconeMesh.position.y = window.pageYOffset * 0.4; window.addEventListener('scroll', () => { coneMesh.position.y = window.pageYOffset * 0.4; });
スクロール量より少なく動くようになりました。
main.jsconeMesh.position.y = window.pageYOffset * 1.5; window.addEventListener('scroll', () => { coneMesh.position.y = window.pageYOffset * 1.5; });
スクロール量より大きく動くようになりました。
スクロールアニメーションは使える場面が多いと思いますのでマスターしておくと応用が効くのではないかと思います。
おわり
フィードバックを送信
記事についてのフィードバックはTwitterかお問い合わせフォームから受け付けております。