実現したいこと
- Three.jsで、アニメーション付きGLTFモデルをマテリアル名で取得し、シェーダーマテリアルに置き換えたい。
前提
GLTFモデルはBlenderのシェイプキーアニメーションで作成しています。下のように球が変形するアニメーションをWeb上で再生するところまでは上手くいきました。
発生している問題
後述のソースコードの39行目あたりで、メッシュをマテリアル名(bg_mat)で取得してシェーダーマテリアルに置き換えたところ、色は意図通りに変わったのですが、アニメーションが動かなくなってしまいました。
アニメーションに関わる何かが上書きされてしまったのでしょうか?
アニメーションが消えてしまう原因や消えない方法をご教示いただけると幸いです。
該当のソースコード
JavaScript
1window.addEventListener('load', init); 2 3function init() { 4 // レンダラーを作成 5 const renderer = new THREE.WebGLRenderer({ 6 canvas: document.querySelector('#canvas'), 7 antialias: true, 8 alpha: true, 9 }); 10 // シーンを作成 11 const scene = new THREE.Scene(); 12 13 // カメラを作成 14 // new THREE.PerspectiveCamera(視野角, アスペクト比, near, far) 15 const camera = new THREE.PerspectiveCamera(45, 1, 1, 2000); 16 camera.fov = 50; 17 camera.position.set(0, 0.5, 8); 18 // 原点方向を見つめる 19 camera.lookAt(0, 0, 0); 20 //camera.rotation.x = THREE.Math.DEG2RAD * (-45); 21 22 // Load GLTF or GLB 23 const loader = new THREE.GLTFLoader(); 24 const url = '3d/sample.glb'; 25 26 let model = null; 27 // clockを作成する 28 const clock = new THREE.Clock(); 29 loader.load( 30 url, 31 function (gltf) { 32 model = gltf.scene; 33 model.traverse((node) => { 34 if (!node.isMesh) return; 35 }); 36 model.scale.set(1, 1, 1); 37 model.position.set(0, 0, 0); 38 39 //マテリアルを置換 40 const bgMesh = getMatbyName(model, "bg_mat"); 41 //バーテックスシェーダ 42 const vertexShader =`void main() {gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`; 43 //フラグメントシェーダ 44 const fragmentShader =`precision mediump float; 45 void main() { 46 // オレンジ色のRGB値を定義 (1.0, 0.5, 0.0) 47 vec3 orangeColor = vec3(1.0, 0.5, 0.0); 48 // 最終的に出力される色に代入 49 gl_FragColor = vec4(orangeColor, 1.0); 50 }`; 51 52 const bgMat = new THREE.ShaderMaterial({ 53 vertexShader:vertexShader, 54 fragmentShader:fragmentShader, 55 side:THREE.DoubleSide, 56 }); 57 58 bgMesh.material = bgMat; 59 60 61 // アニメーションを読み込む 62 let mixer = new THREE.AnimationMixer(model); 63 gltf.animations.forEach((clip) => { 64 mixer.clipAction(clip).play(); 65 }); 66 67 scene.add(model); 68 69 // アニメーションを更新する関数を定義する 70 function update() { 71 if (mixer) { 72 mixer.update(clock.getDelta()); 73 } 74 } 75 76 // アニメーションを再生するイベントを設定する 77 renderer.setAnimationLoop(() => { 78 update(); 79 renderer.render(scene, camera); 80 }); 81 82 }, 83 function (error) { 84 console.log('An error happened'); 85 } 86 ); 87 88 //テクスチャをガンマ補正 89 renderer.gammaOutput = true; 90 renderer.gammaFactor = 2.2; 91 92 // ライト追加 93 hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x4169e1, 4); 94 scene.add(hemisphereLight); 95 96 // カメラコントローラーを作成 97 const controls = new THREE.OrbitControls(camera, renderer.domElement); 98 controls.enableDamping = true; 99 controls.dampingFactor = 0.2; 100 101 // フォグを設定 102 scene.fog = new THREE.Fog(0x2a2a5f, 150, 200); 103 104 // 初回実行 105 var frame_num = 0; 106 tick(); 107 onResize(); 108 109 // リサイズイベント発生で実行 110 window.addEventListener('resize', onResize); 111 112 function onResize() { 113 // サイズを取得 114 const w = window.innerWidth; 115 const h = window.innerHeight; 116 // 描画サイズ 117 renderer.setSize(w, h); 118 // ピクセル比 119 renderer.setPixelRatio(window.devicePixelRatio); 120 // カメラのアスペクト比を正す 121 camera.aspect = w / h; 122 camera.updateProjectionMatrix(); 123 console.log('h' + h + 'h' + h); 124 // レンダリング 125 renderer.render(scene, camera); 126 } 127 128 function tick() { 129 requestAnimationFrame(tick); 130 renderer.render(scene, camera); 131 controls.update(); 132 133 } 134} 135 136function update() { 137 controls.update(); 138 requestAnimationFrame(update); 139 140} 141 142// 指定したマテリアル名がセットされている[ mesh ] を返します 143function getMatbyName(_o, _name){ 144 let refO = null; 145 146 if(_o.material && _o.material.name.indexOf(_name) > -1 ){ 147 return _o; 148 } 149 150 if(_o.materials){ 151 for(let i =0; i < _o.materials.length; i++){ 152 refO = getMatbyName(_o.materials[i], _name ); 153 if(refO) {return refO;} 154 } 155 } 156 157 for(let i =0; i < _o.children.length; i++){ 158 refO = getMatbyName(_o.children[i], _name ); 159 if(refO) {return refO; } 160 } 161 162 return refO; 163}
補足情報(FW/ツールのバージョンなど)
Blender3.6
three.js r124