質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

Q&A

解決済

1回答

680閲覧

three.jsで観覧車を回転させたい

gubi.m

総合スコア16

Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

0グッド

0クリップ

投稿2022/08/28 12:30

編集2022/09/02 06:12

three.jsで観覧車を作ったのですが、思うように動かず困っています。
①乗り物一つずつが変な動きをする(それぞれ別々の座標を中心に回転している)
②観覧車を回すと(アニメーションをスタートさせると)、下記のエラーが大量に表示されている
three.module.js:6969 THREE.Object3D.add: object not an instance of THREE.Object3D. null
③元々乗り物一つずつが、全体的にもう少し真ん中に寄っており、観覧車の丸い骨格にくっついていたが、positionを変えたせいで(?)観覧車の骨格からズレて表示されるようになってしまった。
④154行めに以下コードを書いているが、コンソールに「An error happened」と表示されてしまう。(表示などはちゃんとされている)
function (error) {
console.log('An error happened');
console.log(error);
}

お手数をおかけしますが、何卒よろしくお願いいたします。イメージ説明
イメージ説明

import * as THREE from "./build/three.module.js"; import { OrbitControls } from "./controls/OrbitControls.js"; import { GLTFLoader } from "./build/GLTFLoader.js"; import GUI from 'https://cdn.jsdelivr.net/npm/lil-gui@0.17/+esm';//デバッグのやつ // import { RectAreaLightHelper } from "./helpers/RectAreaLightHelper.js"; //サイズ const sizes = { width: window.innerWidth, height: window.innerHeight, }; //canvasの大きさを画面いっぱいにする const webgl =document.getElementById("webgl"); webgl.width = sizes.window; webgl.height = sizes.height; //リサイズイベント発生時(画面の大きさを変えたとき)に実行 window.addEventListener("resize", () => { //サイズを取得 sizes.width = window.innerWidth; sizes.height = window.innerHeight; //カメラのアスペクト比を正す camera.aspect = sizes.width / sizes.height; camera.updateProjectionMatrix(); //レンダラーのサイズを調整する renderer.setSize(sizes.width, sizes.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); }); // レンダラーを作成 // ウィンドウサイズ設定 const renderer = new THREE.WebGLRenderer(); renderer.setSize(sizes.width, sizes.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); document.body.appendChild(renderer.domElement); // == 追記 renderer.outputEncoding = THREE.GammaEncoding; // 出力エンコーディングを定義 //不要?明るくなるぽい renderer.gammaOutput = true;//明るくなるっぽい renderer.physicallyCorrectLights = true; renderer.outputEncoding = THREE.sRGBEncoding; renderer.toneMapping = THREE.ACESFilmicToneMapping; // renderer.gammaFactor = 2.2; // == ここまで追記 console.log(window.devicePixelRatio); //console.log(width + ", " + height); // シーンを作成 const scene = new THREE.Scene(); scene.background = new THREE.Color( 0x000000 ); // 背景色 // カメラを作成 //カメラ const camera = new THREE.PerspectiveCamera( 75, sizes.width / sizes.height, 0.1, 1000 ); camera.position.x = 0; camera.position.y = 0; camera.position.z = 6; scene.add(camera); const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; const loader = new GLTFLoader(); //blenderで作ったglbファイルを配列に const urls = [ 'blender/foundation.glb',//回転しない、縦棒の土台の部分 'blender/skelton.glb',//objを配列skeltonにpushした。円形の骨格の部分 'blender/wagon_1.glb',//以下、objを配列wagonsにpushした。乗り物一つずつ(以下8個) 'blender/wagon_2.glb', 'blender/wagon_3.glb', 'blender/wagon_4.glb', 'blender/wagon_5.glb', 'blender/wagon_6.glb', 'blender/wagon_7.glb', 'blender/wagon_8.glb' ]; let wagons = [];//ワゴンの配列 let skelton = [];//回転する骨格の配列(中身は一つのみ) let obj = null; for(let i = 0; i < urls.length; i++){//blenderで作ったglbファイルを順番に読み込む loader.load( urls[i], function (gltf) { const obj = gltf.scene;//後に、i=1の時skeltonの配列に入れて、i>1の時wagonsの配列に入れる const animations = gltf.animations; obj.scale.set(1, 1, 1); obj.position.set(0,0,0) scene.add(obj); //urlsの配列の、2以上(ワゴンのみ。土台と骨格除く)を、wagonsという配列に入れる。(urls[2]のobjが、wagons[0]になる。はず) if(i > 1){//ワゴンそれぞれの場所を指定 obj.position.x = 2 * Math.cos(Math.PI / 180 * (360*i/8)); obj.position.y = 2 * Math.sin(Math.PI / 180 * (360*i/8)); obj.position.z = 0; wagons.push(obj); }else if(i > 0 && i < 2){ skelton.push(obj); } /* Blenderでアニメーション設定していないため、ここから不要なはず ================ for (let i = 0; i < animations.length; i++) { let animation = animations[i]; //Animation Actionを生成 let action = mixer.clipAction(animation) ; //ループ設定(1回のみ) action.setLoop(THREE.LoopOnce); //アニメーションの最後のフレームでアニメーションが終了 action.clampWhenFinished = true; //アニメーションを再生 action.play(); } Blenderでアニメーション設定していないため、ここまで不要なはず ================ */ },// ========== ここまでfunction (gltf) function (error) { console.log('An error happened'); console.log(error); } );// ========== ここまでloader.load }// ========== ここまでfor文 let rot = 0;//カメラを回転させるときにフレームごとに角度をプラスしていくので、プラスするための変数を用意※animate関数の中で宣言すると効かないので外に書く function animate() { rot += 1;//1度ずつ足す let radian = rot * (Math.PI / 180);//度数をラジアンに変換する if(skelton.length > 0){//skeltonの配列に入れたやつ for(let i = 0; i < skelton.length; i++){ skelton[i].rotation.z = radian; } } if(wagons.length > 0){//wagonの配列に入れたやつ for(let i = 0; i < wagons.length; i++){ wagons[i].position.y = 2 * Math.sin(Math.PI / 180 * (360*i/8) + radian); wagons[i].position.x = 2 * Math.cos(Math.PI / 180 * (360*i/8) + radian); //wagons[i].position.z = 0; } } //リロードしないと場所が変わらないので、常にぐるぐる回らせるために、アニメート関数に入れて、アニメート関数をフレーム単位で変えていく //JavaScriptでアニメーションをさせるには、時間経過で関数を呼び続ける必要がある。requestAnimationFrame()というグローバルメソッドは引数として渡された関数を、毎フレーム実行する requestAnimationFrame(animate);//これだけではアニメート関数を呼んでいない //レンダリング renderer.render(scene, camera);//これもフレームタイムでレンダリングしないと、画面がフレーム単位でレンダリングされないので、アニメート関数に組み込む scene.add(obj); } //回転をスタートさせるボタン const rotationStart = document.getElementById("rotationStart"); const rotationStop = document.getElementById("rotationStop"); //回転をスタートさせる rotationStart.addEventListener("click", function(){ animate(); }); //回転をストップさせたい(止まらない) rotationStop.addEventListener("click", function(){ cancelAnimationFrame(animate); }); // 平行光源 const light = new THREE.DirectionalLight(0xFFFFFF); light.intensity = 1; // 光の強さ light.position.set(3, 10, 1); // シーンに追加 scene.add(light); //環境光源(アンビエントライト):すべてを均等に照らす、影のない、全体を明るくするライト const ambient = new THREE.AmbientLight(0xffffff, 1); scene.add(ambient); //シーンにアンビエントライトを追加 // 初回実行(何のため??) tick(); function tick() { controls.update(); if (obj != null) { console.log(obj); } renderer.render(scene, camera); requestAnimationFrame(tick); }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

観覧車の骨格からズレて表示される

まずはモデルの原点がどこになっているか確認してみて下さい。

js

1const axesHelper = new THREE.AxesHelper( 1 ); 2obj.add(axesHelper); 3scene.add(obj);

おそらく、モデルの原点が中央に無い為にずれて表示されているのではないかと思います。
https://jsfiddle.net/cx20/c6smyd05/6/
イメージ説明

コンソールに「An error happened」と表示されてしまう

ドキュメントを確認してみたところ load メソッドの引数の指定が違っている気がします。
順番的に function ( error ) の代わりに function ( xhr ) の方が呼ばれているのではないでしょうか?

https://threejs.org/docs/#examples/en/loaders/GLTFLoader

js

1loader.load( 2 'models/gltf/duck/duck.gltf', 3 function ( gltf ) { 4 }, 5 function ( xhr ) { 6 }, 7 function ( error ) { 8 } 9);

投稿2022/08/28 14:19

編集2022/08/28 15:14
cx20

総合スコア4632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gubi.m

2022/08/28 23:24

すぐ回答してくださり誠にありがとうございます!! An error happenedについては、function ( xhr ) {...}を追加することで消えました! 他の部分に関しては夜じっくり見てみます! ありがとうございます。
gubi.m

2022/09/01 09:55

ご連絡が遅くなり申し訳ございません。 無事回転させることができました!!! 回転の中心がズレている点に関しては、blenderからの書き出しの時点で原点に持ってくることで、中心が適当な場所に来て解消されました。 とても助かりました!ありがとうございました!!
cx20

2022/09/01 21:12

解消されたようで何よりです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問