シン・three.jsでPlateauモデルを表示する方法

国交省による都市モデル、Plateauの3DモデルをThree.jsで表示する方法が実質ネットになかったのでまとめました

TL;DR(最初にまとめると)

  • Plateauの3Dモデルは座標系が通常の3Dモデルとは異なっており、そのままだと表示されません
  • Lod1と呼ばれる低解像度のモデルではテクスチャが設定されていないので、設定する必要があります
  • モデル自体にも法線ベクトルが設定されておらず、そのままだと黒い塊になるので設定する必要があります

サンプルコードはどこ?

ここにあります

github.com

どうやるの?

レンダラーの初期化

このあたりは他の場合と変わりません。ここまでに限れば公式のサンプルなど参考になるリソースが大量にあるので、適当に持ってくればOKです

github.com

Plateauの座標系をなんとかする

Plateauのモデルにおいて、各頂点のz軸は通常の高さですが、x軸とy軸は平面直角座標系に基づいています。平面直角座標系は測量用の座標系であり、日本国内に複数ある基準点のいずれか一つからの距離を表しています(詳しくはこちら)。逆に言うとこのおかげでモデル上の位置を通常の緯度経度に変換するなんてこともできるのですが、一方でたいていのモデルが中心から数キロ程度離れた場所に配置されることになり、通常のモデル表示用のコードをそのまま持ってきただけでは表示されません。

そこで中心位置を何とかする必要があります。方法としてはいくつかあるのですが、threejsで表示することを考えると一番楽なのはメッシュに変換した後でそれぞれ最大値と最小値を取得中心を計算してその分を動かすという方法になります。ただしモデルは実際には建物単位であろうと思われるサブモデルの集合体なのですが、fbx形式では親子関係がループしている場所がありその対策も必要です。

テクスチャのないモデル対策

Lod1のようにテクスチャが設定されていないモデルの場合、代替モデルを設定する必要があります。three.jsでは3Dモデルは頂点を表すgeometryとマテリアルを表すmaterialをメンバーとして有しており、テクスチャの無い場合はmaterial.mapが空になるのでこれを利用して判定します。

法線ベクトルを計算する

Plateauのモデルは3DCGやゲームでいうところのアセットよりもCAD等の設計データに近いため、光の反射等を計算するのに必要な法線ベクトルが設定されていません。先述の通りthreejsでは頂点に関わるデータはgeometryに収納されており、computeVertexNormalsメソッドにより設定できます

最終的なコード

            const loader = new FBXLoader();
            const lod1Example = 'models/53392546_bldg_6677.fbx';
            const lod2Example = 'models/53392633_bldg_6677.fbx';
            const alterMaterialColor = 0x90D7EC;
            
            loader.load(lod2Example, function (obj) {
                let maxX = -Infinity;
                let minX = Infinity;
                let maxY = -Infinity;
                let minY = Infinity;
              
                let checked = {};
                
                function traverser(child) {
                    if (checked[child.id] === true) {
                        return;

                    }
                    child.castShadow = true;
                    child.receiveShadow = true;
                    checked[child.id] = true;
                    if (child.isMesh !== true) {
                        return child.traverse(traverser)

                    }

                    child.castShadow = true;
                    child.receiveShadow = true;
                    child.geometry.computeVertexNormals() 
                    if (!child.material.map) {
                        child.material = new THREE.MeshToonMaterial({ color:alterMaterialColor })
                    }



                    
                    const position = child.geometry.attributes.position
                    for (let index = 0; index < position.count; index++) {
                        const x = position.getX(index)
                        if (x > maxX) {
                            maxX = x;
                        }
                        else if (x < minX) {
                            minX = x
                        }
                        const y = position.getY(index)
                        if (y > maxY) {
                            maxY = y;
                        }
                        else if (y < minY) {
                            minY = y
                        }

                       

                    }
                };
                obj.traverse(traverser);
                const centerX = (maxX + minX) / -2
                const centerY = (maxY + minY) / -2;
                
                obj.position.set(centerX, centerY, 0);
                


            
                scene.add(obj);

            });

グラフを手軽に共有できるツールを作ってみました

 
Graphiddleという、Web上のリソースをベースにD3.js + jQueryなグラフを手軽に共有できるサービスを作ってみました。

これは何?

 オープンデータやクラウド型のオフィスソフトのデータを手軽にグラフ化して共有すること、そしてグラフを手軽に使いまわすこと、その二つを目標としたWEBアプリです

 例えばオープンデータプラットフォームで公開されている福井県鯖江市の男女年齢別の人口統計をベースに五才ごとにまとめたグラフ
がこんな感じです。元になったデータはここに公開されていますが、このサイトには他にも同様のデータが公開されているのでフォーク用のページでURLを切り替えれば別の町で同じようなことができます。
 データ自体も男女別で2014年から2010年の分まであるので、コードをいじれば動的に切り替えたり人口ピラミッドを作ったりと色々なことができるわけです。
 
 

コードの書き方

 変数としてグラフを描画するsvgを表すd3.jsのオブジェクトである「svg」、dom要素としてのsvgを操作するためのjQueryオブジェクトである「$svg」、web上のリソースをパースした結果である「data」の三つの変数が設定されているので、それを元にゴリゴリと書いていけばグラフの完成です。
 なお現在のところ、一度保存したらグラフの編集はできません。フォークのみです。ログイン系めんどいのです…

ToDO

 まずはソースコードの公開を目標としています。それとログイン回りの実装。デザイン面も手を抜きすぎですのでなんとかしたいです

 

ライブラリ・ファースト

  1. フレームワークはもう必要ない」というブログ記事
    1. フレームワークではなく、コンポーネントと規約で開発すべき」
  2. Lalavelもライブラリファースト
  3. MVCはあなたを殺す」
  4. 5からLaravelにModelは削除
  5. Lumen(laravelベースのマイクロフレームワーク)
    1. ベンチマーク盛り過ぎじゃないかと話題に

Lraravelでのサービス事例

  1. 典型的なレガシーシステム
  2. というわけでリニューアル
    1. CakePHPがダメというわけではない
    2. Laravelは設定が楽でかゆいところに手が届く
  3. 遅いのとPSR基準になっていないのが問題

第88回PHP勉強会に参加してきました

自己紹介

 テーマは「好きなエディタ」について。メモ帳、vimeclipse、zendstudio、秀丸adobe bracketなど。xcodeemacsは少数派w

PHPUnitでモックを使ってテストしよう

  1. テストは面倒くさくないか?
  2. 実際に案件で使っていると言える人は少ない
  3. PHPUnitは奥が深い
  4. 様々な条件がある
  5. モックを使おう
  6. 事例が解っていればコピペで行ける
    1. 他にも例えばGuzzleはモックをattachできる
  7. モックが正しいとどう確認する?
    1. それは信じるしかない

東京Node学園15限目に参加してきました

「io.jsについて」

  1. io.jsは「friendly fork」
    1. 元々は「spork」。forkほど離れていないという意味
  2. 基本的にnode.jsとそれほど違わない
  3. オープンガバナンスモデルが基本
  4. なるべく開発者に開示
      1. 2週間に一度Googleハングアウトによるオープンミーティング
      2. 録画と議事録が公開される
      3. コアコントリビューターが一つの会社に偏らないように
    1. これによりコントリビューション数が増加
    2. コミッタも6人増加
    3. アクティブになった
  5. v8のバージョンはV4.1.0.14
  6. ecmascript6の機能が使える
  7. constとかテンプレートリテラル
    1. テストやりづらそう
  8. V8エンジンの動的なオプション追加
  9. Streamやログ出力も簡単に
  10. httpモジュールは古いままだが、それ以外は速くなっている。10%程
  11. Nodeとio.jsの混乱を日本では防ぎたい

extensible web

  1. これで何が変わるんだ?
  2. 「つべこべ言わずにコードを書け」
    1. 「標準化には時間がかかる」
    2. 「これじゃない感がある」
    3. 「ベンダーによって対応はまちまち」
  3. 「もっと開発者に力を」
  4. まず開発を
    1. そのためにはそれを実現できる低レベルな機能が必要
  5. ブラウザが実現する機能をもっとも単純なレベルで実現できるAPI
  6. 最近ではちょっとずつ出てきている
  7. 実際に実装してみると大変

ws の permessage deflateを実装した話とそれによりsocket.ioがどう変わるか

  1. 3年物のissue
  2. permessage deflate=httpのgzip相当
    1. ただし双方向で圧縮されるので、クライアントから重いものを投げたい時は最適
  3. context takover
  4. 前のメッセージの圧縮辞書を使いまわす事で圧縮率を改善する
  5. ただし現状のブラウザでオンのみ+chromeのみ
    1. 脆弱性があったので改善してもらった

CodeOnMobile

  1. スマホでコーディングできたらいいんじゃないか?
  2. アプリはしょぼいのしかない
    1. githubのコードをブラウザ上で編集するwebアプリ
  3. Node+Angular.js+ACE
  4. キーバインド独自実装
    1. JS限定だけど、うまくやればサーバーサイドのテストもできるんじゃあ…

今できる通信高速化に挑戦してみた

  1. いきなりjavascriptでgotoする黒魔術紹介
  2. lz4→gzipで圧縮すると圧縮率が向上する
  3. lz4は速度重視、インメモリ型
  4. jsonは特に効く
  5. gzipはwebの標準
  6. lz4は簡単
  7. ベンチマークしてみると、通信速度が十分速い場合は展開コストを回収しきれない
  8. 残念ながらトータルのスループットは変わらない
  9. ガバイトサイズでないと意味がない
  10. ネイティブだったら少し速いかも

Socket.io

  1. ライフゲームをみんなでプレイするゲームを実装してみた

web audio api使って声の高低に合わせてオブジェクトを上下させるアプリつくりました

 13日に開催されたweb music ハッカソンで声の高低に合わせてオブジェクトを上下させるアプリ作ってきました
 マイクを許可して、声か楽器の音程を上下させると丸い球が上下に動きますので、横から飛んでくる棒を避けてください。


仕組み

 web audio apiには波形をフーリエ解析するAPIがあり、音にどの周波数がどれくらいの音量で含まれているのかを2行ほどで解析してくれます。(サンプル)。
 これを使うことでボコーダーやコード進行の検出のような踏み込んだ音のハックができるわけです。
 
 このアプリではanimationframeごとにもっとも音量の大きい周波数を取得し、それを音の高低としています。ただし実際には最大の周波数はかなり揺れるので50フレーム分の平均を取って平滑化し、滑らかにみせています。慣性のような挙動をするのはそのせいですね

これから

 当たった時の演出を乗せて、教育用のゲームとして発展させていければな、と