DMM.comラボエンジニアブログスマートフォン用の表示で見るスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。読者です読者をやめる読者になる読者になるDMM.comラボエンジニアブログDMM.comラボのエンジニアブログです。DMM.comを支える技術について書いています。事業サービス開発部の久野です。この度、社内の勉強会のLTで話した内容をまとめてみました!内容はWebGLというJavaScriptのAPIを使って、ブラウザ上で3Dモデルをアニメーション付きで描画するために何を行ったのか、です。▼実際に動作するデモです。テクスチャを大量に読み込まなければならないので表示まで時間がかかるかもしれません。インラインフレームに対応していないため、こちらにアクセスして下さい。▲ブラウザによっては動作しない可能性がありますがデモプログラムなので悪しからず。2.0をブラウザ上のJavaScriptから扱えるようにしたAPIです。GPU(グラフィックカードまたはグラフィックボード)の機能を駆使して高度な3D描画を高速に行うことが出来、昨今のPC、スマートフォン等の主要なブラウザでこのAPIはサポートされています。今やHTML5の標準APIと言っても過言ではない機能です。Professional)等のツールがWebGLに対応した形式でのデータ出力に対応しています。出来ることWebGLで出来る事としては主にGPUの操作になります。幾何学を取り扱うための数学的な処理(ベクトル、行列、四元数といった数学ユーティリティが無い!)3Dモデルデータの読み込みWebGLはGPUへのアクセスを抽象化しただけの簡素なAPIなので3Dの描画を支援するためのユーティリティ等は一切含まれていません。それは幾何学を取り扱うためのベクトルや行列、四元数といった数学的なユーティリティ(プログラマブルシェーダには用意されていますがJavaScriptからは使用不可)にくわえ、3Dモデルデータを読み込む機能やアニメーションを処理するユーティリティなども当然ありません・・・そのような理由もありWebGLを取り扱う際は汎用的なライブラリを導入するか自前で実装するしかないのです。フルスクラッチで3Dモデル描画を実装してみたUnityやthree.jsといった3D描画をブラウザ上で比較的に簡単かつお手軽に実装出来るツールやフレームワーク、ライブラリが登場しています。3Dモデルの描画という仕組みを深く知るため、ここはあえてフルスクラッチでアニメーション付き3Dモデルの描画を実装に挑戦しました。フルスクラッチでの実装を行うにあたり何が必要かと考えた所、大きく分けて3つの実装が必要になるだろうと考えました。アニメーション付き3Dモデルデータの準備JavaScriptで3Dモデルデータの読み込み処理の実装WebGLでの描画処理の実装アニメーション付き3Dモデルデータの準備やはり質の高い3Dモデルデータが無いと、たとえ描画プログラムに凝ってもパッとしないものが出来上がる可能性が高いと考え、まずは完成物の見た目を良くするため質の高い3Dモデルデータを用意する事にしました。Groupが管理するのCOLLADA形式がありました。これらの仕様は複雑で解析処理を自前で実装する事が難しく、さらに私が今回の3Dモデルの描画実装で使用しないであろうデータの仕様が多く含まれていました。three.js等を使用すれば簡単に読み込み処理を実装し不要なデータは無視するという実装は出来たでしょうが、どうしてもフルスクラッチで実装してみたかったので、これらの形式の使用は見送ました。9系まで採用されていた比較的に構造や仕様が単純なX-Fileと呼ばれる形式を使用しようと思ったのですが、定義されているデータの仕様が単純な割には読み込み側の解析処理が非常に面倒なのでこちらも見送りに・・・いきなり大きな壁にぶつかってしまいました。Blenderとの出会い大きな壁にぶつかって途方に暮れながら何か良い方法はないかと3DCGソフトの情報を探していたところBlenderという無料でありながらプロフェッショナルでも採用例があるほど多機能な3DCGソフトを見つけました!しかも、これがPythonを使ってプラグインを実装出来るという優れもの!これを使用してプラグインを組むことにしました!複雑な3Dのデータを私がプログラム上で読み書きしやすいような形式の3Dモデルのデータとして出力するプラグインを作れば、難解な形式(FBX形式やCOLLADA形式)の読み込み処理を実装しなくて済むので、幾分か楽なのではないかと思い、Blenderを使用してデータ出力するプラグインを作成する事にしました。私は3Dプログラミングと3Dモデル作成を一人で作成出来るような人では無いので、何処からか3Dモデルデータを調達してくる必要がありました。このプログラムを試しで実装している間は無料でダウンロード出来て個人利用に利用が限られる3Dモデルを適当に選んで使用していたのですがプレゼン資料等の公的な場に持参することを考慮するためにライセンスに問題がない3Dモデルデータが必要になりました。そこで色々と探してみたところDeNA様が配布しているハッカドールのMMD用モデルデータ、これがCCライセンスであり、ライセンスの内容的に問題がなさそうなので、そちらを使わせて頂く事にしました。手順としてはMMD用の3DモデルをプラグインをBlenderに導入してインポートしました。́Д`).oO(DMMのブログだし艦これのモデルを使いたかったけど個人作成のMMDモデルはライセンスが・・・)BlenderのAPIの学習Blenderのプラグインは調べた限りではPythonかC/C++で書くことが出来ます。3Dモデルのエクスポート程度であればPythonで十分対応出来そうなので公式のAPIドキュメントを黙々と読み、PythonのAPIを把握していきました。Blenderには素晴らしい機能があり、Pythonのスクリプトコンソールが組み込まれていて3DモデルをBlenderに読み込ませた状態で対話的にAPIを叩きモデルデータのステータスを変化させることが出来ます。一通りBlenderのAPIについて学び終えたのでBlenderのプラグインの作成ガイドを読み、手順に従ってBlender上で実装されているエディタを使用して3Dモデルをバイナリのデータにエクスポートするためのプラグインを作成していきました。Blender上で実装されているエディタは、eclipse等のよくあるIDEほど性能は良くありませんでした。デバッガが無いのでPythonのコンソール上で実装した処理を部分的に実行し、正しく動作しているかを埋め込んだログで確認していくようなデバッグの方法しかなく大変で、その上、日本語でコメント書けなかったりとプラグインの開発には苦戦を強いられました。そんな苦労を乗り越え、完成したプラグインを使用して3Dモデルのバイナリデータを無事、出力しました。JavaScriptでデータの読み込みの実装3Dモデルのバイナリデータは用意できたので次は作成したデータをプラグインで実装したエクスポート処理の逆順で3Dモデルデータを解析しインスタンス化していきます。3Dモデルデータのフォーマットを自分で決めながら実装を作成したので読み込み処理の実装は比較的スムーズに時間をかけずに作成することが出来ました。読み込み手順としてXMLHttpRequestクラスを使い3Dモデルデータを読み込んでからArrayBufferクラスとDataViewクラスを使用しバイナリレベルでのデータ解析の処理を実装していきました。この間で一つ苦労したのが文字列の取り扱い方法です。Blenderからデータを出力するときに文字列はUTF-8にエンコードするような処理を実装していたのでUTF-8のバイナリデータをJavaScriptのString型にデコードする処理を実装しました。str;};WebGLで描画処理の実装ここから数学との地獄の戦いです。冒頭にも書きましたがWebGLには幾何学操作を行うための数学的なユーティリティの実装が皆無なのでフルスクラッチでこれらを実装しなくてはなりません。これらを実装した後は作成した数学ユーティリティを駆使してスキニングやIK(逆運動学)を実装していかなくてはならず技術的な課題が数多くありました。ベクトル(Vector)、行列(Matrix)、四元数(Quaternion)の実装WebGLで3D描画を実装する上で必須と思われる三種の神器、ベクトル、行列、四元数を順々に実装していきました。ベクトルと行列は高校等で学習されている方も多いのではないでしょうか?ベクトル(Vector)とはベクトルは複数の値で構成されていて向きと大きさを表すための定義で頂点座標や法線、テクスチャ座標、色といった情報を収納したり空間上のベクトルの長さの算出や2つのベクトルの角度や回転軸の算出等の色々な処理に使用します。行列(Matrix)とは行列は行と列の矩形状に数でを並べた数学上の道具です。今回は3D空間上でのスクリーンの位置や3Dモデルの位置等を操作に使用します。四元数(Quaternion)とは四元数とは、その定義は難しく1つの実数に3つの虚数(Xの2乗が0以下の数)で構成された4次元ベクトルの一種であり、複素数を拡張した数です。行列で処理するには色々と問題のある回転の問題を解くために使用します。行列への変換スキニングの実装スキニングとはロボットのように明確な関節がなく人間の様な柔らかい皮膚をもち関節の境界が曖昧なモデルの関節の動きによる皮膚の変形を表現するための手法です。人型のモデルの腕を例に上げます。肘を起点に、肘から肩の間にある頂点と、肘から手首の間にある頂点があります。肘から肩の間にある頂点は肘から肩に伸びるボーンの回転に影響を大きく受けます。肘から手首の間にある頂点は肘から手首に伸びるボーンの回転に影響を大きく受けます。肘の周りの頂点はどうでしょうか?その境界はあやふやで、その付近の皮膚は伸びたり縮んだりと、どちらのボーンの位置にも影響される領域があることに気づきます。これを表現するためにスキニングと呼ばれる手法を実装する必要があります。実装としては、これらのモデルの頂点がどのボーンにどれだけ影響されて座標を変えるのかといった情報をスキンウェイトという値に従って、元のモデル情報を描画時に変形させて実現します。これは数千、数万と定義されている頂点に対してJavaScriptで実装すると重くなるのでGPUで動作するシェーダプログラムの方で実装してしまいます。逆運動学)なるものが実装されていて3Dモデルにアニメーションを実装するにあたり重要な機能となっています。IKの概要としては通常は親ボーンから子ボーンに向かって再帰的に回転等を伝達させて子ボーンの位置が確定してのですがIKに関しては、この手順が逆で子ボーンが配置されるべき位置が既にあって、それに合わせ子ボーンから親ボーンに向かってボーンの回転等を逆算するようなアルゴリズムとなっています。肩」と子ボーンから親ボーンへと動作を逆算していくイメージになります。これは歩きのモーションや自伝車のペダルを漕ぐようなモーションの様な足をのせる位置が決まっているアニメーションの作成に効力を発揮します。通常であれば対象のボーンが目標位置に移動するように親ボーンから子ボーンの回転を調整しなくてはなりませんがIKを使用すれば、足の位置さえ決めれば回転を自動的に計算してくれるような機能だからです。Kinematics)という方法で実装を試みました。このCCD法というのは大雑把に説明すると対象のボーンの末端が目標位置に近づくようにボーンを回転し、それを子ボーンから親ボーンに向かって順々に対象のボーンが目標位置に近づくように処理していきます。この処理は1回だけでは結果が収束しないので数十回から多い時は数百回、反復させ結果を収束させていきます。Z軸の3つに増え考慮すべきことが爆発的に増え急激に難易度が跳ね上がる上に、しっかり最適化しないと60FPS出ているアニメーションを数FPSにまで落とす程のほどの重い処理なので今回の実装の中で最も苦労しました。色々な技術的試練を乗り越えた後に半分力尽きている状態だったので、簡素な影をつけただけの単純なシェーダをとりあえず書き、完成!やはりフルスクラッチは挫折しそうになるほど大変でした。要求される知識の広さ、ソースコードの量の多さ、それらの知識の収集と実装は土日の手隙な時間を利用して作ったとはいえ着手から完成まで数ヶ月を要しました・・・Unityやthree.jsのような簡単に3Dを表示出来るツールやフレームワーク、ライブラリの類は偉大だなと思います。́Д`).oO(あと超汚いソースコードでよければ、GitHubで公開しています。)最後にWebGLを使用してフルスクラッチでアニメーション付き3Dモデルを描画した話はいかがだったでしょうか?WebGLを含め3Dプログラミングはゲーム系でなく業務系のシステムでは採用例が日本では、まだまだ少なくニッチな分野だと言わざる得ません。総本山という日本語のページの中では最も情報量の多いWebGL系の情報サイトを見てみると業務系のシステムの採用例が散見され、ゲームを嗜んでいるユーザ以外にも3D関連の技術は身近になりつつあると私は考えています。将来、3Dを使用した商品プロモーション等のコンテンツやUIにWebGL関連の技術がどんどん採用され今までにないUXをユーザに提供出来るような世の中になれば3Dプログラミングがある程度出来る私やWebGLが好きなエンジニアにとっては面白いかなと思っています。この記事を読んでWebGLに少しでも興味を持って頂けたのであれば幸いです。Labo採用ページツチノコブログ。