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

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

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

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

4060閲覧

ループを使ったTextGeometryの生成(Three.js)

essex

総合スコア21

Three.js

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2017/01/20 04:45

お世話になります。Three.jsについて勉強しているのですが、TextGeometryについて
分からないことがあり、質問させていただきます。

現在、表示したい文字と座標を格納した2つのアレイからデータを読み込み、3Dテキストを
配置しようとしています。

作成したのは以下のコード(抜粋です)なのですが、これですと文字が配置されません。

var sText; var sMaterial; var textGeo; var loader = new THREE.FontLoader(); for (var i = 0; i < Name.length; i++) { loader.load( 'fonts/helvetiker_regular.typeface.js', function ( font ) { textGeo = new THREE.TextGeometry(Name[i], { font: font, size: 5, . 中略 . }); sMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } ); sText = new THREE.Mesh( textGeo, sMaterial ); sText.position.set(points[i].position.x,points[i].position.y, points[i].position.z); text_array.push(sText); scene.add( sText ); }); }

不思議なのは、以下の様に書くと、正常に配置されることです。
ということは、表示したい文字と座標のデータは、アレイに正常に格納されていると思われます。

var sText; var sMaterial; var textGeo; var loader = new THREE.FontLoader(); loader.load( 'fonts/helvetiker_regular.typeface.js', function ( font ) { textGeo = new THREE.TextGeometry(Name[0], { font: font, size: 5, . 中略 . }); sMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } ); sText = new THREE.Mesh( textGeo, sMaterial ); sText.position.set(points[0].position.x,points[0].position.y, points[0].position.z); text_array.push(sText); scene.add( sText ); });

do whileでも駄目でしたので、恐らくループのネストの中に入れてはいけないものを
書いてしまっているのではないかと思うのですが、色々変えてもどこが悪いか特定できません。

http://chatora.lolipop.jp/?p=176

こちらのサイトを参考にさせていただきましたが、ループを使ったTextGeometryの配置は可能なようです。
違うのはThree.jsのバージョンの違いから、フォントデータ(json)をhtmlではなくscriptの中から
読み込んでいる点です。

どこが悪いかご教授下さい。よろしくお願いします。

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

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

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

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

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

turbgraphics200

2017/01/20 04:54

コードは<code>ボタンを使って記入してください。これだと、コードが読みづらいです。
guest

回答2

0

ベストアンサー

よく陥りやすいコード実装です。
ループ内において非同期で呼び出される関数(今回の場合はloader.load()のコールバック関数)の中で、ループされる変数を使用すると、最後の値で実行されます。これは、ループが先に完了してしまい後から非同期で関数が実行されるためです。
ですので、別関数にして呼び出すか、クロージャーを使用して非同期関数を呼び出します。
それ以前に、フォントパス情報(typeface.js)をロードしていますが、ループ内でやってしまうと何回もロードされてしまいます。これは1回のロードで十分です。

js

1// 先にfontをロードしておく 2loader.load( 'fonts/helvetiker_regular.typeface.js', function (font) { 3 // ロードが完了したらTextのMesh生成 4 createText(font); 5}); 6 7 8function createTxtMesh(font) { 9 for (var i = 0; i < Name.length; i++) { 10 var txtGeo = new THREE.TextGeometry({ font: font, ...}); 11 // 略 12 } 13}

投稿2017/01/20 05:11

編集2017/01/20 05:19
turbgraphics200

総合スコア4267

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

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

0

配置されないというのは、具体的にどういう状態でしょう?

ただ、ざっと見たところ、ループの変数 i の値が多分、おかしくなっている気がします。
このあたりは非同期処理とループで検索してみるといいかもしれません。

結論から言うと、おそらく、ジオメトリの配置処理の時点ではすべての i が同じ値になっていると思います。
(非同期処理のため、変数 i を参照しても、ループ処理が終わってしまっており、結果としてループ終了後の最後の値が入っている)

なので、以下のようにするとうまく動きませんか?

loader.load( 'fonts/helvetiker_regular.typeface.js', (function (i) { return function ( font ) { textGeo = new THREE.TextGeometry(Name[i], { font: font, size: 5, . 中略 . }); sMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } ); sText = new THREE.Mesh( textGeo, sMaterial ); sText.position.set(points[i].position.x,points[i].position.y, points[i].position.z); text_array.push(sText); scene.add( sText ); } }(i)) });

要は、変数 i をループ処理時点で束縛する、ということをしてます。

投稿2017/01/20 04:53

edo_m18

総合スコア2283

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

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

essex

2017/01/20 20:20

edo_m18様、turbgraphics200様、ご教授ありがとうございます。 また、状況についての説明が不十分だったり、コードの記述が見にくかったりで、 申し訳ありません。 正にご指摘通りの状況でした。要するにループのインデックスだけが先に加算されて、 その後ループの中の処理が走るので、実際に処理する時にはインデックスが終わりまで 行っている…という状況だったのですね。勉強になりました。 そう言われて良く考えると、ループの中で引数が正しく渡されているかwindow.alertで 1周ごとに値を確認してみた時は、文字が指定した場所に表示されていました。どうして window.alertを削除すると正しく表示されなくなるのか不思議でしたが、その理由が 理解できました。また私が最初にアップしたコードは、文字が配置されていないのかと 思いましたが、言われてみると、全てのテキストが一カ所に表示されている様に見えます。 取りあえず、以下の様に直し、期待通りの結果を得ることができました。 do{ var dmin = get3DTX(Name[i],position); //domain_text.push(dmin); //earth.add( dmin ); i= i + 1; }while( i < Name.length); function get3DTX(text_string, position) { var loader = new THREE.FontLoader(); loader.load( 'fonts/helvetiker_regular.typeface.js', function ( font ) { var textGeo = new THREE.TextGeometry(text_string, { font: font, size: 2, height: 0, curveSegments: 0, bevelThickness: 0, bevelSize: 0, bevelEnabled: true }); var lsMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } ); var lsText = new THREE.Mesh( textGeo, lsMaterial ); lsText.position.set(position.x,position.y, position.z); Name_array.push(lsText); scene.add( lsText ); }); } 本当は、生成された3D文字データ(この場合lsText)を戻り値として返し、配置とシーンへの追加は 戻った後に行おうとしたのですが、3D文字のpositionセットがうまくいかないため、 positionデータも引数とし、関数の中でset positionしています。 ところで… turbgraphics200様のご指摘の通り、これですとフォントパスのロードが繰り返されてしまいます。 何故この様な記述になっているかというと、ローダーの引数としてフォントの設定情報を渡す訳ですが、 その中に実際に表示したい文字の情報が含まれているため、例えば10種類の文字を表示するためには、 ロードを10回繰り返すしか方法が浮かばなかったのです。 (このリンクを参考にしました。 http://stackoverflow.com/questions/35589984/textgeometry-in-three-js) ネストをもう一段追加して以下の様に書いてみましたが、これは動いてくれません。 textgeometryに関する処理は、同じWindows7、同じIE11でも、表示される場合とされない場合があるのが 不思議です。 そもそも質問した問題点の原因は理解できたので解決とさせていただきますが、 もし、良い書き方がありましたら、ご教授下さい。 var loader = new THREE.FontLoader(); loader.load( 'fonts/helvetiker_regular.typeface.js', function ( font ) { createText(font); }); function createTxtMesh(font) { for (var i = 0; i < Name.length; i++) { var dmin = get3DTX(top_domain[i],position[i]); } } function get3DTX(text_string, position) { var textGeo = new THREE.TextGeometry(text_string, { font: font, size: 2, height: 0, curveSegments: 0, bevelThickness: 0, bevelSize: 0, bevelEnabled: true }); var lsMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } ); var lsText = new THREE.Mesh( textGeo, lsMaterial ); lsText.position.set(position.x,position.y, position.z); domain_text.push(lsText); earth.add( lsText ); return lsText; } お二人のアドバイスはとても助かりましたので甲乙付けがたかったのですが、 ローダーの問題点もご指摘いただきましたので、turbgraphics200様のご回答を ベストアンサーとさせていただきます。 非常に助かりました。私一人では、気付かなかったと思います。今後とも よろしくお願いします。ありがとうございました。
essex

2017/01/20 20:23

また、読みにくいコードをアップしてしまいました。 済みません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問