2017/03/16(木) [n年前の日記]
#1 [ruby] 3Dモデルデータファイルを読み込んでRubyから使いやすい形に整形するRubyスクリプトを書いた
Ruby + gosu + opengl で実験する際、一々モデルデータを紙に描いて座標を決めて配列にしていくのが面倒臭かったので、Wavefront形式(.obj)の3Dモデルデータファイルを読み込んで、Rubyから使いやすい形に整形して標準出力に出力する Rubyスクリプトを書いてみたり。
_mieki256/tinywavefrontobj
tinywavefrontobj.rb というファイルをダウンロードして実行すれば使える、はず。
Wavefront形式の全ての属性に対応してるわけではないけれど、実験用の頂点配列、法線配列、uv配列、面配列(頂点インデックス配列)をちょこっと作りたい時にはひとまず使える、のではないかなと。
_mieki256/tinywavefrontobj
tinywavefrontobj.rb というファイルをダウンロードして実行すれば使える、はず。
Wavefront形式の全ての属性に対応してるわけではないけれど、実験用の頂点配列、法線配列、uv配列、面配列(頂点インデックス配列)をちょこっと作りたい時にはひとまず使える、のではないかなと。
◎ 使用例その1。 :
例えば、blender でこういうモデルデータを作成して、Wavefront(.obj)形式でエクスポート。
ちなみに、Wavefront形式は、三角形ポリゴンと四角形ポリゴンを混在できるのだけど…。後になってからRubyスクリプト側で、面配列(頂点インデックス配列)のみを眺めてそれぞれ三角ポリゴンか四角ポリゴンかを判別するのはおそらく不可能。故に、エクスポート時に「三角面化」にチェックを入れて、全てのポリゴンを三角ポリゴンにしちゃったほうがいいと思う。
tinywavefrontobj.rb を使って整形出力。
こういう結果が得られる。
ちなみに、Wavefront形式は、三角形ポリゴンと四角形ポリゴンを混在できるのだけど…。後になってからRubyスクリプト側で、面配列(頂点インデックス配列)のみを眺めてそれぞれ三角ポリゴンか四角ポリゴンかを判別するのはおそらく不可能。故に、エクスポート時に「三角面化」にチェックを入れて、全てのポリゴンを三角ポリゴンにしちゃったほうがいいと思う。
tinywavefrontobj.rb を使って整形出力。
ruby tinywavefrontobj.rb sample.obj
こういう結果が得られる。
@vertexes = [ 1.0, -1.0, 0.0, # 0 -1.0, 1.0, 0.0, # 1 -1.0, -1.0, 0.0, # 2 1.0, 1.0, 0.0, # 3 ] @normals = [ 0.0, 0.0, 1.0, # 0 0.0, 0.0, 1.0, # 1 0.0, 0.0, 1.0, # 2 0.0, 0.0, 1.0, # 3 ] @faces = [ 0, 1, 2, # 0 0, 3, 1, # 1 ]これをRubyソースに貼り付ければ実験に使えるだろうと。
◎ jsonやyamlで出力。 :
json や yaml でも出力できる。
Rubyスクリプト側で、例えば以下のような感じで書けば、jsonファイルを読み込んで、頂点配列、法線配列、uv配列、面配列(頂点インデックス配列)を得られる。
ruby tinywavefrontobj.rb sample.obj --json > sample.json
{"vertex":[1.0,-1.0,0.0,-1.0,1.0,0.0,-1.0,-1.0,0.0,1.0,1.0,0.0],"normal":[0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0],"face":[0,1,2,0,3,1]}
ruby tinywavefrontobj.rb sample.obj --yaml > sample.yml
--- vertex: - 1.0 - -1.0 - 0.0 - -1.0 - 1.0 - 0.0 - -1.0 - -1.0 - 0.0 - 1.0 - 1.0 - 0.0 normal: - 0.0 - 0.0 - 1.0 - 0.0 - 0.0 - 1.0 - 0.0 - 0.0 - 1.0 - 0.0 - 0.0 - 1.0 face: - 0 - 1 - 2 - 0 - 3 - 1
Rubyスクリプト側で、例えば以下のような感じで書けば、jsonファイルを読み込んで、頂点配列、法線配列、uv配列、面配列(頂点インデックス配列)を得られる。
require 'json' ... vertex_array = nil normal_array = nil uv_array = nil face_array = nil File.open("sample.json") { |file| hash = JSON.load(file) vertex_array = hash["vertex"] normal_array = hash["normal"] if hash.key?("normal") uv_array = hash["uv"] if hash.key?("uv") face_array = hash["face"] } ... if uv_array puts "use texture" end if normal_array puts "use normal" end
◎ RUbyソース内から呼び出して使う。 :
以下のように書けば、Rubyソース内から呼び出して使うこともできる。
require_relative 'tinywavefrontobj' ... o = TinyWaveFrontObj.new("sample.obj", true, true) vertex_array = o.get_vertex_array normal_array = o.get_normal_array uv_array = o.get_uv_array face_array = o.get_face_array ... if o.use_uv puts "use texture" end if o.use_normal puts "use normal" end
[ ツッコむ ]
以上です。