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

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

新規登録して質問してみよう
ただいま回答率
85.69%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Three.js

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

Q&A

解決済

1回答

958閲覧

three.jsを用いてwebブラウザ上にobj.mtlファイルを表示する

abu1234

総合スコア1

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Three.js

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

0グッド

0クリップ

投稿2022/11/13 16:23

編集2022/11/14 18:50

前提

大学の研究で、PythonFlaskでサーバーを構成し、three.jsを使用することでobj mtlファイルを読み込むプロフラムを利用しています。
データのやり取りはJSON形式で利用しています
前のものがtheree.jsのr96で書かれていたものだったので、r146に変更しようと画策しているところです
かれこれ3週間ほど躓いています

実現したいこと

obj,mtlファイルをwebブラウザ上に表示させたいです

発生している問題・エラーメッセージ

エラーは出ていませんが、画面が真っ白で希望している3Dモデルが表示されません

エラーメッセージ

該当のソースコード

/////////////////階層構造 test |+test.html |+models |+obj |+male02              |+male02.mtl              |+male02.obj              |+male02に関する画像ファイル              |+wakamiya.mtl |+wakamiyaに関するobjファイルすべて              |+wakamiyaに関する画像ファイル /////////////////うまくいったもの <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>test</title> <style> *{margin:0px} </style> </head> <body> <!-- ① importmap を使用した書き方に変更 --> <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@0.146.0/build/three.module.js", "three/addons/": "https://unpkg.com/three@0.146.0/examples/jsm/" } } </script> <script type="module"> import * as THREE from 'three'; import { MTLLoader } from 'three/addons/loaders/MTLLoader.js'; import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; let camera, scene, renderer; let mouseX = 0, mouseY = 0; let windowHalfX = window.innerWidth / 2; let windowHalfY = window.innerHeight / 2; init(); animate(); function init() { const container = document.createElement( 'div' ); document.body.appendChild( container ); camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); camera.position.z = 250; // scene scene = new THREE.Scene(); const ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 ); scene.add( ambientLight ); const pointLight = new THREE.PointLight( 0xffffff, 0.8 ); camera.add( pointLight ); scene.add( camera ); // model const onProgress = function ( xhr ) { if ( xhr.lengthComputable ) { const percentComplete = xhr.loaded / xhr.total * 100; console.log( Math.round( percentComplete, 2 ) + '% downloaded' ); } }; new MTLLoader() .setPath( 'models/obj/male02/') .load( 'male02.mtl', function ( materials ) { materials.preload(); new OBJLoader() .setMaterials( materials ) .setPath( 'models/obj/male02/' ) .load( 'male02.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }, onProgress ); } ); // renderer = new THREE.WebGLRenderer(); renderer.outputEncoding = THREE.sRGBEncoding; renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement ); document.addEventListener( 'mousemove', onDocumentMouseMove ); // window.addEventListener( 'resize', onWindowResize ); } function onWindowResize() { windowHalfX = window.innerWidth / 2; windowHalfY = window.innerHeight / 2; camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } function onDocumentMouseMove( event ) { mouseX = ( event.clientX - windowHalfX ) / 2; mouseY = ( event.clientY - windowHalfY ) / 2; } // function animate() { requestAnimationFrame( animate ); render(); } function render() { camera.position.x += ( mouseX - camera.position.x ) * .05; camera.position.y += ( - mouseY - camera.position.y ) * .05; camera.lookAt( scene.position ); renderer.render( scene, camera ); } </script> </body> </html> ////////////うまくいかなかったものpart1(new MTLLoaderの中身だけ変更しました) new MTLLoader() .setPath( 'models/obj/male02/') .load( 'wakamiya.mtl', function ( materials ) { materials.preload(); new OBJLoader() .setMaterials( materials ) .setPath( 'models/obj/male02/' ) .load( 'wakamiya_Span1.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }, onProgress ); } ); ////////////うまくいかなかったものpart2(new MTLLoaderの中身において全てのobjファイルを含むように変更 ) new MTLLoader() .setPath( 'models/obj/male02/') .load( 'wakamiya.mtl', function ( materials ) { materials.preload(); new OBJLoader() .setMaterials( materials ) .setPath( 'models/obj/male02/' ) .load( 'wakamiya_Pier1.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }, onProgress ); new OBJLoader() .setMaterials( materials ) .setPath( 'models/obj/male02/' ) .load( 'wakamiya_Pier2.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }, onProgress ); new OBJLoader() .setMaterials( materials ) .setPath( 'models/obj/male02/' ) .load( 'wakamiya_Span1.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }, onProgress ); new OBJLoader() .setMaterials( materials ) .setPath( 'models/obj/male02/' ) .load( 'wakamiya_Span2.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }, onProgress ); new OBJLoader() .setMaterials( materials ) .setPath( 'models/obj/male02/' ) .load( 'wakamiya_Span3.obj', function ( object ) { object.position.y = - 95; scene.add( object ); }, onProgress ); } ); //////////ここまでが試したパターンになります //////////r96で作成されたうまくいっているもの //////////jqueryInterface.js function CallOBJ(){ var json = JSON.stringify($(this).attr("id")); $.ajax({ type:'POST', url:'/bridge', data:json, contentType:'application/json', //サーバからの返送データ(json)を受け取る success: function(data){ var result = JSON.parse(data.ResultSet1); SetOBJ(result); } }); //a要素のクリックイベントの場合はfalseを返して、リンク遷移を回避する必要がある。 return false; } function SetOBJ(Path){ var onProgress = function (xhr){}; var onError = function(xhr){}; new THREE.MTLLoader() .load('/obj/'+Path.FilenameSet[0].mtl,function(materials){ materials.preload(); for(i=0; i < Path.FilenameSet.length; i++){ new THREE.OBJLoader() .setMaterials(materials) .load('/obj/'+Path.FilenameSet[i].obj,function(object){ objmodel = object.clone(); objmodel.scale.set(1,1,1); obj = new THREE.Object3D(); obj.add(objmodel); group.add(obj); },onProgress, onError); } }); } //////////////check_VR.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>橋のモデル</title> <script src="/static/three.js"></script> <script src="/static/OBJLoader.js"></script> <script src="/static/MTLLoader.js"></script> <script src="/static/jquery-3.1.1.min.js"></script> <script src="/static/jqueryInterface.js"></script> <style> *{margin:0px} </style> </head> <body> <script> var container, statsVR; var room, camera, scene, renderer, group; var controller1, controller2; var raycaster, intersects = []; var objects = [], TextBoard; var tempMatrix = new THREE.Matrix4(); var VRDisplay, VRPose; init(); animate(); function init(){ container = document.createElement( 'div' ); document.body.appendChild( container ); scene = new THREE.Scene(); scene.background = new THREE.Color( 0xffffff ); camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 1000000 ); scene.add(camera); var light1 = new THREE.DirectionalLight(); var light2 = new THREE.DirectionalLight(); light1.position.set( 20, 20, 20 ); light2.position.set( -20, -20, -10 ); scene.add( light1 ); scene.add( light2 ); //500mbの若宮 group = new THREE.Group(); group.position.set(-20000,0,-20000); group.rotation.set(-Math.PI/2,0,Math.PI/2); scene.add( group ); CallOBJ(); renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); render() } function render() { renderer.render( scene, camera ); //UpdateBordRotate(); } </script> </body> </html>

試したこと

esmojule形式にした
HTMLファイルの中のinit関数の中に<script src="/static/jquery-3.1.1.min.js"></script>の中身を入れました
前は、new THREE MTLLoader、new THREE OBJLoaderと書いていたがTHREEがいらなくなったみたいなのでTHREEを打ち消し線消した

補足情報(FW/ツールのバージョンなど)

webブラウザの、開発者ツール等を見ても相対パスの指定等は問題ないと思います

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

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

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

下記のような質問は推奨されていません。

  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。

回答1

1

ベストアンサー

three.js の公式サンプルに MTLLoader / OBJLoader のサンプルがありますので、r96r146 との違いについて確認してみると良いかもしれません。

https://github.com/mrdoob/three.js/blob/r96/examples/webgl_loader_obj_mtl.html
https://github.com/mrdoob/three.js/blob/r146/examples/webgl_loader_obj_mtl.html

以下は変更例です。
① importmap を使用した書き方に変更してみる
② 単純に scene に object を追加してみる
③ カメラの position を指定してみる

html

1<!-- ① importmap を使用した書き方に変更 --> 2<script type="importmap"> 3{ 4 "imports": { 5 "three": "https://unpkg.com/three@0.146.0/build/three.module.js", 6 "three/addons/": "https://unpkg.com/three@0.146.0/examples/jsm/" 7 } 8} 9</script> 10<script type="module"> 11//import * as THREE from '/static/three.module.js'; 12//import { MTLLoader } from '/static/MTLLoaders.js'; 13//import { OBJLoader } from '/static/OBJLoaders.js'; 14import * as THREE from 'three'; 15import { MTLLoader } from 'three/addons/loaders/MTLLoader.js'; 16import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; 17 18var container, statsVR; 19var room, camera, scene, renderer, group; 20var controller1, controller2; 21var raycaster, intersects = []; 22var objects = [], TextBoard; 23var tempMatrix = new THREE.Matrix4(); 24var VRDisplay, VRPose; 25var i 26 27 28init(); 29animate(); 30 31 32function CallOBJ() { 33 34 var json = JSON.stringify($(this).attr("id")); 35 36 $.ajax({ 37 type: 'POST', 38 url: '/bridge', 39 data: json, 40 contentType: 'application/json', 41 //サーバからの返送データ(json)を受け取る 42 success: function(data) { 43 var result = JSON.parse(data.ResultSet1); 44 SetOBJ(result); 45 } 46 }); 47 //a要素のクリックイベントの場合はfalseを返して、リンク遷移を回避する必要がある。 48 return false; 49} 50 51function SetOBJ(Path) { 52 var onProgress = function(xhr) {}; 53 var onError = function(xhr) {}; 54 55 new MTLLoader() 56 .load('/obj/' + Path.FilenameSet[0].mtl, function(materials) { 57 materials.preload(); 58 59 for (i = 0; i < Path.FilenameSet.length; i++) { 60 new OBJLoader() 61 .setMaterials(materials) 62 .load('/obj/' + Path.FilenameSet[i].obj, function(object) { 63 //objmodel = object.clone(); 64 //objmodel.scale.set(1, 1, 1); 65 //obj = new THREE.Object3D(); 66 //obj.add(objmodel); 67 //group.add(obj); 68 69 scene.add(object); // ② 単純に scene に object を追加してみる 70 }, onProgress, onError); 71 } 72 }); 73} 74 75function init() { 76 77 container = document.createElement('div'); 78 document.body.appendChild(container); 79 scene = new THREE.Scene(); 80 scene.background = new THREE.Color(0xffffff); 81 camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000000); 82 camera.position.set(0, 0, 100); // ③ カメラの position を指定してみる(値は適当です。適宜設定下さい) 83 scene.add(camera); 84 85 var light1 = new THREE.DirectionalLight(); 86 var light2 = new THREE.DirectionalLight(); 87 light1.position.set(20, 20, 20); 88 light2.position.set(-20, -20, -10); 89 scene.add(light1); 90 scene.add(light2); 91 92 //500mbの若宮 93 group = new THREE.Group(); 94 group.position.set(-20000, 0, -20000); 95 group.rotation.set(-Math.PI / 2, 0, Math.PI / 2); 96 scene.add(group); 97 98 CallOBJ(); 99 100 renderer = new THREE.WebGLRenderer({ 101 antialias: true 102 }); 103 renderer.setPixelRatio(window.devicePixelRatio); 104 renderer.setSize(window.innerWidth, window.innerHeight); 105 container.appendChild(renderer.domElement); 106} 107 108function animate() { 109 requestAnimationFrame(animate); 110 render(); 111} 112 113 114 115function render() { 116 117 renderer.render(scene, camera); 118 119 //UpdateBordRotate(); 120} 121</script> 122

投稿2022/11/13 23:06

cx20

総合スコア4605

abu1234❤️を押しています

下記のような回答は推奨されていません。

  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。

回答へのコメント

abu1234

2022/11/14 00:51

返信ありがとうございます。 importmapをつけると、 Uncaught TypeError: モジュール指定 “three” の解決時にエラーが発生しました。モジュール指定の相対パスは “./” または “../”, “/” のいずれかで始まらなければなりません。 というエラーメッセージが表示されて動きません importmapの書き方は変更せずとも、やはり画面が真っ白で何も表示されませんでした(エラーメッセージもありませんでした) 原因はほかに何か考えられるのでしょうか?
abu1234

2022/11/14 01:17 編集

firefoxとgoglecromeの最新版で実行しました goglecromeのほうではimportmapが使えるみたいなので変更例のプログラムそのままを使ったのですが、やはりエラーメッセージがなく白い画面が表示されました。 batファイルの実行画面 (C:\Users\kako1\Desktop\WakamiyaVRDemo>echo off * Serving Flask app "main" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: on * Restarting with stat * Debugger is active! * Debugger PIN: 147-243-067 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) 127.0.0.1 - - [14/Nov/2022 10:14:12] "GET / HTTP/1.1" 200 - {'FilenameSet': [{'mtl': 'wakamiya.mtl', 'obj': 'wakamiya_span1.obj'}, {'mtl': 'wakamiya.mtl', 'obj': 'wakamiya_span2.obj'}, {'mtl': 'wakamiya.mtl', 'obj': 'wakamiya_span3.obj'}, {'mtl': 'wakamiya.mtl', 'obj': 'wakamiya_pier1.obj'}, {'mtl': 'wakamiya.mtl', 'obj': 'wakamiya_pier2.obj'}]} 127.0.0.1 - - [14/Nov/2022 10:14:12] "POST /bridge HTTP/1.1" 200 - 127.0.0.1 - - [14/Nov/2022 10:14:12] "GET /obj/wakamiya_span2.obj HTTP/1.1" 200 - 127.0.0.1 - - [14/Nov/2022 10:14:12] "GET /obj/wakamiya_span1.obj HTTP/1.1" 200 - 127.0.0.1 - - [14/Nov/2022 10:14:12] "GET /obj/wakamiya_span3.obj HTTP/1.1" 200 - を見ても、成功例と同じように表示されていて、おそらくobj mtlloaderは正常に機能しているのですが...
cx20

2022/11/14 11:13

> 原因はほかに何か考えられるのでしょうか? もう少し原因の切り分けをした方が良さそうですね。 ひとまずは Python 側は置いておいて、JavaScript + three.js だけで、問題の事象が再現するか試してみるのが良いのではないでしょうか。 three.js の公式サンプルとしては、下記が MTLLoader / OBJLoader のサンプルになります。 https://github.com/mrdoob/three.js/blob/r146/examples/webgl_loader_obj_mtl.html こちらのサンプルを用いて、下記モデルが表示できるか試してみて下さい。 ・wakamiya.mtl ・wakamiya_span1.obj
abu1234

2022/11/14 18:21

ご丁寧に返信本当にありがとうございます。 サンプルを参考にサーバーを介さず、ローカル環境でfirefox上で実施しました(他のブラウザだとセキュリティ?の問題でエラー発生) サンプルのmale02に関するものは黒い背景の中にしっかり人の姿が表示されていました しかし、wakamiyaに関する話では黒い背景のみで何も表示されませんでした(ウェブ開発ツールを見るとダウンロードは完了している?気になるエラーメッセージは特になし Uncaught TypeError: モジュール指定 “three” の解決時にエラーが発生しまし~のメッセージは表示されるが、male02の場合でも表示されるしデバッガー見てもモジュールは読み込めている) この場合mtl.objファイルに問題があると見たほうがいいのでしょうか?(バージョンとか?) 厚かましくて申し訳ないのですが、階層構造、試したコードを該当するソースコードのところに書いたのでお時間あるときに見てくださると幸いです
cx20

2022/11/14 18:52 編集

> セキュリティ?の問題でエラー発生 three.js など WebGL を用いた Web ページがエラーになるのは、CORS に関するエラーかと思います。 その場合は、ローカル Web サーバーを立てる必要があります。 ローカル Web サーバーを立てる方法は色々あるかと思いますが、Python が入っている環境であれば、 コマンドプロンプトより test.html が置いていあるフォルダで ----------------------------------------- python -m http.server 5000 ----------------------------------------- とすれば、ローカル Web サーバーが起動するかと思います。 その後、任意のブラウザで http://localhost:5000/test.html でアクセス下さい。
cx20

2022/11/14 19:31

> この場合mtl.objファイルに問題があると見たほうがいいのでしょうか?( そうですね。male02 が表示できているのであれば、試そうとしているモデル側の問題かもしれません。 そのモデルは他のビューア(「Blender」や Windows 標準の「3D Viewer」など)では表示できている感じでしょうか? 読み込みでエラーが出ているわけでは無いようですので、恐らく、読み込みは出来ているのだと思います。 モデルが male02(人物のモデル)より大きい為に画面に表示しきれていないという可能性もありそうです。 three.js では、色々な Helper(表示の問題を確認する為の補助クラス)が用意されています。 まずは、 BoxHelper を用いて、モデルの全体が読み込めているが確認してみて下さい。 https://threejs.org/docs/#api/en/helpers/BoxHelper BoxHelper 使用例) ----------------------- scene.add(object); // 表示しようとしているモデル const box = new THREE.BoxHelper(object, 0xff0000); scene.add(box); // BoxHelper を用いてモデルの大きさを確認 -----------------------
abu1234

2022/11/14 19:57 編集

疑問一つ一つに本当にありがとうございます。 webブラウザを介した表示以外まだ試したことありませんので確認します。 かなり大きいモデルなので、もしかしたら表示の問題かもしれません。 本日取り組んで、進展ありましたらまた報告させて頂きますm(_ _)m
cx20

2022/11/14 20:03

モデルが大きいということであれば、 ・モデルのスケールを小さくしてみる ・カメラの位置を遠ざける というのを試してみると良いかもしれませんね。
abu1234

2022/11/15 19:31 編集

本日いろいろ取り組んでみたところどうやらカメラの視界内に入ってなかったことが原因だったみたいです(r96で成功してるもののままの値だと何故か視界外) camera.positionの値を色々変えてみると映し出すことができ、無事サーバーを介した表示もできました。 どこの部分が原因が分からなく、ずっと躓いていたのですが、考え方から丁寧に教えて頂き本当にありがとうございました!

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.69%

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

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

質問する

同じタグがついた質問を見る

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Three.js

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