|
|
【Vocaloid初音ミクとMikuMikuDanceという驚愕のソフトウェア】 |
||
【リンクフリー】 私設研究所ネオテックラボ Neo-Tech-Lab.co.uk 【記載者】 私設研究所Neo-Tech-Lab 上田智章 |
|
|
ここにチェックボックス型外部コンテンツ・メニューが入ります。 | ||
|
|
【メニュー】 [index] ■メモ [PMD1] ●【VBA】ポリゴン・フィルとテクスチャー・マッピング [PMD2] ●【VBA】透視変換 [PMD3] ●【VBA】光源計算 [Sensor]★【NyARToolkitCS】拡張現実センサ【ソース公開】C# [PMD6] ■【NyARToolkitCS】MMDのPMDで拡張現実(モデル描画)C# [PMD4] ■【NyARToolkitCS】MMDのPMDで拡張現実(表情処理)C# [PMD5] ●IK bone制御 [Kinect]★【Kinect】デプスカメラを自作してみた【原理説明あり】 [Kinect]★【Kinect】Kinect for Windows SDK導入編【C#サンプルあり】 [Kinect]★【Kinect】OpenNI導入編【C#サンプルあり】 [TTS] ★【iSpeech APIの音声合成TTS】【ソース公開】JavaScript [TTS] ★『JavaScriptだけで音声合成エンジンμ-iVoiceを製作してみた』 |
|
【WebGLのページ】JavaScriptでリアルタイム3次元グラフィックスが楽しめる時代の到来までもうすぐです。現在、Google Chrome12、Mozilla FireFox5、及び開発版のSafari、Operaで使うことができます。 WebGLは、JavaScriptエンジンv8とDirectXを利用して高速化したOpenGLを融合して構成されたものです。 2011年5月に指摘されたセキュリティー問題はありますが、処理速度の高速性から利便性も高いので、将来的には普及するのではないでしょうか? ●WebGLとは? ●事前準備:利用できるウェブブラウザは? ●事前準備:FireFox5でWebGLが動作しない場合には? ●WebGLのサンプル ●WebGLのデモ ●クロスドメインテクスチャーを将来も利用できる方法 ●ローカルのPMDファイルを読み込んでJSON形式に変換し、3次元モデルを表示 ●物理エンジンBullet.jsのWebGLデモの紹介(Pl4n3氏のragdollデモの修正版)[btBoxShapeとbtCapsuleShape] 【MMD on WebGL】現時点で、edvakf氏のMMD on WebGLがHTML5+JavaScript(WebGL)で3次元モデル表示をモーション付きで実装されている最も優れたコードだと思います。PMD形式のモデルファイルとVMD形式のモーションファイルをバイナリで読み込み実行することができます。使い方も簡単です。1) MMDデモ1(背景の手前に表示) 2) MMDデモ2(Webカメラを同時に使う場合) 3) MMDデモ3(YouTube動画の上に表示する場合) 4) MMD.jsのソース(若干コメントを付与したもの。) |
【Canvasで3次元グラフィックス】NTL3D.jsを使えば、HTML5のCanvasを使って簡単に3次元グラフィックスを描画することができます。まずは、サンプルプログラムを実行してみてください。右のようなテクスチャーマッピングを表示します。JavaScriptで記述されていますのでブラウザの『ソースを表示』でソースを見ることができます。他の3次元グラフィックスと同様に、3次元モデルは頂点座標(X,Y,Z)とテクスチャーUV座標(U,V)からなる頂点リスト(Vertex)と、どの頂点番号でポリゴン(三角形)を構成するかを示す頂点番号インデックスリストで構成されており、Ball.jsにデータが記述されています。 NTL3D.jsは全てソフトウェアで描画を実行しているので、Canvasが利用可能なブラウザであれば利用することが可能です。Google Chrome, FireFox, IE11, Opera, Safariだけでなく、XP, VistaのIE9でも表示することが可能です。 CQ出版株式会社インターフェース2013年9月号の記事『NTL3D.js:Canvasで3次元グラフィックス』の筆者個人サイト内サポートページに飛びます。 |
【サンプルプログラム】/Canvas/NTL3D_TextureMapping3.htmの実行結果 【サンプルプログラム】『回転するピラミッド』/Canvas/NTL3D_Pyramid.htm 【今後の予定】亀足で、透視変換、光源計算、ボーン制御等を盛り込んでいく予定です。 |
【μ-iVoice】『JavaScript版 Web音声合成(シンセサイザ/ボーカロイド機能付)API』 |
|
JavaScriptだけで実現したNeo-Tech-Lab特製の音声合成エンジンAPIです。 本来ハードウェア向けのDirect Digital Synthesizer方式を採用しています。 シンセサイザやボーカロイド風歌唱も可能です。ピアノロールではなく、テキスト読み上げ方式(Text-To-Speech)です。文字数の制約はありません。⇒【Version0.09C】 漢字⇒かな変換辞書、抑揚制御スクリプトも装備しています。通常はテキスト入力して再生ボタンをクリックするだけです。ただ、漢字辞書はまだあまり充実していないので、全角文字で、ひらがなとカタカナを使って入力してください。 モノラル, 16bit, 22.05kHzで0.5秒スパン135音の音データに基づいて、任意話者での発声を実現しています。(自分の声はいくらエディットしてもなんか癖を感じ、やっぱりキモイのでアップしませんが。)但し、ソースは子音等の扱いに関して処理をはしょったレンダリング速度最優先の音質劣化バージョンとさせていただいています。是非、本家Ⅱのレンダリング速度とJavaScript DDS方式を比べてみて下さい。 【対象ブラウザ】 Google Chrome, Mozilla FireFox, Apple Safari ●『なんちゃってミク』NTL版Text-To-Speech API [JavaScript Ver.0.06] ちょっとロボティックな『なんちゃってミク』声での短い挨拶テスト ●『なんちゃってミク』Ieavan Polkka [JavaScript Ver.0.06] ブラウザで波形生成(rendering)を行うので音が出るまでに10~30秒を要します。 気長にお待ちください。 (スタンダード・ドラム・セット付) ●テキスト入力で音声合成できるμ-iVoice体験版Ver.0.09Cを公開中です。⇒ |
【体験版デモページ】Version0.09CJavaScriptなので『ソースを表示』でソースを閲覧できます。初回のアクセスは少しお待ちいただく必要があります。 スタートまでの時間がかかるのは、90秒分のメッセージと2分21秒分のシンセサイザー演奏デモのレンダリングを行っているためです。デモの初期化部分を外せば短時間で立ち上がります。 ■【sites.google.com】【埋め込みμ-iVoice】 ■【web.fc2.com】【μ-iVoice】 ■【geocities.jp】【μ-iVoice】 |
■MMD(MikuMikuDance)のモデル・ビュワー 1) 初音ミク用Excel VBA 2) 亞北ネル用Excel VBA 3) 鏡音リン用Excel VBA 4) 弱音ハク用Excel VBA 5) 咲音メイコ用Excel VBA 6) 鏡音レン用Excel VBA 7) カイト用Excel VBA 【Bone ,IK Boneに関して】■Excel VBAのソース内にこのソースでは記述していたものの使用していなかった部分ですが、ミスを発見しました。Visual C#のソースになりますが、『【NyARToolkitCS】MMDのPMDで拡張現実(表情処理)』に記載しました。ご参考まで。要点はBoneブロック内にIK接続情報(short型)があったこと、IK Boneブロック内にIK_chain_lengthが0のときは配列IK_child_bone_indexは存在しないことの2点でした。詳しくはソースをご覧ください。 【バグ修正のお知らせ】■バグを発見したので、NTL_Lib3DCG_ver048.zipをお使い下さい。詳しくはメモを書きましたのでこちらをご覧ください。 |
■■■記載日2009年9月29日■■■【MikuMikuDanceのモデル(PMD)をExcel VBAで表示するぞ!】Google O3Dプラグインを用いてWeb上で初音ミクを表示させ、喋らせてみようと大それた事を考えている。勿論、現時点でO3Dは3Dグラフィックスのみでオーディオ出力はできない (2011年7月現在、WebGLが利用可能なブラウザが増えてきたので、O3Dをやめて、WebGLに変更。音声合成も当時は知らなかったBase64エンコーディングという方法を見出したので、JavaScriptベースのDirect Digital Synthesizer方式に決定しました。上欄に途中結果を示しています。) そこでそのための一歩として、MikuMikuDanceのモデルデータ(PMD形式)の移植を行ってみようと考えた。 しかし、PMDデータを1から解析してO3Dで利用できる書式に変更するのは大変だ。そこで、偶然、他の事を検索していて見つけた『通りすがりの記憶』を参考にさせていただいた。いやぁ、このページが存在しなければ、私の勝手な思い込みのため決してデータの抽出はできなかっただろう。感謝。感謝。(^_^;) 左側に表示しているのはPMDから抽出した咲音メイコの形状データをワイヤフレーム表示や3次元グラフィックスで表示したものだ。以前に作ったことのある3次元グラフィックス・ライブラリを大幅改訂して、できる限りDirectXとMMD(MikuMikuDance)の構造体をそのまま利用できる形態のライブラリをMicrosoft社のExcel VBA(Visual Basic for Application)で製作した。 え?DirectXをどうして使わないのかって? 確かにExcel VBAだとハードウェアの動作速度の1/100以下の速度しか出ないだろうし、リアルタイム性は全くない。でもアルゴリズムが丸見えなのだ。 Excel Sheetなら手動でもデータの書き換えが簡単だし、将来的にFPGAで組み込みマイコン向けに3次元グラフィック・アクセラレータを設計するためのアルゴリズム評価を行うことができる。 (まぁ、そんなのは言いわけだ。えぇ、そうですよ。DirectXが使えないだけなんだよ! orz....) でも、O3DもMikuMikuDanceも描画段階ではDirectXを使用しているので、できるだけDirectXのデータ構造に近い記述を試みてみた。 【メニュー】 ■MikuMikuDanceのフォルダとファイル ■PMD形式ファイルのデータ構造 ■PMDデータをExcel Sheetへ読出す ■Excelでも行える3次元グラフィックス表示 ■3次元グラフィックス・ライブラリ[Lib_3DGraphic.bas] 【今後の予定】 MMD(MikuMikuDance)のモデルで実際に3次元グラフィックスを見ながら確認できるようになったのでアルゴリズムを詰めていきたい。遠大な計画になりそう。大体こんな感じかな? 透視変換 ⇒ 光源計算(平行光源) ⇒ PMDで拡張現実 ⇒ 表情 ⇒ Bone ⇒ IK Bone ⇒ (透視変換まで完了 [2009/10/2]) (光源計算まで完了 [2009/10/3]) (Altera社のFPGAで超高速グラフィック・アクセラレータを新規に設計して動かすのも面白いかも。) 【注意】 1) 左のビュワーには元データである.pmdやテクスチャー.bmp等は添付していません。 プログラムでは'C:\MyWeb\MMD\'フォルダ内にデータが存在することを前提にしています。 2) 現時点で、テクスチャーデータは実際のデータをペイント等を使って上下を反転させたものを使う必要があります。 3) 左Excel VBAでソースが閲覧できます。Win32API.basは使っていませんので、削除してOkです。 |
【NyARToolkitCSを使って拡張現実】 |
|
|
|
【追記】MikuMikuDanceのPMDファイルを直接読み込んでNyARToolkitCSによる拡張現実を体験するプログラムを製作中です。ソース公開中です。 標準モデルの『Sphere Mapping』には対応しましたが、テクスチャとの合成やspa等の仕様には未対応です。 表情処理の実装確認終わりました。テスト動画やプロジェクトファイルも公開中です。 現在はボーン処理と温度センサのデモ・プログラムをカメ足製作中です。でもなかなかうまく行きませんね.......。 |
図1 MikuMikuDance_vxxxフォルダ 図2 Dataフォルダ内 図3 UserFileフォルダ内 |
【MMD(MikuMikuDance)のフォルダとファイル】MMD(MikuMikuDance)をダウンロードすると、図1に示すようにMikuMikuDance_vxxx(xxxにはversion番号が入る。)というフォルダが作られ、その下にトゥーンtoonxx.bmp(xxには数字が入る)ファイルが格納されたDataフォルダと、UserFileというフォルダが作成される。 UserFileフォルダ内にはさらに幾つかのサブフォルダが作られている。 図2に示すように、Dataフォルダ内にはtoonxx.bmpのほか、メニューで使うアイコンなどの共通データが格納されている。 図3に示すように、UserFileフォルダ内にはDirectXフォーマットで製作されたアクセサリを格納するAccessoryフォルダと、背景にする壁紙を入れるBackGroundフォルダ、PMDデータ形式で記述されたMMDモデルデータと眼等のテクスチャーファイルが格納されるModelフォルダ、モーションデータが格納されるMotionフォルダ、手の形やちょっとしたポーズを格納するPoseフォルダ、Vocaloidのボーカルデータ(.vsq形式)が格納されるvsqフォルダ、音楽データ(.wav形式)が格納されるWaveフォルダがサブフォルダとして存在している。 図4に示すように、Modelフォルダ内には、モデルごとの定義データであるPMDデータ(.pmd形式)やダミーボーン、眼や咲音メイコのテクスチャーファイル、最近追加されたSphere Mappingで用いるsph形式ファイル(実はファイル構造はbmpファイルと同じ。)が格納されている。 このようにモデルの形状やデザインを決定しているファイルはDataフォルダとModelフォルダに記録されている。重要なのはいうまでもなく、PMDデータである。 図4 Modelフォルダ内 |
【PMD形式ファイルのデータ構造】PMDデータはMMD(MikuMikuDance)特有のデータ構造である。描画段階ではDirectXが使用されているが、光源計算、IK Bone、物理エンジンBulletの剛体/ジョイントデータ、Sphere Mappingなどの機能を扱い易く盛り込むために独自の工夫がなされたデータ構造となっている。 描画段階ではDirectXを使うので、3次元座標やベクトルを示すx_Vector型、テクスチャーマッピングを行うためのuv座標を示すx_Coords2d型、透過率を含めた物体色を示すx_ColorRGBA型、他の光源計算での反射率等を示すためのx_ColorRGB型、物体ごとの色を決定するために重要な材質(material)を示すx_material型についてはDirectXに準拠している。(厳密にはmaterial型については互換性はない。DirectXではmaterial型にテクスチャーファイルを示す項が付与される場合があるためだ。) 私はDirectXについて全く素人なので、MikuMikuDanceの標準添付アクセサリを素材としてそのデータ構造を調べてみた。 MikuMikuDanceに添付されているDirectXのデータはメモ帳で開くことができる。そうなのだ。テキスト・データなのだ。 取り敢えず、ステージデータ(stage01.x)をメモ帳で開いてみると、最初にデータ構造を記述するtemplateという部分が書かれている。 今回重要な部分だけを記載したが、座標変換用マトリックスや他の仕様もデータ構造がわかれば理解しやすい。 他の表示デバイスにモデルを移植するためにはPMD特有のデータ構造のうち太字の2つ型は特に重要だ。PMD_vertex型とPMD_material型はエッジ・ハイライティングやトゥーン、Bone操作に伴う変形率、光源計算などを行い易くするための検討がなされた独特のデータ構造を持っている。 PMDファイルのうちモデルの表示を行う上で重要なデータブロックは、PMD_Header型、PMD_VertexList型、PMD_FaceList型、PMD_MaterialList型の4つである。 PMD_Header型は、著作権を示すためのヘッダー部である。 PMD_VertexList型は、頂点データ(x,y,z)を格納するために用いられるDirectXのVertex Bufferに相等するが、法線ベクトル(nx,ny,nz)やテクスチャーマッピング(u,v)なども格納している。 PMD_FaceList型は、DirectXのIndex Bufferに相等する。MikuMikuDanceのモデルではMeshデータはすべて三角形で定義されており、各三角形(面)ごとの頂点番号を3個一組で順に記録している。 PMD_MaterialList型は、通常の材質(material)以外にトゥーン番号やテクスチャーマッピングを行う場合の参照ファイル名等の情報を持っている。 以下に、Microsoft社ExcelのVBA(Visual Basic for Application)での定義例を示す。(太字以外の部分は検証していないので注意が必要。) ここに簡単にポリゴン・フィルとテクスチャー・マッピングのアルゴリズムを示す。 |
' ************************************* ' *****【DirectX の 基本データ型】***** ' ************************************* ' DirectXで使用される基本データ型を定義します。本ビューワーで使うのは以下の5つのタイプです。 ' 1) x_Vectorは3次元の頂点座標やベクトルを定義するために使います。 ' 2) x_Coords2dは主としてテクスチャーマッピングで使うuv座標を定義するために使います。 ' 3) x_ColorRGBAは物体色を定義するために使います。R,G,B,A共に範囲は0.0~1.0です。A(alpha)は透過率を示します。 ' 4) x_ColorRGBは鏡面反射係数や散乱光係数を定義するために用います。R,G,B共に範囲は0.0~1.0です。 ' 5) x_materialは物体の光源計算に必要な物体色、鏡面反射係数、反射強度、散乱光係数を定義する材質を示します。 Public Type x_Vector '【頂点座標、ベクトル】 x As Single ' x座標(単精度浮動小数点形式4Bytes) y As Single ' y座標(単精度浮動小数点形式4Bytes) z As Single ' z座標(単精度浮動小数点形式4Bytes) End Type Public Type x_Coords2d '【テクスチャーマッピング用UV座標】 u As Single ' u座標(単精度浮動小数点形式4Bytes) v As Single ' v座標(単精度浮動小数点形式4Bytes) End Type Public Type x_ColorRGBA '【物体色】 Red As Single ' 赤(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Green As Single ' 緑(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Blue As Single ' 青(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Alpha As Single ' 透過率(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) End Type Public Type x_ColorRGB '【鏡面反射色、散乱光色】 Red As Single ' 赤(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Green As Single ' 緑(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Blue As Single ' 青(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) End Type Public Type x_Material '【材質定義】 FaceColor As x_ColorRGBA ' 物体色 Power As Single ' 反射強度(単精度浮動小数点形式4Bytes) SpecularColor As x_ColorRGB ' 鏡面反射色 EmissiveColor As x_ColorRGB ' 散乱光色 End Type '************************************************************************* '**********************【MikuMikuDance独自の構造体】********************** '************************************************************************* ' MikuMikuDanceで使われている独自の構造体をまとめました。 ' このプログラムでは最初の2タイプを使用しています。 ' なお、MikuMikuDance独自の構造体及び、PMDファイルの構造についての詳細はこちらのページ(通りすがりの記憶)のお世話になりました。 Public Type PMD_vertex '【PMD_頂点データ】 4*3+4*3+4*2+2*2+2 = 12+12+8+4+2 = 38bytes/頂点 pos As x_Vector '・【頂点座標】x,y,z normal As x_Vector '・【法線ベクトル】nx,ny,nz uv As x_Coords2d '・【uv座標】MMDは頂点uv(範囲0.0-1.0) ◆読込時に範囲u:0-(cg.Header.Nx-1),範囲v:0-(cg.Header.Ny-1)に変換する。 bone_num(1) As Integer '・【Bone番号】Bone番号1, Bone番号2 モデル変形(頂点移動)時に影響 bone_weight As Byte '・【Bone重み係数】Bone1に与える影響度 0-100 Bone2への影響度は(100-bone_weight)で与えられる。 edge_flag As Byte '・【エッジ・フラグ】0:通常、1:エッジ無効 輪郭線が有効の場合 End Type ' Public Type PMD_material '【PMD_材質データ】 material As x_Material '・【材質データ】DirectXの材質データ構造体と同じ toon_index As Byte '・【トゥーン・インデックス番号】toon??.bmp 0.bmp:0xFF, 1.bmp:0x00, ・・・10.bmp:0x09 edge_flag As Byte '・【エッジ・フラグ】輪郭、影 face_vert_count As Long '・【面頂点数】面数*3 = 面頂点数 実際のindexに直すには材質0から累積加算する。 texture_file_name As String * 20 '・【テクスチャ・ファイル名】20bytesギリギリまで使える 20bytes時は0x00がなくても可。' End Type Public Type PMD_bone '【PMD_Boneデータ】 bone_name As String * 20 '・【Bone名】Boneの名称 parent_bone_index As Integer '・【親Bone番号】(無い場合は0xFFFF) tail_pos_bone_index As Integer '・【tail位置のBone番号】(chain末端は0xFFFF) 親:子は1:多なので位置決め用 bone_type As Byte '・【Boneの種類】0:回転のみ 1:回転と移動 2:IK 3:不明 4:IK影響下 5:回転影響下 6:IK接続先 7:非表示 dummy As Integer '・【IKBone関連?】詳細不明 ↑注) Boneの種類(MMD 4.0~) 8:捻り 9:回転運動 bone_head_pos As x_Vector '・【Boneのヘッド座標】x,y,z End Type Public Type PMD_IK_data '【PMD_IK_data】 IK_bone_index As Integer ' IK Bone番号 IK_target_bone_index As Integer ' IKターゲットBone番号 IK Boneが最初に接続するBone IK_chain_length As Byte ' IKチェーンの長さ(子の数) Iterations As Integer ' 再帰演算回数 IK値1 Control_weight As Single ' IKの影響度 IK値2 Ik_child_bone_index() As Integer ' 配列サイズはIK_chain_length IK影響下のBone番号 End Type Public Type PMD_Skin_vert_data '【PMD_Skin_vert_data】 (type:base) | (type:base以外) Skin_vert_index As Long ' 表情用の頂点の番号(頂点リストにある番号) | 表情用の頂点の番号(baseの番号。skin_vert_index) Skin_vert_pos As x_Vector ' x,y,z 表情用頂点座標(頂点自体の座標) | x,y,z 表情用頂点の座標オフセット値(baseに対するオフセット) End Type Public Type PMD_Skin_data '【PMD_Skin_data】 Skin_name As String * 20 ' char skin_name[20] 表情名 Skin_vert_count As Long ' 表情用頂点数 Skin_type As Byte ' 表情の種類 0:base, 1:まゆ, 2:眼, 3:リップ, 4:その他 Skin_vert_data() As PMD_Skin_vert_data '配列サイズはSkin_vert_count 表情用の頂点データ(16bytes/頂点) End Type Public Type PMD_Bone_disp '【PMD_Bone_disp】 Bone_index As Integer 'WORD bone_index; // 枠用Bone番号 Bone_disp_frame_index As Byte 'BYTE bone_disp_frame_index; // 表示枠番号 End Type Public Type PMD_RigidBody '【PMD_RigidBody】 RigidBody_name As String * 20 ' 剛体名 // 頭 RigidBody_rel_bone_index As Integer ' 剛体関連ボーン番号 // 03 00 == 3 // 頭 RigidBody_group_index As Byte ' 剛体グループ番号 // 00 RigidBody_group_target As Integer ' 剛体グループ:対象 // 0xFFFFとの差 // 38 FE Shape_type As Byte ' 剛体形状:タイプ(0:球、1:箱、2:カプセル) // 00 // 球 Shape_w As Single ' 剛体形状:半径(幅) // CD CC CC 3F // 1.6 Shape_h As Single ' 剛体形状:高さ // CD CC CC 3D // 0.1 Shape_d As Single ' 剛体形状:奥行 // CD CC CC 3D // 0.1 Pos_pos As x_Vector ' 位置:位置(x, y, z) Pos_rot As x_Vector ' 位置:回転(rad(x), rad(y), rad(z)) RigidBody_weight As Single ' 剛体:質量 // 00 00 80 3F // 1.0 RigidBody_pos_dim As Single ' 剛体:移動減 // 00 00 00 00 RigidBody_rot_dim As Single ' 剛体:回転減 // 00 00 00 00 RigidBody_recoil As Single ' 剛体:反発力 // 00 00 00 00 RigidBody_friction As Single ' 剛体:摩擦力 // 00 00 00 00 RigidBody_type As Byte ' 剛体:タイプ(0:Bone追従、1:物理演算、2:物理演算(Bone位置合せ)) // 00 // Bone追従 End Type Public Type PMD_Joint '【t_joint】 Joint_name As String * 20 ' ジョイント名称 // 右髪1 Joint_rigidbody_a As Long ' ジョイント:剛体A Joint_rigidbody_b As Long ' ジョイント:剛体B Joint_pos As x_Vector ' ジョイント:位置(x, y, z) // 諸データ:位置合せでも設定可 Joint_rot As x_Vector ' ジョイント:回転(rad(x), rad(y), rad(z)) Constrain_pos_1 As x_Vector ' 制限:移動1(x, y, z) Constrain_pos_2 As x_Vector ' 制限:移動2(x, y, z) Constrain_rot_1 As x_Vector ' 制限:回転1(rad(x), rad(y), rad(z)) Constrain_rot_2 As x_Vector ' 制限:回転2(rad(x), rad(y), rad(z)) Spring_pos As x_Vector ' ばね:移動(x, y, z) Spring_rot As x_Vector ' ばね:回転(rad(x), rad(y), rad(z)) End Type '********************************************************************* '**********************【PMDファイルの構成要素】********************** '********************************************************************* ' 実際のPMDファイルの構造を示します。本プログラムでは太字部分の4つのブロックしか使っていません。 Public Type PMD_Header '【ヘッダー】 ID As String * 3 ' char magic[3]; // "Pmd" Version As Single ' float version[4]; // 0x00 0x00 0x80 0x3F == 1.00 ModelName As String * 20 ' char model_name[20]; // モデル名称 Comment As String * 256 ' char comment[256]; // コメント欄 End Type ' 注) 文字列:終端0x00 パディング0xFD 文字コード:shift JIS Public Type PMD_VertexList '【頂点リスト】一般にVertexリストと呼ばれています。 vert_count As Long ' DWORD vert_count; // 頂点数 vertex() As PMD_vertex ' PMD_vertex vertex[vert_count]; // 頂点データ(38bytes/頂点) End Type Public Type PMD_FaceList '【面リスト】MikuMikuDanceのモデルではtriangle(三角形)しか使っていません。 face_vert_count As Long ' DWORD face_vert_count; // 面数(三角形の数)*3 この配列の要素数 face_vert_index() As Integer ' WORD face_vert_index[face_vert_count]; // 頂点番号(3個/面) End Type ' 注)この配列のためにMMDでは最大65535頂点までのモデルしか取り扱えない。 Public Type PMD_MaterialList '【材質リスト】material material_count As Long ' DWORD material_count; // 材質数 material() As PMD_material ' t_material material[material_count]; // 材質データ(70Bytes/material) End Type Public Type PMD_BoneList '【Boneリスト】 bone_count As Integer ' WORD bone_count; // Bone数 Bone() As PMD_bone ' t_bone bone[bone_count]; // Boneデータ End Type Public Type PMD_IK_List '【IKリスト】 IK_data_count As Integer ' WORD ik_data_count; // IKデータ数 IK_data() As PMD_IK_data ' PMD_ik_data ik_data[ik_data_count]; // IKデータ (11 + 2*ik_chain_length)/IK End Type Public Type PMD_SkinList '【表情リスト】 Skin_count As Integer ' WORD skin_count; // 表情数 Skin_data() As PMD_Skin_data 't_skin_data skin_data[skin_count]; // 表情データ End Type Public Type PMD_SkinDispList '【表情枠用表示リスト】 Skin_dsip_count As Byte 'BYTE skin_disp_count; // 表情枠に表示する表情数 Skin_index() As Integer 'WORD skin_index[skin_disp_count]; // 表情番号 End Type Public Type PMD_BoneDispNameList '【Bone枠用枠名リスト】 Bone_disp_name_count As Byte 'BYTE bone_disp_name_count; // Bone枠用の枠名数 Disp_name As String * 50 'char disp_name[50][bone_disp_name_count]; // 枠名(50Bytes/枠) End Type Public Type PMD_BoneDispList '【Bone枠用表示リスト】 Bone_disp_count As Long 'DWORD bone_disp_count; // Bone枠に表示するBone数(枠0センターを除く全てのBoneの合計) Bone_disp() As PMD_Bone_disp ' bone_disp[bone_disp_count]; // 枠用Boneデータ(3Bytes/枠) End Type '注)bone_disp_countの部分は 'BYTE bone_disp_count + 0x0000(Bone0) + 0x00(枠0) 'のように見えますが、DWORDです。 '*BYTEにすると総数が合わない(0x000000をデータとしてカウントすると1足らない) '*Bone番号がWORDなので、WORD以上のサイズが必要 '*データの区切りの位置から判断すると、WORDにはならない。 '**********************【PMD拡張部分】********************* Public Type PMD_Header_eg '【英語メニュー表示拡張】 English_name_compatibility As Byte 'フラグ 01:英名対応あり Model_name As String * 20 '【英語ヘッダー】モデル名model_name_eg[20] Comment As String * 256 ' comment_eg[256]; // コメント(英語) Bone_name_eg() As String * 20 '【Boneリスト】char bone_name_eg[20][bone_count]; // Bone名(英名) Skin_name_eg() As String * 20 '【表情リスト】char skin_name_eg[20][skin_count-1]; // 表情名(英名) baseは英名が登録されないため Disp_name_eg() As String * 50 '【Bone枠用枠名リスト】char disp_name_eg[50][bone_disp_name_count]; // 枠名(英名) MMDでは区分名 Centerは英名は登録されない。 End Type '********************【トゥーンテクスチャ】******************** Public Type PMD_ToonTextureList '【トゥーンテクスチャリスト】(Toon指定) toon_filename(9) As String * 100 'トゥーンテクスチャファイル名 toon_file_name[100][10] End Type '********************【Bullet物理演算】******************** Public Type PMD_RigidBodyList '【物理演算_剛体リスト】 RigidBody_count As Long 'DWORD rigidbody_count; // 剛体数 // 2D 00 00 00 == 45 RigidBody() As PMD_RigidBody 't_rigidbody[rigidbody_count]; // 剛体データ(83Bytes/rigidbody) End Type Public Type PMD_JointList '【物理演算_ジョイントリスト】 0x0007 3111~0x0007 3E28(ファイル末尾) Joint_count As Long 'DWORD joint_count; // ジョイント数 // 1B 00 00 00 == 27 Joint() As PMD_Joint 't_joint[joint_count]; // ジョイントデータ(124Bytes/joint) End Type '【剛体について】 '【補足1】 'pos_rot[3]; // 位置:回転 '記録される値は、設定ボックスの値(度)をラジアンに変換した値(若干の誤差あり) '※1 記録される値 = 設定ボックスの値 * Pi / 180 '※2 PI == 3.1415920 '※3 有効桁数は8桁 '※4 設定ボックスに表示されていない桁も計算対象とするようです。(値をペーストした場合など) '※5 記録される値は2*PI(360度)で制限されません '【補足2】 'rigidbody_group_target; // 諸データ:グループ:対象 '・各値を(設定値-1)左シフトした後、ビットOR '・0xFFFFとの差を記録 '例: '設定ボックス 記録される値 '1 FE FF (0xFFFE == 0xFFFF - (1 << 0)) '16 FF 7F (0x7FFF == 0xFFFF - (1 << 15)) '1 2 FC FF (0xFFFC == 0xFFFF - (1 << 0) - (1 << 1)) '【補足3】 '0x0007 227A~ // 頭 '0x0007 22CD~ // 上半身右 '・・・ '【補足4】 'float 'CD CC CC 3D == 0.1 'CD CC 4C 3E == 0.2 'CD CC CC 3E == 0.4 'CD CC 4C 3F == 0.8 '00 00 80 3F == 1.0 'CD CC CC 3F == 1.6 '【ジョイントについて】 '【補足1】 'constrain_pos_1[3]; // 制限:移動1(x, y, z)、constrain_pos_2[3]; // 制限:移動2(x, y, z) '記録される順番に注意。 '設定ボックスの並びは、移動1x - 移動2x 移動1y - 移動2y 移動1z - 移動2z '記録される値の並びは、移動1x 移動1y 移動1z 移動2x 移動2y 移動2z '制限: 回転も同様。 |
【PMDデータをExcel Sheetへ読出す】前述の構造体の定義を行っていれば、PMDファイルからExcel Sheetへのモデル形状データの読み出しは容易だ。 ボタンをクリックしたときに読み出し処理を行う場合なら、例えば次のようにプログラムを記述することができる。 |
Private ss As String ' PMDデータ形式ファイル名 Private header As PMD_Header ' PMDデータファイルのヘッダー部 Private VertexList As PMD_VertexList ' PMDデータファイルの頂点データリスト Private FaceList As PMD_FaceList ' PMDデータファイルの面データリスト Private MaterialList As PMD_MaterialList ' PMDデータファイルの材質データリスト Private i As Long Private Sub CommandButton1_Click() ' ss = "C:\MyWeb\MMD\初音ミクVer2.pmd" ' ss = "C:\MyWeb\MMD\Haku_Yowane.pmd" ' ss = "C:\MyWeb\MMD\Meiko_Sakine.pmd" ss = "C:\MyWeb\MMD\Neru_Akita.pmd" '【読み出しPMDファイル名を指定する】 Sheet4.Cells(1, 2) = ss Open ss For Binary Access Read As #1 ' 【PMDファイルをバイナリモードで開く】 '【PMDヘッダー】 Get #1, , header ' 【PMDファイルからHeader型を読み込む】 Sheet4.Cells(3, 3) = header.ID ' "Pmd"と書かれている Sheet4.Cells(4, 3) = header.Version ' バージョン番号が1.00のように単精度浮動小数点形式で記述されている。 Sheet4.Cells(5, 3) = header.ModelName ' モデル名称 Sheet4.Cells(6, 3) = header.Comment ' 著作権に関する情報が書かれている。 Sheet4.Cells(6, 3).WrapText = False '【PMD頂点リスト】 Get #1, , VertexList.vert_count ' 【PMDファイルから頂点データの総数を得る】 ReDim VertexList.vertex(VertexList.vert_count - 1) ' 【読込に必要な配列領域を確保する】 Sheet4.Cells(9, 2) = VertexList.vert_count For i = 0 To VertexList.vert_count - 1 ' 【1頂点ずつデータを読み込む】一括して読み込むとエラーになるので要素ごとに分割読込 Get #1, , VertexList.vertex(i).pos.x ' ■頂点のx,y,z座標 Get #1, , VertexList.vertex(i).pos.y Get #1, , VertexList.vertex(i).pos.z Get #1, , VertexList.vertex(i).normal.x ' ■法線ベクトル Get #1, , VertexList.vertex(i).normal.y Get #1, , VertexList.vertex(i).normal.z Get #1, , VertexList.vertex(i).uv.u ' ■テクスチャーマッピングのu,v座標 Get #1, , VertexList.vertex(i).uv.v Get #1, , VertexList.vertex(i).bone_num(0) ' ■どのBoneの支配下か Get #1, , VertexList.vertex(i).bone_num(1) Get #1, , VertexList.vertex(i).bone_weight Get #1, , VertexList.vertex(i).edge_flag ' ■エッジフラグ Sheet4.Cells(11 + i, 1) = i Sheet4.Cells(11 + i, 2) = VertexList.vertex(i).pos.x Sheet4.Cells(11 + i, 3) = VertexList.vertex(i).pos.y Sheet4.Cells(11 + i, 4) = VertexList.vertex(i).pos.z Sheet4.Cells(11 + i, 5) = VertexList.vertex(i).normal.x Sheet4.Cells(11 + i, 6) = VertexList.vertex(i).normal.y Sheet4.Cells(11 + i, 7) = VertexList.vertex(i).normal.z Sheet4.Cells(11 + i, 8) = VertexList.vertex(i).uv.u Sheet4.Cells(11 + i, 9) = VertexList.vertex(i).uv.v Sheet4.Cells(11 + i, 10) = VertexList.vertex(i).bone_num(0) Sheet4.Cells(11 + i, 11) = VertexList.vertex(i).bone_num(1) Sheet4.Cells(11 + i, 12) = VertexList.vertex(i).bone_weight Sheet4.Cells(11 + i, 13) = VertexList.vertex(i).edge_flag Next i '【PMD面リスト】 Get #1, , FaceList.face_vert_count ' 【面を構成する頂点ののべ総数】三角形なので面数×3になっている ReDim FaceList.face_vert_index(FaceList.face_vert_count - 1) ' 【読込に必要な配列領域を確保する】 Sheet6.Cells(2, 2) = FaceList.face_vert_count j = 0 For i = 0 To FaceList.face_vert_count - 1 Step 3 ' 【三角形単位に頂点インデックス番号を読込】 Get #1, , FaceList.face_vert_index(i) Get #1, , FaceList.face_vert_index(i + 1) Get #1, , FaceList.face_vert_index(i + 2) Sheet6.Cells(4 + j, 1) = j Sheet6.Cells(4 + j, 2) = FaceList.face_vert_index(i) Sheet6.Cells(4 + j, 3) = FaceList.face_vert_index(i + 1) Sheet6.Cells(4 + j, 4) = FaceList.face_vert_index(i + 2) j = j + 1 Next i '【材質リスト】 Get #1, , MaterialList.material_count ' 【登録材質総数を読み込む】 ReDim MaterialList.material(MaterialList.material_count - 1) ' 【読込に必要な配列領域を確保する】 Sheet7.Cells(2, 2) = MaterialList.material_count For i = 0 To MaterialList.material_count - 1 ' 【材質ごとに要素をまとめて読み込む】 Get #1, , MaterialList.material(i) Sheet7.Cells(4 + i, 1) = i Sheet7.Cells(4 + i, 2) = MaterialList.material(i).material.faceColor.Red Sheet7.Cells(4 + i, 3) = MaterialList.material(i).material.faceColor.Green Sheet7.Cells(4 + i, 4) = MaterialList.material(i).material.faceColor.Blue Sheet7.Cells(4 + i, 5) = MaterialList.material(i).material.faceColor.alpha Sheet7.Cells(4 + i, 6) = MaterialList.material(i).material.power Sheet7.Cells(4 + i, 7) = MaterialList.material(i).material.specularColor.Red Sheet7.Cells(4 + i, 8) = MaterialList.material(i).material.specularColor.Green Sheet7.Cells(4 + i, 9) = MaterialList.material(i).material.specularColor.Blue Sheet7.Cells(4 + i, 10) = MaterialList.material(i).material.emissiveColor.Red Sheet7.Cells(4 + i, 11) = MaterialList.material(i).material.emissiveColor.Green Sheet7.Cells(4 + i, 12) = MaterialList.material(i).material.emissiveColor.Blue Sheet7.Cells(4 + i, 13) = MaterialList.material(i).toon_index Sheet7.Cells(4 + i, 14) = MaterialList.material(i).edge_flag Sheet7.Cells(4 + i, 15) = MaterialList.material(i).face_vert_count Sheet7.Cells(4 + i, 16) = MaterialList.material(i).texture_file_name Next i Close #1 End Sub |
図5 Sheet4(ヘッダー部と頂点データリスト) 図6 Sheet6(面リスト) 図7 Sheet7(材質リスト) |
【Excelでも行える3次元グラフィックス表示】【VBAでの画像表示法】 VBAで画像を表示する方法の選択肢はそれほど多くない。 オリジナルActive Xコントロールを作って張り込む方法はあるが、それだとインストール作業が必要になる。他のパソコンですぐに利用できない場合があるし、何よりコントロールのバージョンが一致しなければならず面倒だ。 そこで標準実装されている機能だけを使う方法を検討した。 Microsoft社のExcelやPower PointのVBA(Visual Basic for Application)に標準実装されているActive Xコントロールの中でグラフィックスを表示するために利用できるものはImageコントロール(Forms.Image)しかない。 ImageコントロールにはPictureプロパティがあり、画像ファイルを読み込んだり、書き込んだりすることができる。 開発タブにある挿入ボタンをクリックすると、図8のようにExcelシート内に張り込めるActive Xコントロールが表示される。中央下にあるを選んで、シート上の矩形領域を選択すれば、図9のように、灰色の矩形領域が表示され、同時にデザインモードボタンの色が変わるはずだ。このとき4隅をドラッグして大きさを調整することができる。 デザインモードボタンが選択されているときにimageコントロールをマウスでクリックして選択してから、ボタンを押すと、プロパティー・ウィンドウが表示される。Pictureと書かれた枠の右側にある枠内をダブル・クリックすることで図10に示すようにimageコントロール内に画像ファイルを読み込むことができる。 Imageコントロールが読み込むことのできるファイル形式はbmp, jpg, gif, ico, cur, wmfである。 VBA (Visual Basic for Application)でImageコントロールを用いた画像ファイルの読み込み/書き込みの操作を行うには以下のようにする。 プログラムで読み込む場合にはLoadPicture関数を用いる。反対にファイルとして書き出す場合にはSavePictureを使う。但し、読み出しは様々なファイル形式に対応しているが、書き出せるのはbmp形式に限定される。 ■指定ファイルをImageコントロールに読み込む方法の例 Image1.Picture = LoadPicture("ファイル名.bmp") ■Imageコントロール内の画像データを指定ファイルに書き出す方法の例 SavePicture Image1.Picture, "ファイル名.bmp" 【実施例】 Private Sub CommandButton4_Click() Image4.Picture = LoadPicture("C:\MyWeb\MMD\Ahoge2.jpg") ' jpg形式ファイルをImage4に読込、表示する。 SavePicture Image4.Picture, "C:\MyWeb\MMD\Ahoge2.bmp" ' End Sub Private Sub CommandButton5_Click() Image4.Picture = LoadPicture("C:\MyWeb\MMD\eyeM2.bmp") ' bmp形式ファイルをImage4に読込、表示する。 End Sub 取り扱えるファイル形式の中では、ソフト的にbmp形式の取扱が最も容易だろう。特に、1画素当たりRGB24bit(1670万色表示)の書式が最も目的に適合している。 ImageコントロールにはPictureSizeModeというプロパティもあり、 ●fmPictureSizeModeClipモード:元画像と同倍率で表示し、枠からはみ出た分は表示されない ●fmPictureSizeModeStretchモード:Imageコントロールの縦、横のサイズに自動的に調整される ●fmPictureSizeModeZoomモード:枠の短い方の長さに合わせて表示する 3つの表示モードがある。 以上のように、1フレーム分のグラフィック描画処理をメモリ上で行い、完了後ファイル化してImageコントロールに読み込んで表示する方法をとることにした。これは実際のフレーム・メモリのダブル・バッファ(表示用と描画用を分けて持つ)方式に対応する。 【図8】Active Xコントロール 【図9】Imageコントロール 【図10】Imageコントロールのプロパティ 【bmpファイル形式について】 bmp形式ファイルと言ってもいろいろなパターンがあるが、3次元グラフィックスを表示することが目的なら1画素がRGB24bitの書式が最もふさわしいだろう。 RGB24bit形式のbmpファイルのヘッダー情報のフォーマットは次のようになっている。 Public Type RGB24bitBitMapHeader ' RGB24bitタイプのBitMapファイルのヘッダー B As Byte ' ファイル識別子 "B" M As Byte ' "M" FileLength As Long ' ファイルの長さ=ヘッダーサイズ(54バイト)+データサイズ Null1 As Long ' 0 HeaderSize As Long ' ヘッダー領域のサイズ(54バイト) Offset As Long ' 画素データまでのオフセットサイズ(40バイト) Nx As Long ' x方向画素数 Ny As Long ' y方向画素数 NumberOfPlanes As Integer ' プレーンの数(1プレーン) BitsOfPixel As Integer ' 1画素を構成するビット数 (24ビット) Null2 As Long ' 0 SizeOfData As Long ' 画素領域のバイト・サイズ Null3 As Long ' Null4 As Long ' Null5 As Long ' 0 Null6 As Long ' 0 End Type 上から順に説明すると、 ●最初の2バイト(B, M)はファイル識別子であり、アスキー・コードで"B"、"M"と書かれている。 ●次の4バイトFileLengthはファイルの総バイト数である。下の例では0x000CC44A=836682バイトである。 ●次の4バイトはnull(意味がない隙間)である。 ●次の4バイトHeaderSizeはヘッダー情報のバイト数を示している。下の例は0x36=54バイトである。 ●次の4バイトOffsetは画像データ領域までのオフセット値を示す。この情報を含めて40バイトである。 ●次の4バイトNxはx方向の画素数を示す。例では0x00000219=537画素である。 ●次の4バイトNyはy方向の画素数を示す。例では0x00000207=519画素である。 ●次の2バイトNumberOfPlanesはフレーム・メモリの何画面分(プレーン数)を持っているかを示す。例は1である。 ●次の2バイトBitsOfPixelは1画素を構成するビット数を示す。例では24である。 以上がヘッダー情報部分の概略である。 【図11】ヘッダー情報部分 RGB24bit形式のbmpファイルの場合、画像データ部分は次のようになっている。 簡単のため、横7画素、縦3画素とすれば、 BGRBGRBGRBGRBGRBGRBGR* BGRBGRBGRBGRBGRBGRBGR* BGRBGRBGRBGRBGRBGRBGR* と並んでいる。ここでスキャンラインの最後尾に付いている*はスキャンライン1本分のデータ長を必ず4の倍数にしなければならないのでワード境界を揃えるために必要なバイトだ。これは画像の横幅画素数が4の倍数になっている場合には必要ない。 この『ワード境界問題』と『生データの並び順(B,G,R)』さえ忘れなければ、VBA(Visual Basic for Application)は2次元配列で簡単にアクセスすることが可能だ。 Public Type NTL_ColorRGB ' 画素データの構造(RGB24bitタイプ) B As Byte ' 青(0~255) G As Byte ' 緑(0~255) R As Byte ' 赤(0~255) End Type と宣言しておいて、 Dim PixcelBuffer() As NTL_ColorRGB Nx=7: Ny=3 Redim PixcelBuffer(Nx-1, Ny-1) とすれば2次元配列で画素単位のアクセスが可能になる。 |
■MikuMikuDanceのモデルデータ 1) 初音ミク用Excel VBA 2) 亞北ネル用Excel VBA 3) 鏡音リン用Excel VBA 4) 弱音ハク用Excel VBA 5) 咲音メイコ用Excel VBA |
■■■記載日2009年9月27日■■■【3次元グラフィックス・ライブラリ】[Lib_3DGraphic.bas] まだ、いろいろとできていないが、PMDデータをExcel VBAでSheetに読み込んで全てソフトウェアで3次元グラフィックス表示を行うビュワーの開発を開始。今現在の結果を示す。 DirectXやWin32APIも一切使わず、VBAだけでRGB24bitのbmpファイルを作成し、Imageオブジェクトに表示する方式をとっている。 ポリゴン・フィルのバグ取り後をした後でテクスチャーマッピングまで実装しています。この後の予定としては透視変換、表情(skin)を実装し、Boneにトライする予定。 【備考欄】2009/10/02 透視変換まで実装完了しました。 |
■■■記載日2009年9月30日■■■ 【Excel VBAでMMDモデルを表示】 Lib_3DGraphic.basをコーディング・デバッグに約14時間程かけて作った。なので、まだ透視変換も光源計算(ライティング)も実装していないが、3次元陰面処理をかけてポリゴン・フィルやテクスチャーマッピングは実装済みだ。ちゃんとRGB24bit(1670万色)表示に対応しているので光源計算が付与されればそれなりに見れる画像が作れるようになると思う。 このライブラリを使えば、Excel VBAで表示するのは簡単だ。ソースの実例を示す。 |
Private MyPic As NTL2D_BitMapRGB ' RGB24bit形式のBITMAP構造体(Colorテーブルも含む) Private My3DCG As NTL3D_BitMapRGB ' RGB24bit形式のBITMAP構造体(Colorテーブルも含む) Private s As String ' BITMAPファイル名称を格納するための文字列型変数 Private ss As String ' PMDデータ形式ファイル名 Private Header As PMD_Header ' PMDデータファイルのヘッダー部 Private VertexList As PMD_VertexList ' PMDデータファイルの頂点データリスト Private FaceList As PMD_FaceList ' PMDデータファイルの面データリスト Private MaterialList As PMD_MaterialList ' PMDデータファイルの材質データリスト Private i As Long Private Sub CommandButton2_Click() Dim i As Double Const Dx As Long = 800 ' x方向イメージ画素数 Const Dy As Long = 800 ' y方向イメージ画素数 Const Ox_xy As Long = 265 ' xy方向描画時のx方向イメージ・オフセット265*5=1325 Const Ox_zy As Long = 600 ' zy方向描画時のx方向イメージ・オフセット600*5=3000 Const Oy As Long = 2 ' 描画時のy方向イメージ・オフセット Const K As Single = 32 ' 描画倍率 32*5=160 Dim MColor As NTL_ColorRGB ' 描画時背景色 Dim P1 As NTL_ColorRGB, P2 As NTL_ColorRGB, P3 As NTL_ColorRGB Dim fP1 As x_ColorRGBA, fP2 As x_ColorRGBA '【2次元デモ/3次元テクスチャーマッピング用】 Dim uv1 As x_Coords2d, uv2 As x_Coords2d, uv3 As x_Coords2d '【3次元デモ用】 Dim pos1 As x_Vector, pos2 As x_Vector, pos3 As x_Vector '【頂点データ読込】 VertexList.vert_count = Sheet4.Cells(9, 2) ReDim VertexList.vertex(VertexList.vert_count - 1) For i = 0 To VertexList.vert_count - 1 VertexList.vertex(i).pos.x = Sheet4.Cells(11 + i, 2) VertexList.vertex(i).pos.y = Sheet4.Cells(11 + i, 3) VertexList.vertex(i).pos.z = Sheet4.Cells(11 + i, 4) VertexList.vertex(i).normal.x = Sheet4.Cells(11 + i, 5) VertexList.vertex(i).normal.y = Sheet4.Cells(11 + i, 6) VertexList.vertex(i).normal.z = Sheet4.Cells(11 + i, 7) VertexList.vertex(i).uv.u = Sheet4.Cells(11 + i, 8) VertexList.vertex(i).uv.v = Sheet4.Cells(11 + i, 9) VertexList.vertex(i).bone_num(0) = Sheet4.Cells(11 + i, 10) VertexList.vertex(i).bone_num(1) = Sheet4.Cells(11 + i, 11) VertexList.vertex(i).bone_weight = Sheet4.Cells(11 + i, 12) VertexList.vertex(i).edge_flag = Sheet4.Cells(11 + i, 13) Next i '【面データ読込】 FaceList.face_vert_count = Sheet6.Cells(2, 2) ReDim FaceList.face_vert_index(FaceList.face_vert_count - 1) j = 0 For i = 0 To FaceList.face_vert_count - 1 Step 3 FaceList.face_vert_index(i) = Sheet6.Cells(4 + j, 2) FaceList.face_vert_index(i + 1) = Sheet6.Cells(4 + j, 3) FaceList.face_vert_index(i + 2) = Sheet6.Cells(4 + j, 4) j = j + 1 Next i '【材質データ読込】 MaterialList.material_count = Sheet7.Cells(2, 2) ReDim MaterialList.material(MaterialList.material_count - 1) For i = 0 To MaterialList.material_count - 1 MaterialList.material(i).material.FaceColor.Red = Sheet7.Cells(4 + i, 2) MaterialList.material(i).material.FaceColor.Green = Sheet7.Cells(4 + i, 3) MaterialList.material(i).material.FaceColor.Blue = Sheet7.Cells(4 + i, 4) MaterialList.material(i).material.FaceColor.Alpha = Sheet7.Cells(4 + i, 5) MaterialList.material(i).material.Power = Sheet7.Cells(4 + i, 6) MaterialList.material(i).material.SpecularColor.Red = Sheet7.Cells(4 + i, 7) MaterialList.material(i).material.SpecularColor.Green = Sheet7.Cells(4 + i, 8) MaterialList.material(i).material.SpecularColor.Blue = Sheet7.Cells(4 + i, 9) MaterialList.material(i).material.EmissiveColor.Red = Sheet7.Cells(4 + i, 10) MaterialList.material(i).material.EmissiveColor.Green = Sheet7.Cells(4 + i, 11) MaterialList.material(i).material.EmissiveColor.Blue = Sheet7.Cells(4 + i, 12) MaterialList.material(i).toon_index = Sheet7.Cells(4 + i, 13) MaterialList.material(i).edge_flag = Sheet7.Cells(4 + i, 14) MaterialList.material(i).face_vert_count = Sheet7.Cells(4 + i, 15) MaterialList.material(i).texture_file_name = Sheet7.Cells(4 + i, 16) Next i ' *****【データの読み込み処理】ここまで *********************************** ' *********************************************************************** ' *****【3次元グラフィックス・モデル表示処理】ここから ' *********************************************************************** Eye$ = "C:\MyWeb\MMD\eye3Ne.bmp" ' 亞北ネルの眼のテクスチャー TEX% = 13 ' テクスチャーを張り付ける材質番号 BmpFileName$ = "\RinKagamine_800x800.bmp" ' 3次元グラフィックス出力ファイル '【テクスチャー・マッピング・ファイルを読み込む】眼のデータ NTL2D_GetBitMapFile MyPic, Eye$ '【3次元フレームメモリを確保】 NTL3D_BuildBitMap Dx, Dy, My3DCG ' 横Dx画素、縦Dy画素のbmp形式オブジェクト・データMy3DCGを作成。 MColor.R = 40: MColor.G = 200: MColor.B = 90 ' 背景色R=40 G=200 B=90 NTL3D_FillBitMapImage My3DCG, MColor ' 画面全体を背景色で塗りつぶす。 '【フレーム枠を描画する】 pos1.x = 0: pos1.y = 0: pos1.z = -100: pos2.x = Dx - 1: pos2.y = 0: pos2.z = -100 NTL3D_DrawLineConstant My3DCG, pos1, pos2, My3DCG.BasicColor.Red ' MyPicの枠を黒色で描画する。 pos1.x = Dx - 1: pos1.y = 0: pos1.z = -100: pos2.x = Dx - 1: pos2.y = Dy - 1: pos2.z = -100 NTL3D_DrawLineConstant My3DCG, pos1, pos2, My3DCG.BasicColor.Red ' MyPicの枠を黒色で描画する。 pos1.x = Dx - 1: pos1.y = Dy - 1: pos1.z = -100: pos2.x = 0: pos2.y = Dy - 1: pos2.z = -100 NTL3D_DrawLineConstant My3DCG, pos1, pos2, My3DCG.BasicColor.Red ' MyPicの枠を黒色で描画する。 pos1.x = 0: pos1.y = Dy - 1: pos1.z = -100: pos2.x = 0: pos2.y = 0: pos2.z = -100 NTL3D_DrawLineConstant My3DCG, pos1, pos2, My3DCG.BasicColor.Red ' MyPicの枠を黒色で描画する。 '【xy平面から見た初音ミク】 ' xy平面から見た初音ミクを横オフセットOx_xy、縦オフセットOy、倍率はK倍で描画する。 CP% = 0 CC% = 0 For i = 0 To FaceList.face_vert_count - 1 Step 3 ' MMDではポリゴンは三角形単位 pos1.x = CLng(K * VertexList.vertex(FaceList.face_vert_index(i)).pos.x) + Ox_xy pos1.y = CLng(K * VertexList.vertex(FaceList.face_vert_index(i)).pos.y) + Oy pos1.z = CLng(K * VertexList.vertex(FaceList.face_vert_index(i)).pos.z) pos2.x = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 1)).pos.x) + Ox_xy pos2.y = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 1)).pos.y) + Oy pos2.z = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 1)).pos.z) pos3.x = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 2)).pos.x) + Ox_xy pos3.y = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 2)).pos.y) + Oy pos3.z = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 2)).pos.z) If CC% <= 0 Then CC% = Sheet7.Cells(4 + CP%, 15) P1.R = 255 * Sheet7.Cells(4 + CP%, 2) P1.G = 255 * Sheet7.Cells(4 + CP%, 3) P1.B = 255 * Sheet7.Cells(4 + CP%, 4) CP% = CP% + 1 End If CC% = CC% - 3 If CP% = TEX% Then uv1.u = (MyTex.Header.Nx - 1) * VertexList.vertex(FaceList.face_vert_index(i)).uv.u uv1.v = (MyTex.Header.Ny - 1) * VertexList.vertex(FaceList.face_vert_index(i)).uv.v uv2.u = (MyTex.Header.Nx - 1) * VertexList.vertex(FaceList.face_vert_index(i + 1)).uv.u uv2.v = (MyTex.Header.Ny - 1) * VertexList.vertex(FaceList.face_vert_index(i + 1)).uv.v uv3.u = (MyTex.Header.Nx - 1) * VertexList.vertex(FaceList.face_vert_index(i + 2)).uv.u uv3.v = (MyTex.Header.Ny - 1) * VertexList.vertex(FaceList.face_vert_index(i + 2)).uv.v NTL3D_TriangleWithTextureMapping My3DCG, MyPic, pos1, uv1, pos2, uv2, pos3, uv3 Else NTL3D_Triangle My3DCG, pos1, P1, pos2, P1, pos3, P1 End If DoEvents Next i ' zy平面から見た初音ミクを横オフセットOx_zy、縦オフセットOy、倍率はK倍で描画する。 CP% = 0 CC% = 0 For i = 0 To FaceList.face_vert_count - 1 Step 3 ' MMDではポリゴンは三角形単位 pos1.x = CLng(K * VertexList.vertex(FaceList.face_vert_index(i)).pos.z) + Ox_zy pos1.y = CLng(K * VertexList.vertex(FaceList.face_vert_index(i)).pos.y) + Oy pos1.z = -CLng(K * VertexList.vertex(FaceList.face_vert_index(i)).pos.x) pos2.x = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 1)).pos.z) + Ox_zy pos2.y = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 1)).pos.y) + Oy pos2.z = -CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 1)).pos.x) pos3.x = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 2)).pos.z) + Ox_zy pos3.y = CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 2)).pos.y) + Oy pos3.z = -CLng(K * VertexList.vertex(FaceList.face_vert_index(i + 2)).pos.x) If CC% <= 0 Then CC% = Sheet7.Cells(4 + CP%, 15) P1.R = 255 * Sheet7.Cells(4 + CP%, 2) P1.G = 255 * Sheet7.Cells(4 + CP%, 3) P1.B = 255 * Sheet7.Cells(4 + CP%, 4) CP% = CP% + 1 End If CC% = CC% - 3 If CP% = TEX% Then uv1.u = (MyTex.Header.Nx - 1) * VertexList.vertex(FaceList.face_vert_index(i)).uv.u uv1.v = (MyTex.Header.Ny - 1) * VertexList.vertex(FaceList.face_vert_index(i)).uv.v uv2.u = (MyTex.Header.Nx - 1) * VertexList.vertex(FaceList.face_vert_index(i + 1)).uv.u uv2.v = (MyTex.Header.Ny - 1) * VertexList.vertex(FaceList.face_vert_index(i + 1)).uv.v uv3.u = (MyTex.Header.Nx - 1) * VertexList.vertex(FaceList.face_vert_index(i + 2)).uv.u uv3.v = (MyTex.Header.Ny - 1) * VertexList.vertex(FaceList.face_vert_index(i + 2)).uv.v NTL3D_TriangleWithTextureMapping My3DCG, MyPic, pos1, uv1, pos2, uv2, pos3, uv3 Else NTL3D_Triangle My3DCG, pos1, P1, pos2, P1, pos3, P1 End If DoEvents Next i ' 描画を終了後、ファイル化し、ExcelのSheet内のimageオブジェクトに読込、表示する。 s = CurDir + BmpFileName$ NTL3D_CreateBitMapFile My3DCG, s ' 描画を終了したbmp形式オブジェクト・データMyPicをファイル名sとして作成する。 Image1.Picture = LoadPicture(s) ' bmp形式ファイルをImage1に読込、表示する。 End Sub |
【Lib_3DGraphic.bas】 |
' ******************************************************************************* ' *** 3D Computer Graphics Library (Microsoft Excel VBA) ' *** Version 0.47 (23th September, 2009) ' *** Copyright ☆Tomoaki Ueda☆ (Japan) ' *** [Neo-Tech-Lab Co., Ltd.] ' ***【使用許諾条件】 ' *** 1) 本プログラムは『私的利用』に限りお使いいただけるフリーウェアです。 ' *** 従いまして、商用利用、法人でのご利用、販売はお断りいたします。 ' *** 2) このプログラムを用いて製作された画像は勿論自由にお使いいただけます。 ' *** 3) 作者は多忙のため本プログラムの技術サポートを行うことはありません。 ' *** バグ対応、個別の問合せに対する返答はいたしません。 ' *** 4) 本プログラムの利用による一切の責任はご利用者自身にあります。 ' *** 例え如何なる問題が生じても作者が責任を負うことはありません。 ' ******************************************************************************* '【仕様】 ' 本プログラムは、製作期間2~3日間程度で製作できる程度の簡易的3次元グラフィックス処理に限定して作成したプログラムです。 Microsoft社のExcel VBAで簡易3次元グラフィックス表示を行うにあたり、このライブラリでは以下の前提条件を適用しています。 ' 1) ポリゴンは三角形に限定。 ' 2) 物体色のみ利用。光源計算を行わない。 ' 3) 透視変換を行わない。 ' 4) 三角形の法線ベクトル方向による裏ポリゴンの非表示処理を行わない。 ' 5) クリッピング処理を行わない。 ' 6) カーニングを行わない。 ' つまり、物体色あるいはテクスチャーマッピングによる表示色で、zバッファ法での3次元陰面処理による三角形表示しか行いません。 ' ************************************* ' *****【DirectX の 基本データ型】***** ' ************************************* ' DirectXで使用される基本データ型を定義します。本ビューワーで使うのは以下の5つのタイプです。 ' 1) x_Vectorは3次元の頂点座標やベクトルを定義するために使います。 ' 2) x_Coords2dは主としてテクスチャーマッピングで使うuv座標を定義するために使います。 ' 3) x_ColorRGBAは物体色を定義するために使います。R,G,B,A共に範囲は0.0~1.0です。A(alpha)は透過率を示します。 ' 4) x_ColorRGBは鏡面反射係数や散乱光係数を定義するために用います。R,G,B共に範囲は0.0~1.0です。 ' 5) x_materialは物体の光源計算に必要な物体色、鏡面反射係数、反射強度、散乱光係数を定義する材質を示します。 Public Type x_Vector '【頂点座標、ベクトル】 x As Single ' x座標(単精度浮動小数点形式4Bytes) y As Single ' y座標(単精度浮動小数点形式4Bytes) z As Single ' z座標(単精度浮動小数点形式4Bytes) End Type Public Type x_Coords2d '【テクスチャーマッピング用UV座標】 u As Single ' u座標(単精度浮動小数点形式4Bytes) v As Single ' v座標(単精度浮動小数点形式4Bytes) End Type Public Type x_ColorRGBA '【物体色】 Red As Single ' 赤(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Green As Single ' 緑(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Blue As Single ' 青(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Alpha As Single ' 透過率(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) End Type Public Type x_ColorRGB '【鏡面反射色、散乱光色】 Red As Single ' 赤(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Green As Single ' 緑(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) Blue As Single ' 青(単精度浮動小数点形式4Bytes, 範囲0.00-1.00) End Type Public Type x_Material '【材質定義】 FaceColor As x_ColorRGBA ' 物体色 Power As Single ' 反射強度(単精度浮動小数点形式4Bytes) SpecularColor As x_ColorRGB ' 鏡面反射色 EmissiveColor As x_ColorRGB ' 散乱光色 End Type '************************************************************************* '********************【MikuMikuDanColore独自の構造体】******************** '************************************************************************* ' MikuMikuDanceで使われている独自の構造体をまとめました。 ' このプログラムでは最初の2タイプを使用しています。 ' なお、MikuMikuDance独自の構造体及び、PMDファイルの構造についての詳細はこちらのページ(通りすがりの記憶)のお世話になりました。 Public Type PMD_vertex '【PMD_頂点データ】 4*3+4*3+4*2+2*2+2 = 12+12+8+4+2 = 38bytes/頂点 pos As x_Vector '・【頂点座標】x,y,z normal As x_Vector '・【法線ベクトル】nx,ny,nz uv As x_Coords2d '・【uv座標】MMDは頂点uv(範囲0.0-1.0) ◆読込時に範囲u:0-(cg.Header.Nx-1),範囲v:0-(cg.Header.Ny-1)に変換する。 bone_num(1) As Integer '・【Bone番号】Bone番号1, Bone番号2 モデル変形(頂点移動)時に影響 bone_weight As Byte '・【Bone重み係数】Bone1に与える影響度 0-100 Bone2への影響度は(100-bone_weight)で与えられる。 edge_flag As Byte '・【エッジ・フラグ】0:通常、1:エッジ無効 輪郭線が有効の場合 End Type ' Public Type PMD_material '【PMD_材質データ】 material As x_Material '・【材質データ】DirectXの材質データ構造体と同じ toon_index As Byte '・【トゥーン・インデックス番号】toon??.bmp 0.bmp:0xFF, 1.bmp:0x00, ・・・10.bmp:0x09 edge_flag As Byte '・【エッジ・フラグ】輪郭、影 face_vert_count As Long '・【面頂点数】面数*3 = 面頂点数 実際のindexに直すには材質0から累積加算する。 texture_file_name As String * 20 '・【テクスチャ・ファイル名】20bytesギリギリまで使える 20bytes時は0x00がなくても可。' End Type Public Type PMD_bone '【PMD_Boneデータ】 bone_name As String * 20 '・【Bone名】Boneの名称 parent_bone_index As Integer '・【親Bone番号】(無い場合は0xFFFF) tail_pos_bone_index As Integer '・【tail位置のBone番号】(chain末端は0xFFFF) 親:子は1:多なので位置決め用 bone_type As Byte '・【Boneの種類】0:回転のみ 1:回転と移動 2:IK 3:不明 4:IK影響下 5:回転影響下 6:IK接続先 7:非表示 bone_head_pos As x_Vector '・【Boneのヘッド座標】x,y,z ↑注) Boneの種類(MMD 4.0~) 8:捻り 9:回転運動 End Type Public Type PMD_IK_data '【PMD_IK_data】 IK_bone_index As Integer ' IK Bone番号 IK_target_bone_index As Integer ' IKターゲットBone番号 IK Boneが最初に接続するBone IK_chain_length As Byte ' IKチェーンの長さ(子の数) Iterations As Integer ' 再帰演算回数 IK値1 Control_weight As Single ' IKの影響度 IK値2 Ik_child_bone_index() As Integer ' 配列サイズはIK_chain_length IK影響下のBone番号 End Type Public Type PMD_Skin_vert_data '【PMD_Skin_vert_data】 (type:base) | (type:base以外) Skin_vert_index As Long ' 表情用の頂点の番号(頂点リストにある番号) | 表情用の頂点の番号(baseの番号。skin_vert_index) Skin_vert_pos As x_Vector ' x,y,z 表情用頂点座標(頂点自体の座標) | x,y,z 表情用頂点の座標オフセット値(baseに対するオフセット) End Type Public Type PMD_Skin_data '【PMD_Skin_data】 Skin_name As String * 20 ' char skin_name[20] 表情名 Skin_vert_count As Long ' 表情用頂点数 Skin_type As Byte ' 表情の種類 0:base, 1:まゆ, 2:眼, 3:リップ, 4:その他 Skin_vert_data() As PMD_Skin_vert_data '配列サイズはSkin_vert_count 表情用の頂点データ(16bytes/頂点) End Type Public Type PMD_Bone_disp '【PMD_Bone_disp】 Bone_index As Integer 'WORD bone_index; // 枠用Bone番号 Bone_disp_frame_index As Byte 'BYTE bone_disp_frame_index; // 表示枠番号 End Type Public Type PMD_RigidBody '【PMD_RigidBody】 RigidBody_name As String * 20 ' 剛体名 // 頭 RigidBody_rel_bone_index As Integer ' 剛体関連ボーン番号 // 03 00 == 3 // 頭 RigidBody_group_index As Byte ' 剛体グループ番号 // 00 RigidBody_group_target As Integer ' 剛体グループ:対象 // 0xFFFFとの差 // 38 FE Shape_type As Byte ' 剛体形状:タイプ(0:球、1:箱、2:カプセル) // 00 // 球 Shape_w As Single ' 剛体形状:半径(幅) // CD CC CC 3F // 1.6 Shape_h As Single ' 剛体形状:高さ // CD CC CC 3D // 0.1 Shape_d As Single ' 剛体形状:奥行 // CD CC CC 3D // 0.1 Pos_pos As x_Vector ' 位置:位置(x, y, z) Pos_rot As x_Vector ' 位置:回転(rad(x), rad(y), rad(z)) RigidBody_weight As Single ' 剛体:質量 // 00 00 80 3F // 1.0 RigidBody_pos_dim As Single ' 剛体:移動減 // 00 00 00 00 RigidBody_rot_dim As Single ' 剛体:回転減 // 00 00 00 00 RigidBody_recoil As Single ' 剛体:反発力 // 00 00 00 00 RigidBody_friction As Single ' 剛体:摩擦力 // 00 00 00 00 RigidBody_type As Byte ' 剛体:タイプ(0:Bone追従、1:物理演算、2:物理演算(Bone位置合せ)) // 00 // Bone追従 End Type Public Type PMD_Joint '【t_joint】 Joint_name As String * 20 ' ジョイント名称 // 右髪1 Joint_rigidbody_a As Long ' ジョイント:剛体A Joint_rigidbody_b As Long ' ジョイント:剛体B Joint_pos As x_Vector ' ジョイント:位置(x, y, z) // 諸データ:位置合せでも設定可 Joint_rot As x_Vector ' ジョイント:回転(rad(x), rad(y), rad(z)) Constrain_pos_1 As x_Vector ' 制限:移動1(x, y, z) Constrain_pos_2 As x_Vector ' 制限:移動2(x, y, z) Constrain_rot_1 As x_Vector ' 制限:回転1(rad(x), rad(y), rad(z)) Constrain_rot_2 As x_Vector ' 制限:回転2(rad(x), rad(y), rad(z)) Spring_pos As x_Vector ' ばね:移動(x, y, z) Spring_rot As x_Vector ' ばね:回転(rad(x), rad(y), rad(z)) End Type '********************************************************************* '**********************【PMDファイルの構成要素】********************** '********************************************************************* ' 実際のPMDファイルの構造を示します。本プログラムでは太字部分の4つのブロックしか使っていません。 Public Type PMD_Header '【ヘッダー】 ID As String * 3 ' char magic[3]; // "Pmd" Version As Single ' float version[4]; // 0x00 0x00 0x80 0x3F == 1.00 ModelName As String * 20 ' char model_name[20]; // モデル名称 Comment As String * 256 ' char comment[256]; // コメント欄 End Type ' 注) 文字列:終端0x00 パディング0xFD 文字コード:shift JIS Public Type PMD_VertexList '【頂点リスト】一般にVertexリストと呼ばれています。 vert_count As Long ' DWORD vert_count; // 頂点数 vertex() As PMD_vertex ' PMD_vertex vertex[vert_count]; // 頂点データ(38bytes/頂点) End Type Public Type PMD_FaceList '【面リスト】MikuMikuDanceのモデルではtriangle(三角形)しか使っていません。 face_vert_count As Long ' DWORD face_vert_count; // 面数(三角形の数)*3 この配列の要素数 face_vert_index() As Integer ' WORD face_vert_index[face_vert_count]; // 頂点番号(3個/面) End Type ' 注)この配列のためにMMDでは最大65535頂点までのモデルしか取り扱えない。 Public Type PMD_MaterialList '【材質リスト】material material_count As Long ' DWORD material_count; // 材質数 material() As PMD_material ' t_material material[material_count]; // 材質データ(70Bytes/material) End Type Public Type PMD_BoneList '【Boneリスト】 bone_count As Integer ' WORD bone_count; // Bone数 Bone() As PMD_bone ' t_bone bone[bone_count]; // Boneデータ End Type Public Type PMD_IK_List '【IKリスト】 IK_data_count As Integer ' WORD ik_data_count; // IKデータ数 IK_data() As PMD_IK_data ' PMD_ik_data ik_data[ik_data_count]; // IKデータ (11 + 2*ik_chain_length)/IK End Type Public Type PMD_SkinList '【表情リスト】 Skin_count As Integer ' WORD skin_count; // 表情数 Skin_data() As PMD_Skin_data 't_skin_data skin_data[skin_count]; // 表情データ End Type Public Type PMD_SkinDispList '【表情枠用表示リスト】 Skin_dsip_count As Byte 'BYTE skin_disp_count; // 表情枠に表示する表情数 Skin_index() As Integer 'WORD skin_index[skin_disp_count]; // 表情番号 End Type Public Type PMD_BoneDispNameList '【Bone枠用枠名リスト】 Bone_disp_name_count As Byte 'BYTE bone_disp_name_count; // Bone枠用の枠名数 Disp_name As String * 50 'char disp_name[50][bone_disp_name_count]; // 枠名(50Bytes/枠) End Type Public Type PMD_BoneDispList '【Bone枠用表示リスト】 Bone_disp_count As Long 'DWORD bone_disp_count; // Bone枠に表示するBone数(枠0センターを除く全てのBoneの合計) Bone_disp() As PMD_Bone_disp ' bone_disp[bone_disp_count]; // 枠用Boneデータ(3Bytes/枠) End Type '注)bone_disp_countの部分は 'BYTE bone_disp_count + 0x0000(Bone0) + 0x00(枠0) 'のように見えますが、DWORDです。 '*BYTEにすると総数が合わない(0x000000をデータとしてカウントすると1足らない) '*Bone番号がWORDなので、WORD以上のサイズが必要 '*データの区切りの位置から判断すると、WORDにはならない。 '**********************【PMD拡張部分】********************* Public Type PMD_Header_eg '【英語メニュー表示拡張】 English_name_compatibility As Byte 'フラグ 01:英名対応あり Model_name As String * 20 '【英語ヘッダー】モデル名model_name_eg[20] Comment As String * 256 ' comment_eg[256]; // コメント(英語) Bone_name_eg() As String * 20 '【Boneリスト】char bone_name_eg[20][bone_count]; // Bone名(英名) Skin_name_eg() As String * 20 '【表情リスト】char skin_name_eg[20][skin_count-1]; // 表情名(英名) baseは英名が登録されないため Disp_name_eg() As String * 50 '【Bone枠用枠名リスト】char disp_name_eg[50][bone_disp_name_count]; // 枠名(英名) MMDでは区分名 Centerは英名は登録されない。 End Type '********************【トゥーンテクスチャ】******************** Public Type PMD_ToonTextureList '【トゥーンテクスチャリスト】(Toon指定) toon_filename(9) As String * 100 'トゥーンテクスチャファイル名 toon_file_name[100][10] End Type '********************【Bullet物理演算】******************** Public Type PMD_RigidBodyList '【物理演算_剛体リスト】 RigidBody_count As Long 'DWORD rigidbody_count; // 剛体数 // 2D 00 00 00 == 45 RigidBody() As PMD_RigidBody 't_rigidbody[rigidbody_count]; // 剛体データ(83Bytes/rigidbody) End Type Public Type PMD_JointList '【物理演算_ジョイントリスト】 0x0007 3111~0x0007 3E28(ファイル末尾) Joint_count As Long 'DWORD joint_count; // ジョイント数 // 1B 00 00 00 == 27 Joint() As PMD_Joint 't_joint[joint_count]; // ジョイントデータ(124Bytes/joint) End Type '【剛体について】 '【補足1】 'pos_rot[3]; // 位置:回転 '記録される値は、設定ボックスの値(度)をラジアンに変換した値(若干の誤差あり) '※1 記録される値 = 設定ボックスの値 * Pi / 180 '※2 PI == 3.1415920 '※3 有効桁数は8桁 '※4 設定ボックスに表示されていない桁も計算対象とするようです。(値をペーストした場合など) '※5 記録される値は2*PI(360度)で制限されません '【補足2】 'rigidbody_group_target; // 諸データ:グループ:対象 '・各値を(設定値-1)左シフトした後、ビットOR '・0xFFFFとの差を記録 '例: '設定ボックス 記録される値 '1 FE FF (0xFFFE == 0xFFFF - (1 << 0)) '16 FF 7F (0x7FFF == 0xFFFF - (1 << 15)) '1 2 FC FF (0xFFFC == 0xFFFF - (1 << 0) - (1 << 1)) '【補足3】 '0x0007 227A~ // 頭 '0x0007 22CD~ // 上半身右 '・・・ '【補足4】 'float 'CD CC CC 3D == 0.1 'CD CC 4C 3E == 0.2 'CD CC CC 3E == 0.4 'CD CC 4C 3F == 0.8 '00 00 80 3F == 1.0 'CD CC CC 3F == 1.6 '【ジョイントについて】 '【補足1】 'constrain_pos_1[3]; // 制限:移動1(x, y, z)、constrain_pos_2[3]; // 制限:移動2(x, y, z) '記録される順番に注意。 '設定ボックスの並びは、移動1x - 移動2x 移動1y - 移動2y 移動1z - 移動2z '記録される値の並びは、移動1x 移動1y 移動1z 移動2x 移動2y 移動2z '制限: 回転も同様。 ' *********************************************** ' *****【NTL3Dの3Dオブジェクト・データ型】***** ' *********************************************** ' 本プログラムで2次元及び3次元の描画処理に使用する構造体を定義しています。 ' 1) 1画素RGB24ビットのbmp形式ファイルの構造を利用して描画処理を行っています。 ' 2) 1画素3バイト単位のため、画像の横幅によって1スキャンライン毎にワード境界の問題が発生します。 ' 3) 描画処理の時に基本色が定義されていると色の設定が楽になることが多いのでBasicColorを定義しています。 ' 4) NTL_BitMapRGB_HeaderはWindowsで使用されているRGB24bitタイプのBitMapファイルのヘッダー部分の構造を示しています。 ' 5) 2次元描画のためにNTL2D_BitMapRGBを、3次元描画のためにNTL3D_BitMapRGBを用意しました。 ' 違いはzバッファの有無だけです。テクスチャーマッピングデータは2次元を使います。 Public Const NTL3D_Z_max As Single = 3.402823E+38 '【NTL単精度】zバッファで使用する最奥値です。 Public Type NTL_ColorRGB ' 画素データの構造(RGB24bitタイプ) B As Byte ' 青(0~255) G As Byte ' 緑(0~255) R As Byte ' 赤(0~255) End Type Public Type NTL_BasicColor ' オブジェクトを描画する際に用いる固定色 White As NTL_ColorRGB ' 白 255 255 255 Black As NTL_ColorRGB ' 黒 0 0 0 Red As NTL_ColorRGB ' 赤 255 0 0 Orange As NTL_ColorRGB ' オレンジ 255 128 0 Yellow As NTL_ColorRGB ' 黄 255 255 0 Green As NTL_ColorRGB ' 緑 0 255 0 Cyan As NTL_ColorRGB ' シアン 0 255 255 Blue As NTL_ColorRGB ' 青 0 0 255 Violet As NTL_ColorRGB ' 紫 255 0 128 Magenta As NTL_ColorRGB ' マゼンタ 255 0 255 Brown As NTL_ColorRGB ' 茶 128 0 0 DarkGray As NTL_ColorRGB ' 濃灰 50 50 50 Gray As NTL_ColorRGB ' 灰 128 128 128 LightGray As NTL_ColorRGB ' 淡灰 200 200 200 DarkGreen As NTL_ColorRGB ' 濃緑 0 128 0 End Type Public Type NTL_BitMapRGB_Header ' RGB24bitタイプのBitMapファイルのヘッダー ID As String * 2 ' ファイル識別子 "BM" FileLength As Long ' ファイルの長さ = ヘッダーサイズ (54バイト) + データサイズ( (x方向画素数×3に最も近い4の倍数)×(y方向画素数) ) Null1 As Long ' **ヌル領域** 0 HeaderSize As Long ' ヘッダー領域のサイズ (54バイト) Offset As Long ' 画素データまでのオフセットサイズ(40バイト) Nx As Long ' x方向画素数 Ny As Long ' y方向画素数 NumberOfPlanes As Integer ' プレーンの数 (1プレーン) BitsOfPixel As Integer ' 1画素を構成するビット数 (24ビット) Null2 As Long ' **ヌル領域** 0 SizeOfData As Long ' 画素領域のバイト・サイズ (x方向画素数×3に最も近い4の倍数)×(y方向画素数) Null3(3) As Long ' **ヌル領域** 0,0,0,0 End Type Public Type NTL2D_BitMapRGB ' ***** 2D描画/テクスチャーマッピング ***** Header As NTL_BitMapRGB_Header '【ヘッダー部】RGB24bitタイプのbmp(BitMap)形式ファイルのヘッダー部分 PixelBuffer() As NTL_ColorRGB '【画素バッファ】RGB画素バッファ領域 (注)ヘッダー+画素バッファでbmpファイルを構成 Nw As Long ' (x方向画素数×3に最も近い4の倍数) = (y方向に隣接する画素までのバイト距離) BasicColor As NTL_BasicColor '【基本色】固定色(白、黒、赤、オレンジ、黄、緑、シアン、青、紫、マゼンタ、茶、濃灰、灰、淡灰、濃緑) nColor As Long '【カラーインデックス】ColorLookupテーブルの登録色数 Color() As NTL_ColorRGB ' ColorLookupテーブルのデータ領域 End Type Public Type NTL3D_BitMapRGB ' ***** 3D描画/テクスチャーマッピング ***** Header As NTL_BitMapRGB_Header '【ヘッダー部】RGB24bitタイプのbmp(BitMap)形式ファイルのヘッダー部分 PixelBuffer() As NTL_ColorRGB '【画素バッファ】RGB画素バッファ領域 (注)ヘッダー+画素バッファでbmpファイルを構成 Z_buffer() As Single '【Zバッファ】Zバッファ(単精度浮動小数点形式4bytes/画素) Nw As Long ' (x方向画素数×3に最も近い4の倍数) = (y方向に隣接する画素までのバイト距離) BasicColor As NTL_BasicColor '【基本色】固定色(白、黒、赤、オレンジ、黄、緑、シアン、青、紫、マゼンタ、茶、濃灰、灰、淡灰、濃緑) nColor As Long '【カラーインデックス】ColorLookupテーブルの登録色数 Color() As NTL_ColorRGB ' ColorLookupテーブルのデータ領域 End Type '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% '%%% 内部ルーチン '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ' 以下の2つは内部で初期化に利用するルーチンです。 ' 1) Windowsの1画素RGB24bitのbmpファイル形式は1画素当たり3バイト単位なので、 ' 画像の横x方向サイズによってワード境界(4バイト単位)の問題が発生します。フ ' ァイル格納時に1スキャンライン分のデータ量を調べるためにNTL_GetNwを使用し ' ます。 ' 2) 本プログラムではbmp形式オブジェクトへの描画の際に使用する色はNTL_ColorRGB ' を使いますが、いちいち色を指定するのが面倒くさいので、予めオブジェクト内に ' 基本色を定義しておくようにしています。NTL_SetBasicColorはNTL2D_BitMapRGBや ' NTL3D_BitMapRGBのBasicColorパレットに基本色を設定するためのルーチンです。 '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% '%%% x方向画素数×3に最も近い4の倍数を求める。(word境界対応) '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Private Function NTL_GetNw(Nx As Long) As Long Dim i As Long, j As Long i = Nx * 3& j = i Mod 4& ' If j > 0 Then ' i = (i \ 4& + 1&) * 4& ' End If GetNw = i End Function '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% '%%% 2D/3D描画オブジェクト内の基本色を設定する '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Public Sub NTL_SetBasicColor(BC As NTL_BasicColor) With BC '【基本色】 色 R G B .White.R = 255 ' 白 255 255 255 .White.G = 255 ' .White.B = 255 ' .Black.R = 0 ' 黒 0 0 0 .Black.G = 0 ' .Black.B = 0 ' .Red.R = 255 ' 赤 255 0 0 .Red.G = 0 ' .Red.B = 0 ' .Yellow.R = 255 ' 黄 255 255 0 .Yellow.G = 255 ' .Yellow.B = 0 ' .Green.R = 0 ' 緑 0 255 0 .Green.G = 255 ' .Green.B = 0 ' .Cyan.R = 0 ' シアン 0 255 255 .Cyan.G = 255 ' .Cyan.B = 255 ' .Blue.R = 0 ' 青 0 0 255 .Blue.G = 0 ' .Blue.B = 255 ' .Magenta.R = 255 ' マゼンタ 255 0 255 .Magenta.G = 0 ' .Magenta.B = 255 ' .Orange.R = 255 ' オレンジ 255 128 0 .Orange.G = 128 ' .Orange.B = 0 ' .Violet.R = 128 ' 紫 128 0 255 .Violet.G = 0 ' .Violet.B = 128 ' .Brown.R = 128 ' 茶 128 0 0 .Brown.G = 0 ' .Brown.B = 0 ' .Gray.R = 128 ' 灰 128 128 128 .Gray.G = 128 ' .Gray.B = 128 ' .DarkGray.R = 50 ' 濃灰 50 50 50 .DarkGray.G = 50 ' .DarkGray.B = 50 ' .LightGray.R = 200 ' 淡灰 200 200 200 .LightGray.G = 200 ' .LightGray.B = 200 ' .DarkGreen.R = 0 ' 濃緑 0 128 0 .DarkGreen.G = 128 ' .DarkGreen.B = 0 ' End With End Sub '****************************************************** '********** '********** 2次元グラッフィックス用コマンド '********** '****************************************************** ' 本プログラムは3次元グラフィックスのためのライブラリですが、テクスチャーマッピング処理を行うために ' 2次元画像の取り扱いが必要なため、2次元グラフィックスも実装しています。点,線分,三角形の描画を行う ' ことができます。 '【2次元オブジェクトに対するコマンド】 ' 1) NTL2D_CreateBitMapRGB_Header ' 1画素当たりRGB24bit, 横Nx画素, 縦Ny画素のbmp形式ファイルのヘッダー情報を生成するために使います。 ' 2) NTL2D_GetBitMapFile ' 指定のRGB24bit形式のbmpファイルを読み込んで描画オブジェクトを生成します。BasicColor(基本色)パレット ' が初期化されます。描画オブジェクトとなることでテクスチャーマッピングを行うことや、追加で描画を行うこと ' ができるようになります。 ' 3) NTL2D_BuildBitMap ' 指定サイズの2次元描画オブジェクトを生成します。BasicColor(基本色)パレットが初期化され、PixcelBuffer ' (フレーム)は白色でクリアされます。 ' 4) NTL2D_FillBitMapImage ' 指定色でPixcelBufferをクリアします。NTL_ColorRGB形式で色の指定を行います。 ' 5) NTL2D_CreateBitMapFile ' 指定描画オブジェクトの内容を指定ファイル名で1画素RGB24bitのbmp形式ファイルに書き出します。 ' 6) NTL2D_InitializeColorLookupTable ' 描画オブジェクトにはBasicColor(基本色)パレットのほかにカラーインデックス方式の描画を行うために用意した ' Colorパレット[配列]があります。このコマンドは指定色数の配列領域を確保するために用います。このコマンドは ' 領域の確保だけで、色の設定は行いません。 ' 7) NTL2D_CreateColor ' Colorパレット配列に色を直線補間処理で設定するために用います。開始番号、開始色、終了番号、終了色を指定する ' ことで、指定2色間を補間したカラーパレットを作ることができます。 ' 8) NTL2D_CreateGrayScale ' 指定した階調数のグレースケールをカラーパレットに設定することができます。 ' 9) NTL2D_CreateDipoleScale ' シミュレーションなどで正負の値を赤青系で階調表現したいときに使うと便利なカラーパレット設定コマンドです。 ' 階調数を指定することができます。 ' 10) NTL2D_CreateMonopoleScale ' シミュレーションなどで絶対強度を階調表現したいときに使うと便利なカラーパレット設定コマンドです。 ' 階調数を指定することができます。 ' 11) MMD2D_DrawPixel ' 1画素単位に描画するコマンドです。 ' MikuMikuDanceではuv空間の座標範囲は0.0~1.0です。またRGB項は0.0~1.0の範囲で指定されているので、自動的に ' u座標を0~Nx-1に、v座標を0~Ny-1に、RGB項を0~255になるように変換して描画します。 ' 12) MMD2D_DrawLineConstant ' 指定uv座標2点間を結ぶ線分を指定単色で描画するコマンドです。 ' MikuMikuDanceではuv空間の座標範囲は0.0~1.0です。またRGB項は0.0~1.0の範囲で指定されているので、自動的に ' u座標を0~Nx-1に、v座標を0~Ny-1に、RGB項を0~255になるように変換して描画します。 ' 13) MMD2D_DrawLineShading ' 指定uv座標2点間を結ぶ線分を指定2色の直線補間をかけながら描画するコマンドです。 ' MikuMikuDanceではuv空間の座標範囲は0.0~1.0です。またRGB項は0.0~1.0の範囲で指定されているので、自動的に ' u座標を0~Nx-1に、v座標を0~Ny-1に、RGB項を0~255になるように変換して描画します。 ' 14) NTL2D_DrawPixel ' 指定色(NTL_ColorRGB)で画素を描画します。uv座標は画素に対応しており、PixelBufferのu座標の範囲は0~(Nx-1)、 ' v座標の範囲は0~(Ny-1)の単精度浮動小数点形式です。枠外のuv座標を指定した場合には描画されないだけで問題あり ' ません。 ' 15) NTL2D_DrawLineConstant ' 指定単色(NTL_ColorRGB)で指定2点間を結ぶ線分を描画します。uv座標は画素に対応しており、PixelBufferのu座標の ' 範囲は0~(Nx-1)、v座標の範囲は0~(Ny-1)の単精度浮動小数点形式です。枠外のuv座標を指定した場合にはまずPixel ' Bufferの枠に交差するかチェックし、枠に交差しない線分は描画されません。枠に交差する線分の場合は枠内の点だけが ' 描画されます。但し、これはクリッピング処理ではなく、描画時に有効な画素のみを描画する方式です。 ' 16) NTL2D_DrawLineShading ' 指定2色(NTL_ColorRGB)間を直線補間しながら指定2点間を結ぶ線分を描画します。uv座標は画素に対応しており、 ' PixelBufferのu座標の範囲は0~(Nx-1)、v座標の範囲は0~(Ny-1)の単精度浮動小数点形式です。枠外のuv座標を指定 ' した場合にはまずPixel Bufferの枠に交差するかチェックし、枠に交差しない線分は描画されません。枠に交差する ' 線分の場合は枠内の点だけが描画されます。但し、これはクリッピング処理ではなく、描画時に有効な画素のみを描画 ' する方式です。 ' 17) NTL2D_LineKerning ' 指定線分がPixelBufferのフレーム(枠)内あるいは枠に交差して描画処理可能であるか、あるいは枠外に存在する線分で ' 描画の必要性がないかを判断する関数である。この関数の戻り値がtrueならカーニング可能な(描画の必要性がない)線分 ' であることを示す。 ' 18) NTL2D_Triangle ' カラーシェーディングに対応した三角形描画を行う。uv座標は浮動小数点形式であるが、3線分で囲まれる整数座標上の ' 画素のみを描画する。カラーも整数座標上の色が計算される。 ' 19) NTL2D_Polygon ' n頂点からなる多角形を描画する。[NTL2D_Triangleで使用] ' 20) NTL2D_ScanLine ' スキャンラインに沿って2点間をカラーを直線補間しながら描画する。[NTL2D_Polygonで使用] ' ' ' '########################################################### '### 2D描画オブジェクトのヘッダー情報を指定イメージサイズで構成する '########################################################### ' 横Nx画素、縦Ny画素の2次元ビットマップ・オブジェクトのヘッダー情報を作成する。 Private Sub NTL2D_CreateBitMapRGB_Header(cg As NTL2D_BitMapRGB, Nx As Long, Ny As Long) cg.Nw = NTL_GetNw(Nx) With cg.Header .ID = "BM" .FileLength = 54& + cg.Nw * Ny .Null1 = 0& .HeaderSize = 54 .Offset = 40 .Nx = Nx .Ny = Ny .NumberOfPlanes = 1 .BitsOfPixel = 24 .Null2 = 0& .SizeOfData = cg.Nw * Ny .Null3(0) = 0& .Null3(1) = 0& .Null3(2) = 0& .Null3(3) = 0& End With End Sub '########################################################### '### 指定画像ファイル(RGB24bit BMP形式)を2D形式として読み込む '########################################################### ' RGB24bit BMP形式の画像ファイルを読込、オブジェクトを作成する。 Public Sub NTL2D_GetBitMapFile(cg As NTL2D_BitMapRGB, filename As String) Open filename For Binary Access Read As #1 Get #1, , cg.Header ReDim cg.PixelBuffer(cg.Header.Nx - 1, cg.Header.Ny - 1) Get #1, 55, cg.PixelBuffer Close #1 cg.Nw = NTL_GetNw(cg.Header.Nx) '【x方向画素数×3に最も近い4の倍数を求める】 NTL_SetBasicColor cg.BasicColor '【基本色を設定する】 End Sub '########################################################### '### 指定サイズの画像ファイル(RGB24bit BMP形式)を2D形式で作る '########################################################### Public Sub NTL2D_BuildBitMap(Nx As Long, Ny As Long, cg As NTL2D_BitMapRGB) NTL2D_CreateBitMapRGB_Header cg, Nx, Ny '【BMP形式ファイルのヘッダーを作成する】 NTL_SetBasicColor cg.BasicColor '【基本色を設定する】 ReDim cg.PixelBuffer(cg.Header.Nx - 1, cg.Header.Ny - 1) '【画素バッファの初期化】 NTL2D_FillBitMapImage cg, cg.BasicColor.White ' End Sub '########################################################### '### 2D用画素バッファのカレントイメージをクリアする '########################################################### Public Sub NTL2D_FillBitMapImage(cg As NTL2D_BitMapRGB, P As NTL_ColorRGB) Dim i As Long, j As Long For j = 0 To cg.Header.Ny - 1 For i = 0 To cg.Header.Nx - 1 cg.PixelBuffer(i, j) = P Next i Next j End Sub '########################################################### '### 2D用カレントイメージをファイル化する '########################################################### Public Sub NTL2D_CreateBitMapFile(cg As NTL2D_BitMapRGB, filename As String) Open filename For Binary Access Write As #1 Put #1, 1, cg.Header Put #1, 55, cg.PixelBuffer Close #1 End Sub '########################################################### '### 2D用カラーLookupテーブルを初期化する '########################################################### Public Sub NTL2D_InitializeColorLookupTable(cg As NTL2D_BitMapRGB, n As Long) cg.nColor = n ReDim cg.Color(n - 1) End Sub '########################################################### '### 2D用カラーパレットの指定色間を補間した色を作る '########################################################### Public Sub NTL2D_CreateColor(cg As NTL2D_BitMapRGB, i1 As Long, P1 As NTL_ColorRGB, i2 As Long, P2 As NTL_ColorRGB) Dim Dr As Single, Dg As Single, Db As Single, i As Long Dr = (CSng(P2.R) - CSng(P1.R)) / CSng(i2 - i1) Dg = (CSng(P2.G) - CSng(P1.G)) / CSng(i2 - i1) Db = (CSng(P2.B) - CSng(P1.B)) / CSng(i2 - i1) For i = i1 To i2 Step Sgn(i2 - i1) cg.Color(i).R = P1.R + Dr * CSng(i - i1) cg.Color(i).G = P1.G + Dg * CSng(i - i1) cg.Color(i).B = P1.B + Db * CSng(i - i1) Next i End Sub '########################################################### '### 2D用カラーパレットを作る(グレイ・スケール) '########################################################### Public Sub NTL2D_CreateGrayScale(cg As NTL2D_BitMapRGB, n As Long) NTL2D_InitializeColorLookupTable cg, n NTL2D_CreateColor cg, 0, cg.BasicColor.Black, n - 1, cg.BasicColor.White End Sub '########################################################### '### 2D用カラーパレットを作る(正負) '########################################################### Public Sub NTL2D_CreateDipoleScale(cg As NTL2D_BitMapRGB, n As Long) Dim C0 As Long, C1 As Long, C2 As Long, C3 As Long, C4 As Long, C5 As Long C0 = n - 1 C1 = n * 0.84 C2 = n * 0.67 C3 = n * 0.5 C4 = n * 0.33 C5 = n * 0.17 NTL2D_InitializeColorLookupTable cg, n NTL2D_CreateColor cg, C0, cg.BasicColor.Red, C1, cg.BasicColor.Orange NTL2D_CreateColor cg, C1, cg.BasicColor.Orange, C2, cg.BasicColor.Yellow NTL2D_CreateColor cg, C2, cg.BasicColor.Yellow, C3, cg.BasicColor.Green NTL2D_CreateColor cg, C3, cg.BasicColor.DarkGreen, C4, cg.BasicColor.Cyan NTL2D_CreateColor cg, C4, cg.BasicColor.Cyan, C5, cg.BasicColor.Blue NTL2D_CreateColor cg, C5, cg.BasicColor.Blue, 0, cg.BasicColor.Violet cg.Color(C3) = cg.BasicColor.White End Sub '########################################################### '### 2D用カラーパレットを作る(絶対値) '########################################################### Public Sub NTL2D_CreateMonopoleScale(cg As NTL2D_BitMapRGB, n As Long) Dim C0 As Long, C1 As Long, C2 As Long, C3 As Long, C4 As Long, C5 As Long, C6 As Long C0 = n - 1 C1 = n * 10 / 12 C2 = n * 8 / 12 C3 = n * 6 / 12 C4 = n * 5 / 12 C5 = n * 4 / 12 C6 = n * 2 / 12 NTL2D_InitializeColorLookupTable cg, n ' 表示色数 赤⇒橙⇒黄⇒緑⇒淡青⇒青⇒濃灰⇒灰⇒淡灰⇒白 NTL2D_CreateColor cg, C0, cg.BasicColor.Red, C1, cg.BasicColor.Orange NTL2D_CreateColor cg, C1, cg.BasicColor.Orange, C2, cg.BasicColor.Yellow NTL2D_CreateColor cg, C2, cg.BasicColor.Yellow, C3, cg.BasicColor.Green NTL2D_CreateColor cg, C3, cg.BasicColor.Green, C4, cg.BasicColor.DarkGreen NTL2D_CreateColor cg, C4, cg.BasicColor.DarkGreen, C5, cg.BasicColor.Blue NTL2D_CreateColor cg, C5, cg.BasicColor.Blue, C6, cg.BasicColor.Violet NTL2D_CreateColor cg, C6, cg.BasicColor.DarkGray, 0, cg.BasicColor.White End Sub '########################################################### '###【MMD】2Dカレントイメージに指定色で点を描画する '########################################################### Public Sub MMD2D_DrawPixel(cg As NTL2D_BitMapRGB, MMD_uv As x_Coords2d, MMD_P As x_ColorRGBA) Dim P As NTL_ColorRGB, uv As x_Coords2d P.R = (255 * MMD_P.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P.G = (255 * MMD_P.Green) And &HFF ' P.B = (255 * MMD_P.Blue) And &HFF ' uv.u = (MMD_uv.u - Int(MMD_uv.u)) * (cg.Header.Nx - 1) '【uv座標変換】テクスチャの回込み処理も含む uv.v = (MMD_uv.v - Int(MMD_uv.v)) * (cg.Header.Ny - 1) NTL2D_DrawPixel cg, uv, P End Sub '########################################################### '###【MMD】2Dカレントイメージに指定単色で直線を描画する(コンスタント・シェーディング) '########################################################### Public Sub MMD2D_DrawLineConstant(cg As NTL2D_BitMapRGB, MMD_uv1 As x_Coords2d, MMD_uv2 As x_Coords2d, MMD_P As x_ColorRGBA) Dim P As NTL_ColorRGB, uv1 As x_Coords2d, uv2 As x_Coords2d P.R = (255 * MMD_P.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P.G = (255 * MMD_P.Green) And &HFF ' P.B = (255 * MMD_P.Blue) And &HFF ' uv1.u = (MMD_uv1.u - Int(MMD_uv1.u)) * (cg.Header.Nx - 1) '【uv座標変換】テクスチャの回込み処理も含む uv1.v = (MMD_uv1.v - Int(MMD_uv1.v)) * (cg.Header.Ny - 1) uv2.u = (MMD_uv2.u - Int(MMD_uv2.u)) * (cg.Header.Nx - 1) '【uv座標変換】テクスチャの回込み処理も含む uv2.v = (MMD_uv2.v - Int(MMD_uv2.v)) * (cg.Header.Ny - 1) NTL2D_DrawLineShading cg, uv1, P, uv2, P End Sub '########################################################### '###【MMD】 2Dカレントイメージに指定補間色で直線を描画する(カラー・シェーディング) '########################################################### Public Sub MMD2D_DrawLineShading(cg As NTL2D_BitMapRGB, MMD_uv1 As x_Coords2d, MMD_P1 As x_ColorRGBA, MMD_uv2 As x_Coords2d, MMD_P2 As x_ColorRGBA) Dim P1 As NTL_ColorRGB, P2 As NTL_ColorRGB, uv1 As x_Coords2d, uv2 As x_Coords2d P1.R = (255 * MMD_P1.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P1.G = (255 * MMD_P1.Green) And &HFF ' P1.B = (255 * MMD_P1.Blue) And &HFF ' P2.R = (255 * MMD_P2.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P2.G = (255 * MMD_P2.Green) And &HFF ' P2.B = (255 * MMD_P2.Blue) And &HFF ' uv1.u = (MMD_uv1.u - Int(MMD_uv1.u)) * (cg.Header.Nx - 1) '【uv座標変換】テクスチャの回込み処理も含む uv1.v = (MMD_uv1.v - Int(MMD_uv1.v)) * (cg.Header.Ny - 1) uv2.u = (MMD_uv2.u - Int(MMD_uv2.u)) * (cg.Header.Nx - 1) '【uv座標変換】テクスチャの回込み処理も含む uv2.v = (MMD_uv2.v - Int(MMD_uv2.v)) * (cg.Header.Ny - 1) NTL2D_DrawLineShading cg, uv1, P1, uv2, P2 End Sub '########################################################### '###【NTL】2Dカレントイメージに指定色で点を描画する[表示枠内座標のみ描画する] '########################################################### Public Sub NTL2D_DrawPixel(cg As NTL2D_BitMapRGB, uv As x_Coords2d, P As NTL_ColorRGB) ' テクスチャーの折返し処理は上位コマンドで行う If (CLng(uv.u) >= 0 And CLng(uv.u) < cg.Header.Nx And CLng(uv.v) >= 0 And CLng(uv.v) < cg.Header.Ny) Then cg.PixelBuffer(CLng(uv.u), CLng(uv.v)) = P End If End Sub '########################################################### '###【NTL】2Dカレントイメージに指定単色で直線を描画する(コンスタント・シェーディング)[表示枠内座標のみ描画する] '########################################################### Public Sub NTL2D_DrawLineConstant(cg As NTL2D_BitMapRGB, uv1 As x_Coords2d, uv2 As x_Coords2d, P As NTL_ColorRGB) NTL2D_DrawLineShading cg, uv1, P, uv2, P End Sub '########################################################### '###【NTL】2Dカレント・イメージに指定補間色で直線を描画する(カラー・シェーディング)[表示枠内座標のみ描画する] '########################################################### Public Sub NTL2D_DrawLineShading(cg As NTL2D_BitMapRGB, uv1 As x_Coords2d, P1 As NTL_ColorRGB, uv2 As x_Coords2d, P2 As NTL_ColorRGB) Dim Du As Single, Dv As Single, Dr As Single, Dg As Single, Db As Single, w As Single, MajorDir As Long Dim i As Long, j As Long If NTL2D_LineKerning(cg, uv1, uv2) Then GoTo LE ' この線分が表示枠に引っ掛からない場合、無処理。 Du = uv2.u - uv1.u Dv = uv2.v - uv1.v If Abs(Du) > Abs(Dv) Then ' u座標がMajor軸(長軸) If Du < 0 Then MajorDir = -1 Else MajorDir = 1 ' Major軸の補間進行方向を示す If CLng(Du) <> 0 Then w = 1# / Du Else w = 0 End If Dv = Dv * w Dr = CSng(P2.R - P1.R) * w Dg = CSng(P2.G - P1.G) * w Db = CSng(P2.B - P1.B) * w For i = CLng(uv1.u) To CLng(uv2.u) Step MajorDir If (i >= 0 And i < cg.Header.Nx) Then j = uv1.v + Dv * CSng(i - CLng(uv1.u)) If (j >= 0 And j < cg.Header.Ny) Then cg.PixelBuffer(i, j).R = P1.R + Dr * CSng(i) cg.PixelBuffer(i, j).G = P1.G + Dg * CSng(i) cg.PixelBuffer(i, j).B = P1.B + Db * CSng(i) End If End If Next i Else ' v座標がMajor軸(長軸) If Dv < 0 Then MajorDir = -1 Else MajorDir = 1 ' Major軸の補間進行方向を示す If CLng(Dv) <> 0 Then w = 1# / Dv Else w = 0 End If Du = Du * w Dr = CSng(P2.R - P1.R) * w Dg = CSng(P2.G - P1.G) * w Db = CSng(P2.B - P1.B) * w For j = CLng(uv1.v) To CLng(uv2.v) Step MajorDir If (j >= 0 And j < cg.Header.Ny) Then i = uv1.u + Du * CSng(j - CLng(uv1.v)) If (i >= 0 And i < cg.Header.Nx) Then cg.PixelBuffer(i, j).R = P1.R + Dr * CSng(j) cg.PixelBuffer(i, j).G = P1.G + Dg * CSng(j) cg.PixelBuffer(i, j).B = P1.B + Db * CSng(j) End If End If Next j End If LE: End Sub '########################################################### '###【NTL】2Dカレント・イメージに指定補間色で直線を描画する(カーニング) 枠に引っ掛かったときに線分をクリッピング処理していない。チェックのみ。 '########################################################### Public Function NTL2D_LineKerning(cg As NTL2D_BitMapRGB, uv1 As x_Coords2d, uv2 As x_Coords2d) As Boolean Dim u As Single, v As Single, Duv1 As Single, Duv2 As Single, flag1 As Boolean, flag2 As Boolean NTL2D_LineClipping = False flag1 = (uv1.u >= 0) And (uv1.u < cg.Header.Nx) And (uv1.v >= 0) And (uv1.v < cg.Header.Ny) ' Trueなら頂点uv1は表示枠内 flag2 = (uv2.u >= 0) And (uv2.u < cg.Header.Nx) And (uv2.v >= 0) And (uv2.v < cg.Header.Ny) ' Trueなら頂点uv2は表示枠内 If (flag1 Or flag2) Then GoTo LE '【2頂点のいずれか一方が表示枠内】カーニング不可 If (uv1.u = uv2.u) Or (uv1.v = uv2.v) Then GoTo LE Duv1 = (uv2.u - uv1.u) / (uv2.v - uv1.v) Duv2 = 1# / Duv1 '【交差チェック】v軸(v=0)及びv=cg.Header.Ny-1 ' u = u1 + (v-v1)*(u2-u1)/(v2-v1) u = uv1.u - uv1.v * Duv1 If (u >= 0 And u < cg.Header.Nx) Then GoTo LE '【線分交差】枠下側 v=0 u = uv1.u + (cg.Header.Ny - uv1.v) * Duv1 If (u >= 0 And u < cg.Header.Nx) Then GoTo LE '【線分交差】枠上側 v=cg.Header.Ny '【交差チェック】u軸(u=0)及びu=cg.Header.Nx-1 ' v = v1 + (u-u1)(v2-v1)/(u2-u1) v = uv1.v - uv1.u * Duv2 If (v >= 0 And v < cg.Header.Ny) Then GoTo LE '【線分交差】枠左側 u=0 v = uv1.v + (cg.Header.Nx - uv1.u) * Duv2 If (v >= 0 And v < cg.Header.Ny) Then GoTo LE '【線分交差】枠右側 u=cg.Header.Nx NTL2D_LineClipping = True '【2頂点とも表示枠外、かつ表示枠と交差しない⇒カーニング】 LE: End Function '########################################################### '###【NTL】2Dカレント・イメージに指定補間色で三角形を描画する '########################################################### Public Sub NTL2D_Triangle(cg As NTL2D_BitMapRGB, uv1 As x_Coords2d, P1 As NTL_ColorRGB, uv2 As x_Coords2d, P2 As NTL_ColorRGB, uv3 As x_Coords2d, P3 As NTL_ColorRGB) Dim uv(2) As x_Coords2d, P(2) As NTL_ColorRGB uv(0) = uv1: uv(1) = uv2: uv(2) = uv3: P(0) = P1: P(1) = P2: P(2) = P3 NTL2D_Polygon cg, 3, uv, P End Sub '########################################################### '###【NTL】2Dカレント・イメージに指定補間色で任意多角形を描画する '########################################################### Public Sub NTL2D_Polygon(cg As NTL2D_BitMapRGB, n As Long, uv() As x_Coords2d, pn() As NTL_ColorRGB) Dim Ymax As Single, Ymin As Single, Pmax As Long, Pmin As Long Dim uva1 As x_Coords2d, uva2 As x_Coords2d, uvb1 As x_Coords2d, uvb2 As x_Coords2d Dim pa1 As x_ColorRGBA, pa2 As x_ColorRGBA, pb1 As x_ColorRGBA, pb2 As x_ColorRGBA Dim Dua As Single, Dra As Single, Dga As Single, Dba As Single, Dub As Single, Drb As Single, Dgb As Single, Dbb As Single Dim i As Long, Pa As Long, Pb As Long, Ca As Long, Cb As Long, wa As Single, wb As Single, w As Single Dim P() As x_ColorRGBA ReDim P(n - 1) Ymax = -NTL3D_Z_max: Ymin = NTL3D_Z_max For i = 0 To n - 1 P(i).Red = pn(i).R P(i).Green = pn(i).G P(i).Blue = pn(i).B P(i).Alpha = 1 If (uv(i).v > Ymax) Then Pmax = i: Ymax = uv(i).v End If If (uv(i).v < Ymin) Then Pmin = i: Ymin = uv(i).v End If Next i i = 0: Pa = Pmax: Pb = Pmax: Ca = 0: Cb = 0 GetALine: uva1 = uv(Pa): pa1 = P(Pa): Pa = Pa + 1: If Pa = n Then Pa = 0 uva2 = uv(Pa): pa2 = P(Pa): wa = uva2.v - uva1.v: If Abs(wa) = 0 Then wa = 0 Else wa = 1# / wa Dua = (uva2.u - uva1.u) * wa: Dra = (pa2.Red - pa1.Red) * wa: Dga = (pa2.Green - pa1.Green) * wa: Dba = (pa2.Blue - pa1.Blue) * wa w = uva1.v - Int(uva1.v): uva1.v = Int(uva1.v): Ca = Abs(uva2.v - uva1.v) uva1.u = uva1.u - Dua * w: pa1.Red = pa1.Red - Dra * w: pa1.Green = pa1.Green - Dga * w: pa1.Blue = pa1.Blue - Dba * w If i = 1 Then GoTo L1 If i = 2 Then GoTo L3 GetBLine: uvb1 = uv(Pb): pb1 = P(Pb): Pb = Pb - 1: If Pb = -1 Then Pb = n - 1 uvb2 = uv(Pb): pb2 = P(Pb): wb = uvb2.v - uvb1.v: If Abs(wb) = 0 Then wb = 0 Else wb = 1# / wb Dub = (uvb2.u - uvb1.u) * wb: Drb = (pb2.Red - pb1.Red) * wb: Dgb = (pb2.Green - pb1.Green) * wb: Dbb = (pb2.Blue - pb1.Blue) * wb w = uvb1.v - Int(uvb1.v): uvb1.v = Int(uvb1.v): Cb = Abs(uvb2.v - uvb1.v) uvb1.u = uvb1.u - Dub * w: pb1.Red = pb1.Red - Drb * w: pb1.Green = pb1.Green - Dgb * w: pb1.Blue = pb1.Blue - Dbb * w If i = 1 Then GoTo L1 If i = 2 Then GoTo L4 i = 1 L1: If (Ca < 0) And (Pa <> Pb) Then GoTo GetALine '【20090928修正】 If (Cb < 0) And (Pa <> Pb) Then GoTo GetBLine '【20090928修正】 If (Ca <= 0) And (Cb <= 0) And (Pa = Pb) Then GoTo LE '【20090928修正】 L2: NTL2D_ScanLine cg, uva1, pa1, uvb1, pb1 ' ax = uva1.u: bx = uvb1.u: ay = uva1.v: by = uvb1.v '【Debug用】 L3: Ca = Ca - 1: uva1.v = uva1.v - 1: uva1.u = uva1.u - Dua: pa1.Red = pa1.Red - Dra: pa1.Green = pa1.Green - Dga: pa1.Blue = pa1.Blue - Dba If (Ca < 0) And (Pa <> Pb) Then '【20090928修正】 i = 2: GoTo GetALine End If L4: Cb = Cb - 1: uvb1.v = uvb1.v - 1: uvb1.u = uvb1.u - Dub: pb1.Red = pb1.Red - Drb: pb1.Green = pb1.Green - Dgb: pb1.Blue = pb1.Blue - Dbb If (Cb < 0) And (Pa <> Pb) Then '【20090928修正】 i = 2: GoTo GetBLine End If GoTo L1 LE: End Sub '########################################################### '###【NTL】2Dカレント・イメージに指定補間色でスキャンラインを描画する '########################################################### Public Sub NTL2D_ScanLine(cg As NTL2D_BitMapRGB, uv1 As x_Coords2d, P1 As x_ColorRGBA, uv2 As x_Coords2d, P2 As x_ColorRGBA) Dim uvs As x_Coords2d, ps As x_ColorRGBA, uve As x_Coords2d, pe As x_ColorRGBA, NTL_P As NTL_ColorRGB Dim Du As Single, Dr As Single, Dg As Single, Db As Single, w As Single, u As Single, i As Long, j As Long If (uv1.u < uv2.u) Then '【スキャンラインを左から右へ描画するために始点と終点を決定する】 uvs = uv1: uve = uv2: ps = P1: pe = P2 Else uvs = uv2: uve = uv1: ps = P2: pe = P1 End If If uve.u < 0 Then GoTo LE '【終点がu=0より小さいので終了】 Du = uve.u - uvs.u: If Du <> 0 Then w = 1# / Du Else w = 0 Dr = (pe.Red - ps.Red) * w Dg = (pe.Green - ps.Green) * w Db = (pe.Blue - ps.Blue) * w If uvs.u >= 0 Then '【20090928修正】 u = uvs.u - Int(uvs.u) ' u軸方向微調整分(1画素未満) If u <> 0 Then u = 1 - u ' If u > Du Then GoTo LE ' 幅を超えているので終了 uvs.u = uvs.u + u ' 整数座標に合わせる Else ' u = -uvs.u ' u軸方向スキップ分 If u > Du Then GoTo LE ' 幅を超えているので終了 uvs.u = 0 ' End If ' ps.Red = ps.Red + u * Dr ps.Green = ps.Green + u * Dg ps.Blue = ps.Blue + u * Db j = CLng(uve.u - uvs.u) '【20090928修正】 For i = 0 To j NTL_P.R = CInt(ps.Red) And &HFF NTL_P.G = CInt(ps.Green) And &HFF NTL_P.B = CInt(ps.Blue) And &HFF NTL2D_DrawPixel cg, uvs, NTL_P If i = j Then GoTo LE uvs.u = uvs.u + 1 ps.Red = ps.Red + Dr ps.Green = ps.Green + Dg ps.Blue = ps.Blue + Db Next i LE: End Sub '****************************************************** '********** '********** 3次元グラッフィックス用コマンド '********** '****************************************************** ' 本プログラムはテクスチャーマッピング処理も実装した3次元グラフィックスのためのライブラリです。 ' 点,線分,三角形の描画を行うことができます。 '【2次元オブジェクトに対するコマンド】 ' 1) NTL3D_CreateBitMapRGB_Header ' 3次元描画オブジェクト型NTL3D_BitMapRGBに対して、1画素当たりRGB24bit, 横Nx画素, 縦Ny画素のbmp形式ファイル ' のヘッダー情報を生成するために使います。 ' 2) NTL3D_GetBitMapFile ' 指定のRGB24bit形式のbmpファイルを読み込んで3次元描画オブジェクト型NTL3D_BitMapRGBを生成します。BasicColor ' (基本色)パレットが初期化され、zバッファが最奥値に初期化されます。描画オブジェクトとなることでテクスチャー ' マッピングを行うことや、追加で描画を行うことができるようになります。 ' 3) NTL3D_BuildBitMap ' 指定サイズの3次元描画オブジェクト型NTL3D_BitMapRGBを生成します。BasicColor(基本色)パレットが初期化され、 ' PixcelBuffer(フレーム)は白色でクリアされ、zバッファが最奥値に初期化されます。 ' 4) NTL3D_FillBitMapImage ' 3次元描画オブジェクト型NTL3D_BitMapRGBのPixcelBufferを指定色でクリアします。NTL_ColorRGB形式で色の指定を行います。 ' 5) NTL3D_ClearZ_Buffer ' 3次元描画オブジェクト型NTL3D_BitMapRGBのZ_bufferを最奥値でクリアします。z値は単精度浮動小数点形式です。 ' 6) NTL3D_CreateBitMapFile ' 指定描画オブジェクトの内容を指定ファイル名で1画素RGB24bitのbmp形式ファイルに書き出します。 ' 7) NTL3D_InitializeColorLookupTable ' 指定3次元描画オブジェクト型NTL3D_BitMapRGBにはBasicColor(基本色)パレットのほかにカラーインデックス方式の描画を行うため ' に用意したColorパレット[配列]があります。このコマンドは指定色数の配列領域を確保するために用います。このコマンドは領域 ' の確保だけで、色の設定は行いません。 ' 8) NTL3D_CreateColor ' Colorパレット配列に色を直線補間処理で設定するために用います。開始番号、開始色、終了番号、終了色を指定する ' ことで、指定2色間を補間したカラーパレットを作ることができます。 ' 9) NTL3D_CreateGrayScale ' 指定した階調数のグレースケールをカラーパレットに設定することができます。 ' 10) NTL3D_CreateDipoleScale ' シミュレーションなどで正負の値を赤青系で階調表現したいときに使うと便利なカラーパレット設定コマンドです。 ' 階調数を指定することができます。 ' 11) NTL3D_CreateMonopoleScale ' シミュレーションなどで絶対強度を階調表現したいときに使うと便利なカラーパレット設定コマンドです。 ' 階調数を指定することができます。 ' 12) MMD3D_DrawPixel ' 1画素単位に描画するコマンドです。zバッファは後書き優先になっています。 ' MikuMikuDanceではRGB項は0.0~1.0の範囲で指定されているので、自動的にRGB項を0~255になるように変換して描画します。 ' 13) MMD3D_DrawLineConstant ' 指定xyz座標2点間を結ぶ線分を指定単色で描画するコマンドです。zバッファは後書き優先になっています。 ' MikuMikuDanceではRGB項は0.0~1.0の範囲で指定されているので、自動的にRGB項を0~255になるように変換して描画します。 ' 14) MMD3D_DrawLineShading ' 指定xyz座標2点間を結ぶ線分を指定2色の直線補間をかけながら描画するコマンドです。zバッファは後書き優先になっています。 ' MikuMikuDanceではRGB項は0.0~1.0の範囲で指定されているので、自動的にRGB項を0~255になるように変換して描画します。 ' 15) NTL3D_DrawPixel ' 指定色(NTL_ColorRGB)で画素を描画します。x,y座標は画素に対応しており、PixelBufferのx座標の範囲は0~(Nx-1)、 ' y座標の範囲は0~(Ny-1)の単精度浮動小数点形式です。枠外のxy座標を指定した場合には描画されないだけで問題あり ' ません。zバッファは後書き優先になっています。 ' 16) NTL3D_DrawLineConstant ' 指定単色(NTL_ColorRGB)で指定2点間を結ぶ線分を描画します。x,y座標は画素に対応しており、PixelBufferのx座標の ' 範囲は0~(Nx-1)、y座標の範囲は0~(Ny-1)の単精度浮動小数点形式です。枠外のxy座標を指定した場合にはまずPixel ' Bufferの枠に交差するかチェックし、枠に交差しない線分は描画されません。枠に交差する線分の場合は枠内の点だけが ' 描画されます。但し、これはクリッピング処理ではなく、描画時に有効な画素のみを描画する方式です。 ' zバッファは後書き優先になっています。 ' 17) NTL3D_DrawLineShading ' 指定2色(NTL_ColorRGB)間を直線補間しながら指定2点間を結ぶ線分を描画します。x,y座標は画素に対応しており、 ' PixelBufferのx座標の範囲は0~(Nx-1)、y座標の範囲は0~(Ny-1)の単精度浮動小数点形式です。枠外のxy座標を指定 ' した場合にはまずPixel Bufferの枠に交差するかチェックし、枠に交差しない線分は描画されません。枠に交差する ' 線分の場合は枠内の点だけが描画されます。但し、これはクリッピング処理ではなく、描画時に有効な画素のみを描画 ' する方式です。zバッファは後書き優先になっています。 ' 18) NTL3D_LineKerning ' 指定線分がPixelBufferのフレーム(枠)内あるいは枠に交差して描画処理可能であるか、あるいは枠外に存在する線分で ' 描画の必要性がないかを判断する関数である。この関数の戻り値がtrueならカーニング可能な(描画の必要性がない)線分 ' であることを示す。 ' 19) NTL3D_Triangle ' カラーシェーディングに対応した三角形描画を行う。xyz座標は浮動小数点形式であるが、3線分で囲まれる整数座標上の ' 画素のみを描画する。カラーも整数座標上の色が計算される。 ' 20) NTL3D_Polygon ' n頂点からなる多角形を描画する。[NTL3D_Triangleで使用] ' 21) NTL3D_ScanLine ' スキャンラインに沿って2点間をカラーを直線補間しながら描画する。[NTL3D_Polygonで使用] ' 22) NTL3D_TriangleWithTextureMapping ' 指定uv空間の三角形領域内のテクスチャーを指定xyz空間の三角形領域にマッピングする。xyz座標、uv座標は画素単位の浮動 ' 小数点形式である。xy座標において3線分で囲まれる整数座標上の画素のみを描画する。カラーも整数座標上の色が計算される。 ' 23) NTL3D_PolygonWithTextureMapping ' n頂点からなる多角形に対してテクスチャーマッピングを行う。 ' 24) NTL3D_ScanLineWithTextureMapping ' スキャンラインに沿って2点間のテクスチャーマッピングを行う。 '########################################################### '### 3D描画オブジェクトのヘッダー情報を指定イメージサイズで構成する '########################################################### Private Sub NTL3D_CreateBitMapRGB_Header(cg As NTL3D_BitMapRGB, Nx As Long, Ny As Long) cg.Nw = NTL_GetNw(Nx) With cg.Header .ID = "BM" .FileLength = 54& + cg.Nw * Ny .Null1 = 0& .HeaderSize = 54 .Offset = 40 .Nx = Nx .Ny = Ny .NumberOfPlanes = 1 .BitsOfPixel = 24 .Null2 = 0& .SizeOfData = cg.Nw * Ny .Null3(0) = 0& .Null3(1) = 0& .Null3(2) = 0& .Null3(3) = 0& End With End Sub '########################################################### '### 指定画像ファイル(RGB24bit BMP形式)を3D形式として読み込む '########################################################### Public Sub NTL3D_GetBitMapFile(cg As NTL3D_BitMapRGB, filename As String) Open filename For Binary Access Read As #1 Get #1, , cg.Header ReDim cg.PixelBuffer(cg.Header.Nx - 1, cg.Header.Ny - 1) Get #1, 55, cg.PixelBuffer Close #1 ReDim cg.Z_buffer(cg.Header.Nx - 1, cg.Header.Ny - 1) '【zバッファの初期化】 NTL3D_ClearZ_Buffer cg, NTL3D_Z_max ' cg.Nw = NTL_GetNw(cg.Header.Nx) '【x方向画素数×3に最も近い4の倍数を求める】 NTL_SetBasicColor cg.BasicColor '【基本色を設定する】 End Sub '########################################################### '### 指定サイズの画像ファイル(RGB24bit BMP形式)を3D形式で作る '########################################################### Public Sub NTL3D_BuildBitMap(Nx As Long, Ny As Long, cg As NTL3D_BitMapRGB) NTL3D_CreateBitMapRGB_Header cg, Nx, Ny '【BMP形式ファイルのヘッダーを作成する】 NTL_SetBasicColor cg.BasicColor '【基本色を設定する】 ReDim cg.PixelBuffer(cg.Header.Nx - 1, cg.Header.Ny - 1) '【画素バッファの初期化】 NTL3D_FillBitMapImage cg, cg.BasicColor.White ' ReDim cg.Z_buffer(cg.Header.Nx - 1, cg.Header.Ny - 1) '【Zバッファの初期化】 NTL3D_ClearZ_Buffer cg, NTL3D_Z_max ' End Sub '########################################################### '### 3D用画素バッファのカレントイメージをクリアする '########################################################### Public Sub NTL3D_FillBitMapImage(cg As NTL3D_BitMapRGB, P As NTL_ColorRGB) Dim i As Long, j As Long For j = 0 To cg.Header.Ny - 1 For i = 0 To cg.Header.Nx - 1 cg.PixelBuffer(i, j) = P Next i Next j End Sub '########################################################### '### 3D用ZバッファのZ値をクリアする '########################################################### Public Sub NTL3D_ClearZ_Buffer(cg As NTL3D_BitMapRGB, z As Single) Dim i As Long, j As Long For j = 0 To cg.Header.Ny - 1 For i = 0 To cg.Header.Nx - 1 cg.Z_buffer(i, j) = z Next i Next j End Sub '########################################################### '### 3D用カレントイメージをファイル化する '########################################################### Public Sub NTL3D_CreateBitMapFile(cg As NTL3D_BitMapRGB, filename As String) Open filename For Binary Access Write As #1 Put #1, 1, cg.Header Put #1, 55, cg.PixelBuffer Close #1 End Sub '########################################################### '### 3D用カラーLookupテーブルを初期化する '########################################################### Public Sub NTL3D_InitializeColorLookupTable(cg As NTL3D_BitMapRGB, n As Long) cg.nColor = n ReDim cg.Color(n - 1) End Sub '########################################################### '### 3D用カラーパレットの指定色間を補間した色を作る '########################################################### Public Sub NTL3D_CreateColor(cg As NTL3D_BitMapRGB, i1 As Long, P1 As NTL_ColorRGB, i2 As Long, P2 As NTL_ColorRGB) Dim Dr As Single, Dg As Single, Db As Single, i As Long Dr = (CSng(P2.R) - CSng(P1.R)) / CSng(i2 - i1) Dg = (CSng(P2.G) - CSng(P1.G)) / CSng(i2 - i1) Db = (CSng(P2.B) - CSng(P1.B)) / CSng(i2 - i1) For i = i1 To i2 Step Sgn(i2 - i1) cg.Color(i).R = P1.R + Dr * CSng(i - i1) cg.Color(i).G = P1.G + Dg * CSng(i - i1) cg.Color(i).B = P1.B + Db * CSng(i - i1) Next i End Sub '########################################################### '### 3D用カラーパレットを作る(グレイ・スケール) '########################################################### Public Sub NTL3D_CreateGrayScale(cg As NTL3D_BitMapRGB, n As Long) NTL3D_InitializeColorLookupTable cg, n NTL3D_CreateColor cg, 0, cg.BasicColor.Black, n - 1, cg.BasicColor.White End Sub '########################################################### '### 3D用カラーパレットを作る(正負) '########################################################### Public Sub NTL3D_CreateDipoleScale(cg As NTL3D_BitMapRGB, n As Long) Dim C0 As Long, C1 As Long, C2 As Long, C3 As Long, C4 As Long, C5 As Long C0 = n - 1 C1 = n * 0.84 C2 = n * 0.67 C3 = n * 0.5 C4 = n * 0.33 C5 = n * 0.17 NTL3D_InitializeColorLookupTable cg, n NTL3D_CreateColor cg, C0, cg.BasicColor.Red, C1, cg.BasicColor.Orange NTL3D_CreateColor cg, C1, cg.BasicColor.Orange, C2, cg.BasicColor.Yellow NTL3D_CreateColor cg, C2, cg.BasicColor.Yellow, C3, cg.BasicColor.Green NTL3D_CreateColor cg, C3, cg.BasicColor.DarkGreen, C4, cg.BasicColor.Cyan NTL3D_CreateColor cg, C4, cg.BasicColor.Cyan, C5, cg.BasicColor.Blue NTL3D_CreateColor cg, C5, cg.BasicColor.Blue, 0, cg.BasicColor.Violet cg.Color(C3) = cg.BasicColor.White End Sub '########################################################### '### 3D用カラーパレットを作る(絶対値) '########################################################### Public Sub NTL3D_CreateMonopoleScale(cg As NTL3D_BitMapRGB, n As Long) Dim C0 As Long, C1 As Long, C2 As Long, C3 As Long, C4 As Long, C5 As Long, C6 As Long C0 = n - 1 C1 = n * 10 / 12 C2 = n * 8 / 12 C3 = n * 6 / 12 C4 = n * 5 / 12 C5 = n * 4 / 12 C6 = n * 2 / 12 NTL3D_InitializeColorLookupTable cg, n ' 表示色数 赤⇒橙⇒黄⇒緑⇒淡青⇒青⇒濃灰⇒灰⇒淡灰⇒白 NTL3D_CreateColor cg, C0, cg.BasicColor.Red, C1, cg.BasicColor.Orange NTL3D_CreateColor cg, C1, cg.BasicColor.Orange, C2, cg.BasicColor.Yellow NTL3D_CreateColor cg, C2, cg.BasicColor.Yellow, C3, cg.BasicColor.Green NTL3D_CreateColor cg, C3, cg.BasicColor.Green, C4, cg.BasicColor.DarkGreen NTL3D_CreateColor cg, C4, cg.BasicColor.DarkGreen, C5, cg.BasicColor.Blue NTL3D_CreateColor cg, C5, cg.BasicColor.Blue, C6, cg.BasicColor.Violet NTL3D_CreateColor cg, C6, cg.BasicColor.DarkGray, 0, cg.BasicColor.White End Sub '########################################################### '###【MMD】3Dカレントイメージに指定色で点を描画する '########################################################### Public Sub MMD3D_DrawPixel(cg As NTL3D_BitMapRGB, pos As x_Vector, MMD_P As x_ColorRGBA) Dim P As NTL_ColorRGB P.R = (255 * MMD_P.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P.G = (255 * MMD_P.Green) And &HFF ' P.B = (255 * MMD_P.Blue) And &HFF ' NTL3D_DrawPixel cg, pos, P End Sub '########################################################### '###【MMD】3Dカレントイメージに指定単色で直線を描画する(コンスタント・シェーディング) '########################################################### Public Sub MMD3D_DrawLineConstant(cg As NTL3D_BitMapRGB, pos1 As x_Vector, pos2 As x_Vector, MMD_P As x_ColorRGBA) Dim P As NTL_ColorRGB P.R = (255 * MMD_P.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P.G = (255 * MMD_P.Green) And &HFF ' P.B = (255 * MMD_P.Blue) And &HFF ' NTL3D_DrawLineShading cg, pos1, P, pos2, P End Sub '########################################################### '###【MMD】 3Dカレントイメージに指定補間色で直線を描画する(カラー・シェーディング) '########################################################### Public Sub MMD3D_DrawLineShading(cg As NTL3D_BitMapRGB, pos1 As x_Vector, MMD_P1 As x_ColorRGBA, pos2 As x_Vector, MMD_P2 As x_ColorRGBA) Dim P1 As NTL_ColorRGB, P2 As NTL_ColorRGB P1.R = (255 * MMD_P1.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P1.G = (255 * MMD_P1.Green) And &HFF ' P1.B = (255 * MMD_P1.Blue) And &HFF ' P2.R = (255 * MMD_P2.Red) And &HFF '【色範囲変換】MMD,DirectXは範囲(0.0-1.0)、これを範囲(0-255)に変換する。 P2.G = (255 * MMD_P2.Green) And &HFF ' P2.B = (255 * MMD_P2.Blue) And &HFF ' NTL3D_DrawLineShading cg, pos1, P1, pos2, P2 End Sub '########################################################### '###【NTL】3Dカレントイメージに指定色で点を描画する[表示枠内座標のみ描画する] '########################################################### Public Sub NTL3D_DrawPixel(cg As NTL3D_BitMapRGB, pos As x_Vector, P As NTL_ColorRGB) ' テクスチャーの折返し処理は上位コマンドで行う If (CLng(pos.x) >= 0 And CLng(pos.x) < cg.Header.Nx And CLng(pos.y) >= 0 And CLng(pos.y) < cg.Header.Ny) Then If pos.z <= cg.Z_buffer(CLng(pos.x), CLng(pos.y)) Then cg.PixelBuffer(CLng(pos.x), CLng(pos.y)) = P cg.Z_buffer(CLng(pos.x), CLng(pos.y)) = pos.z End If End If End Sub '########################################################### '###【NTL】3Dカレントイメージに指定単色で直線を描画する(コンスタント・シェーディング)[表示枠内座標のみ描画する] '########################################################### Public Sub NTL3D_DrawLineConstant(cg As NTL3D_BitMapRGB, pos1 As x_Vector, pos2 As x_Vector, P As NTL_ColorRGB) NTL3D_DrawLineShading cg, pos1, P, pos2, P End Sub '########################################################### '###【NTL】3Dカレント・イメージに指定補間色で直線を描画する(カラー・シェーディング)[表示枠内座標のみ描画する] '########################################################### Public Sub NTL3D_DrawLineShading(cg As NTL3D_BitMapRGB, pos1 As x_Vector, P1 As NTL_ColorRGB, pos2 As x_Vector, P2 As NTL_ColorRGB) Dim Dx As Single, Dy As Single, Dz As Single, Dr As Single, Dg As Single, Db As Single, w As Single, MajorDir As Long Dim i As Long, j As Long If NTL3D_LineKerning(cg, pos1, pos2) Then GoTo LE ' この線分が表示枠に引っ掛からない場合、無処理。 Dx = pos2.x - pos1.x Dy = pos2.y - pos1.y If Abs(Dx) > Abs(Dy) Then ' x座標がMajor軸(長軸) If Dx < 0 Then MajorDir = -1 Else MajorDir = 1 ' Major軸の補間進行方向を示す If CLng(Dx) <> 0 Then w = 1# / Dx Else w = 0 End If Dy = Dy * w Dz = CSng(pos2.z - pos1.z) * w Dr = CSng(P2.R - P1.R) * w Dg = CSng(P2.G - P1.G) * w Db = CSng(P2.B - P1.B) * w For i = CLng(pos1.x) To CLng(pos2.x) Step MajorDir If (i >= 0 And i < cg.Header.Nx) Then j = pos1.y + Dy * CSng(i - CLng(pos1.x)) If (j >= 0 And j < cg.Header.Ny) Then If cg.Z_buffer(i, j) >= (pos1.z + Dz * CSng(i)) Then cg.Z_buffer(i, j) = pos1.z + Dz * CSng(i) cg.PixelBuffer(i, j).R = P1.R + Dr * CSng(i) cg.PixelBuffer(i, j).G = P1.G + Dg * CSng(i) cg.PixelBuffer(i, j).B = P1.B + Db * CSng(i) End If End If End If Next i Else ' y座標がMajor軸(長軸) If Dy < 0 Then MajorDir = -1 Else MajorDir = 1 ' Major軸の補間進行方向を示す If CLng(Dy) <> 0 Then w = 1# / Dy Else w = 0 End If Dx = Dx * w Dz = CSng(pos2.z - pos1.z) * w Dr = CSng(P2.R - P1.R) * w Dg = CSng(P2.G - P1.G) * w Db = CSng(P2.B - P1.B) * w For j = CLng(pos1.y) To CLng(pos2.y) Step MajorDir If (j >= 0 And j < cg.Header.Ny) Then i = pos1.x + Dx * CSng(j - CLng(pos1.y)) If (i >= 0 And i < cg.Header.Nx) Then If cg.Z_buffer(i, j) >= (pos1.z + Dz * CSng(j)) Then cg.Z_buffer(i, j) = pos1.z + Dz * CSng(j) cg.PixelBuffer(i, j).R = P1.R + Dr * CSng(j) cg.PixelBuffer(i, j).G = P1.G + Dg * CSng(j) cg.PixelBuffer(i, j).B = P1.B + Db * CSng(j) End If End If End If Next j End If LE: End Sub '########################################################### '###【NTL】3Dカレント・イメージに指定補間色で直線を描画する(カーニング) 枠に引っ掛かったときに線分をクリッピング処理していない。チェックのみ。 '########################################################### Public Function NTL3D_LineKerning(cg As NTL3D_BitMapRGB, pos1 As x_Vector, pos2 As x_Vector) As Boolean Dim x As Single, y As Single, Dpos1 As Single, Dpos2 As Single, flag1 As Boolean, flag2 As Boolean NTL3D_LineClipping = False flag1 = (pos1.x >= 0) And (pos1.x < cg.Header.Nx) And (pos1.y >= 0) And (pos1.y < cg.Header.Ny) ' Trueなら頂点uv1は表示枠内 flag2 = (pos2.x >= 0) And (pos2.x < cg.Header.Nx) And (pos2.y >= 0) And (pos2.y < cg.Header.Ny) ' Trueなら頂点uv2は表示枠内 If (flag1 Or flag2) Then GoTo LE '【2頂点のいずれか一方が表示枠内】カーニング不可 If (pos1.x = pos2.x) Or (pos1.y = pos2.y) Then GoTo LE Dpos1 = (pos2.x - pos1.x) / (pos2.y - pos1.y) Dpos2 = 1# / Dpos1 '【交差チェック】y軸(y=0)及びy=cg.Header.Ny-1 ' x = x1 + (y-y1)*(x2-x1)/(y2-y1) x = pos1.x - pos1.y * Dpos1 If (x >= 0 And x < cg.Header.Nx) Then GoTo LE '【線分交差】枠下側 y=0 x = pos1.x + (cg.Header.Ny - pos1.y) * Dpos1 If (x >= 0 And x < cg.Header.Nx) Then GoTo LE '【線分交差】枠上側 y=cg.Header.Ny '【交差チェック】x軸(x=0)及びx=cg.Header.Nx-1 ' y = y1 + (x-x1)(y2-y1)/(x2-x1) y = pos1.y - pos1.x * Dpos2 If (y >= 0 And y < cg.Header.Ny) Then GoTo LE '【線分交差】枠左側 x=0 y = pos1.y + (cg.Header.Nx - pos1.x) * Dpos2 If (y >= 0 And y < cg.Header.Ny) Then GoTo LE '【線分交差】枠右側 x=cg.Header.Nx NTL3D_LineClipping = True '【2頂点とも表示枠外、かつ表示枠と交差しない⇒カーニング】 LE: End Function '########################################################### '###【NTL】3Dカレント・イメージに指定補間色で三角形を描画する '########################################################### Public Sub NTL3D_Triangle(cg As NTL3D_BitMapRGB, pos1 As x_Vector, P1 As NTL_ColorRGB, pos2 As x_Vector, P2 As NTL_ColorRGB, pos3 As x_Vector, P3 As NTL_ColorRGB) Dim pos(2) As x_Vector, P(2) As NTL_ColorRGB pos(0) = pos1: pos(1) = pos2: pos(2) = pos3: P(0) = P1: P(1) = P2: P(2) = P3 NTL3D_Polygon cg, 3, pos, P End Sub '########################################################### '###【NTL】3Dカレント・イメージに指定補間色で任意多角形を描画する '########################################################### Public Sub NTL3D_Polygon(cg As NTL3D_BitMapRGB, n As Long, pos() As x_Vector, pn() As NTL_ColorRGB) Dim Ymax As Single, Ymin As Single, Pmax As Long, Pmin As Long Dim posa1 As x_Vector, posa2 As x_Vector, posb1 As x_Vector, posb2 As x_Vector Dim pa1 As x_ColorRGBA, pa2 As x_ColorRGBA, pb1 As x_ColorRGBA, pb2 As x_ColorRGBA Dim Dxa As Single, Dza As Single, Dra As Single, Dga As Single, Dba As Single Dim Dxb As Single, Dzb As Single, Drb As Single, Dgb As Single, Dbb As Single Dim i As Long, Pa As Long, Pb As Long, Ca As Long, Cb As Long, wa As Single, wb As Single, w As Single Dim P() As x_ColorRGBA ReDim P(n - 1) Ymax = -NTL3D_Z_max: Ymin = NTL3D_Z_max For i = 0 To n - 1 P(i).Red = pn(i).R P(i).Green = pn(i).G P(i).Blue = pn(i).B P(i).Alpha = 1 If (pos(i).y > Ymax) Then Pmax = i: Ymax = pos(i).y End If If (pos(i).y < Ymin) Then Pmin = i: Ymin = pos(i).y End If Next i i = 0: Pa = Pmax: Pb = Pmax: Ca = 0: Cb = 0 GetALine: posa1 = pos(Pa): pa1 = P(Pa): Pa = Pa + 1: If Pa = n Then Pa = 0 posa2 = pos(Pa): pa2 = P(Pa): wa = posa2.y - posa1.y: If Abs(wa) = 0 Then wa = 0 Else wa = 1# / wa Dxa = (posa2.x - posa1.x) * wa: Dza = (posa2.z - posa1.z) * wa: Dra = (pa2.Red - pa1.Red) * wa: Dga = (pa2.Green - pa1.Green) * wa: Dba = (pa2.Blue - pa1.Blue) * wa w = posa1.y - Int(posa1.y): posa1.y = Int(posa1.y): Ca = Abs(posa2.y - posa1.y) '【20090928修正】 posa1.x = posa1.x - Dxa * w: posa1.z = posa1.z - Dza * w: pa1.Red = pa1.Red - Dra * w: pa1.Green = pa1.Green - Dga * w: pa1.Blue = pa1.Blue - Dba * w If i = 1 Then GoTo L1 If i = 2 Then GoTo L3 GetBLine: posb1 = pos(Pb): pb1 = P(Pb): Pb = Pb - 1: If Pb = -1 Then Pb = n - 1 posb2 = pos(Pb): pb2 = P(Pb): wb = posb2.y - posb1.y: If Abs(wb) = 0 Then wb = 0 Else wb = 1# / wb Dxb = (posb2.x - posb1.x) * wb: Dzb = (posb2.z - posb1.z) * wb: Drb = (pb2.Red - pb1.Red) * wb: Dgb = (pb2.Green - pb1.Green) * wb: Dbb = (pb2.Blue - pb1.Blue) * wb w = posb1.y - Int(posb1.y): posb1.y = Int(posb1.y): Cb = Abs(posb2.y - posb1.y) '【20090928修正】 posb1.x = posb1.x - Dxb * w: posb1.z = posb1.z - Dzb * w: pb1.Red = pb1.Red - Drb * w: pb1.Green = pb1.Green - Dgb * w: pb1.Blue = pb1.Blue - Dbb * w If i = 1 Then GoTo L1 If i = 2 Then GoTo L4 i = 1 L1: If (Ca <= 0) And (Pa <> Pb) Then GoTo GetALine '【20090928修正】 If (Cb <= 0) And (Pa <> Pb) Then GoTo GetBLine '【20090928修正】 If (Ca <= 0) And (Cb <= 0) And (Pa = Pb) Then GoTo LE '【20090928修正】 L2: NTL3D_ScanLine cg, posa1, pa1, posb1, pb1 ax = posa1.x: bx = posb1.x: ay = posa1.y: by = posb1.y '【Debug時座標確認用】 L3: If (Ca = 0) And (Pa <> Pb) Then '【20090928修正】 i = 2: GoTo GetALine End If Ca = Ca - 1: posa1.y = posa1.y - 1: posa1.x = posa1.x - Dxa: posa1.z = posa1.z - Dza: pa1.Red = pa1.Red - Dra: pa1.Green = pa1.Green - Dga: pa1.Blue = pa1.Blue - Dba L4: If (Cb = 0) And (Pa <> Pb) Then '【20090928修正】 i = 2: GoTo GetBLine End If Cb = Cb - 1: posb1.y = posb1.y - 1: posb1.x = posb1.x - Dxb: posb1.z = posb1.z - Dzb: pb1.Red = pb1.Red - Drb: pb1.Green = pb1.Green - Dgb: pb1.Blue = pb1.Blue - Dbb GoTo L1 LE: NTL3D_ScanLine cg, posa1, pa1, posb1, pb1 End Sub '########################################################### '###【NTL】3Dカレント・イメージに指定補間色でスキャンラインを描画する '########################################################### Public Sub NTL3D_ScanLine(cg As NTL3D_BitMapRGB, pos1 As x_Vector, P1 As x_ColorRGBA, pos2 As x_Vector, P2 As x_ColorRGBA) Dim poss As x_Vector, ps As x_ColorRGBA, pose As x_Vector, pe As x_ColorRGBA, NTL_P As NTL_ColorRGB Dim Dx As Single, Dz As Single, Dr As Single, Dg As Single, Db As Single, w As Single, u As Single, i As Long, j As Long If (pos1.x < pos2.x) Then '【スキャンラインを左から右へ描画するために始点と終点を決定する】 poss = pos1: pose = pos2: ps = P1: pe = P2 Else poss = pos2: pose = pos1: ps = P2: pe = P1 End If If pose.x < 0 Then GoTo LE '【終点がx=0より小さいので終了】 Dx = pose.x - poss.x: If Dx <> 0 Then w = 1# / Dx Else w = 0 Dz = (pose.z - poss.z) * w Dr = (pe.Red - ps.Red) * w Dg = (pe.Green - ps.Green) * w Db = (pe.Blue - ps.Blue) * w If poss.x >= 0 Then '【20090928修正】 u = poss.x - Int(poss.x) ' x軸方向微調整分(1画素未満) If u <> 0 Then u = 1 - u ' If u > Dx Then GoTo LE ' 幅を超えているので終了 poss.x = poss.x + u ' 整数座標に合わせる Else ' u = -poss.x ' x軸までスキップする If u > Dx Then GoTo LE ' 幅を超えているので終了 poss.x = 0 ' End If ' poss.z = poss.z + u * Dz ps.Red = ps.Red + u * Dr ps.Green = ps.Green + u * Dg ps.Blue = ps.Blue + u * Db j = CLng(pose.x - poss.x) '【20090928修正】 For i = 0 To j NTL_P.R = CInt(ps.Red) And &HFF NTL_P.G = CInt(ps.Green) And &HFF NTL_P.B = CInt(ps.Blue) And &HFF NTL3D_DrawPixel cg, poss, NTL_P If i = j Then GoTo LE poss.x = poss.x + 1 poss.z = poss.z + Dz ps.Red = ps.Red + Dr ps.Green = ps.Green + Dg ps.Blue = ps.Blue + Db Next i LE: End Sub '########################################################### '###【NTL】3Dカレント・イメージにテクスチャー・マッピングで三角形を描画する '########################################################### Public Sub NTL3D_TriangleWithTextureMapping(cg As NTL3D_BitMapRGB, tx As NTL2D_BitMapRGB, pos1 As x_Vector, uv1 As x_Coords2d, pos2 As x_Vector, uv2 As x_Coords2d, pos3 As x_Vector, uv3 As x_Coords2d) Dim pos(2) As x_Vector, uv(2) As x_Coords2d pos(0) = pos1: pos(1) = pos2: pos(2) = pos3: uv(0) = uv1: uv(1) = uv2: uv(2) = uv3 NTL3D_PolygonWithTextureMapping cg, tx, 3, pos, uv End Sub '########################################################### '###【NTL】3Dカレント・イメージにテクスチャー・マッピングで任意多角形を描画する '########################################################### Public Sub NTL3D_PolygonWithTextureMapping(cg As NTL3D_BitMapRGB, tx As NTL2D_BitMapRGB, n As Long, pos() As x_Vector, uv() As x_Coords2d) Dim Ymax As Single, Ymin As Single, Pmax As Long, Pmin As Long Dim posa1 As x_Vector, posa2 As x_Vector, posb1 As x_Vector, posb2 As x_Vector Dim uva1 As x_Coords2d, uva2 As x_Coords2d, uvb1 As x_Coords2d, uvb2 As x_Coords2d Dim Dxa As Single, Dza As Single, Dua As Single, Dva As Single Dim Dxb As Single, Dzb As Single, Dub As Single, Dvb As Single Dim i As Long, Pa As Long, Pb As Long, Ca As Long, Cb As Long, wa As Single, wb As Single, w As Single Ymax = -NTL3D_Z_max: Ymin = NTL3D_Z_max For i = 0 To n - 1 If (pos(i).y > Ymax) Then Pmax = i: Ymax = pos(i).y End If If (pos(i).y < Ymin) Then Pmin = i: Ymin = pos(i).y End If Next i i = 0: Pa = Pmax: Pb = Pmax: Ca = 0: Cb = 0 GetALine: posa1 = pos(Pa): uva1 = uv(Pa): Pa = Pa + 1: If Pa = n Then Pa = 0 posa2 = pos(Pa): uva2 = uv(Pa): wa = posa2.y - posa1.y: If Abs(wa) = 0 Then wa = 0 Else wa = 1# / wa Dxa = (posa2.x - posa1.x) * wa: Dza = (posa2.z - posa1.z) * wa: Dua = (uva2.u - uva1.u) * wa: Dva = (uva2.v - uva1.v) * wa w = posa1.y - Int(posa1.y): posa1.y = Int(posa1.y): Ca = Abs(posa2.y - posa1.y) '【20090928修正】 posa1.x = posa1.x - Dxa * w: posa1.z = posa1.z - Dza * w: uva1.u = uva1.u - Dua * w: uva1.v = uva1.v - Dva * w If i = 1 Then GoTo L1 If i = 2 Then GoTo L3 GetBLine: posb1 = pos(Pb): uvb1 = uv(Pb): Pb = Pb - 1: If Pb = -1 Then Pb = n - 1 posb2 = pos(Pb): uvb2 = uv(Pb): wb = posb2.y - posb1.y: If Abs(wb) = 0 Then wb = 0 Else wb = 1# / wb Dxb = (posb2.x - posb1.x) * wb: Dzb = (posb2.z - posb1.z) * wb: Dub = (uvb2.u - uvb1.u) * wb: Dvb = (uvb2.v - uvb1.v) * wb w = posb1.y - Int(posb1.y): posb1.y = Int(posb1.y): Cb = Abs(posb2.y - posb1.y) '【20090928修正】 posb1.x = posb1.x - Dxb * w: posb1.z = posb1.z - Dzb * w: uvb1.u = uvb1.u - Dub * w: uvb1.v = uvb1.v - Dvb * w If i = 1 Then GoTo L1 If i = 2 Then GoTo L4 i = 1 L1: If (Ca <= 0) And (Pa <> Pb) Then GoTo GetALine '【20090928修正】 If (Cb <= 0) And (Pa <> Pb) Then GoTo GetBLine '【20090928修正】 If (Ca <= 0) And (Cb <= 0) And (Pa = Pb) Then GoTo LE '【20090928修正】 L2: NTL3D_ScanLineWithTextureMapping cg, tx, posa1, uva1, posb1, uvb1 ' ax = posa1.x: bx = posb1.x: ay = posa1.y: by = posb1.y '【Debug時座標確認用】 L3: If (Ca = 0) And (Pa <> Pb) Then '【20090928修正】 i = 2: GoTo GetALine End If Ca = Ca - 1: posa1.y = posa1.y - 1: posa1.x = posa1.x - Dxa: posa1.z = posa1.z - Dza: uva1.u = uva1.u - Dua: uva1.v = uva1.v - Dva L4: If (Cb = 0) And (Pa <> Pb) Then '【20090928修正】 i = 2: GoTo GetBLine End If Cb = Cb - 1: posb1.y = posb1.y - 1: posb1.x = posb1.x - Dxb: posb1.z = posb1.z - Dzb: uvb1.u = uvb1.u - Dub: uvb1.v = uvb1.v - Dvb GoTo L1 LE: NTL3D_ScanLineWithTextureMapping cg, tx, posa1, uva1, posb1, uvb1 End Sub '########################################################### '###【NTL】3Dカレント・イメージにテクスチャー・マッピングでスキャンラインを描画する '########################################################### Public Sub NTL3D_ScanLineWithTextureMapping(cg As NTL3D_BitMapRGB, tx As NTL2D_BitMapRGB, pos1 As x_Vector, uv1 As x_Coords2d, pos2 As x_Vector, uv2 As x_Coords2d) Dim poss As x_Vector, uvs As x_Coords2d, pose As x_Vector, uve As x_Coords2d, NTL_P As NTL_ColorRGB Dim Dx As Single, Dz As Single, Du As Single, Dv As Single, w As Single, u As Single, i As Long, j As Long If (pos1.x < pos2.x) Then '【スキャンラインを左から右へ描画するために始点と終点を決定する】 poss = pos1: pose = pos2: uvs = uv1: uve = uv2 Else poss = pos2: pose = pos1: uvs = uv2: uve = uv1 End If If pose.x < 0 Then GoTo LE '【終点がx=0より小さいので終了】 Dx = pose.x - poss.x: If Dx <> 0 Then w = 1# / Dx Else w = 0 Dz = (pose.z - poss.z) * w Du = (uve.u - uvs.u) * w Dv = (uve.v - uvs.v) * w If poss.x >= 0 Then '【20090928修正】 u = poss.x - Int(poss.x) ' x軸方向微調整分(1画素未満) If u <> 0 Then u = 1 - u ' If u > Dx Then GoTo LE ' 幅を超えているので終了 poss.x = poss.x + u ' 整数座標に合わせる Else ' u = -poss.x ' x軸までスキップする If u > Dx Then GoTo LE ' 幅を超えているので終了 poss.x = 0 ' End If ' poss.z = poss.z + u * Dz uvs.u = uvs.u + u * Du uvs.v = uvs.v + u * Dv j = CLng(pose.x - poss.x) '【20090928修正】 For i = 0 To j NTL_P = tx.PixelBuffer(CLng(uvs.u), CLng(uvs.v)) NTL3D_DrawPixel cg, poss, NTL_P If i = j Then GoTo LE poss.x = poss.x + 1 poss.z = poss.z + Dz uvs.u = uvs.u + Du uvs.v = uvs.v + Dv Next i LE: End Sub |