mqoをjsonっぽくするコンバータ
Firefox3.0からOpenGLが使えるらしい
JavaScriptで3D描画―ネットアプリの常識変える?:Firefox 3.0で搭載へ - ZDNet Japan
ということはjavascriptから使える3Dデータフォーマットが必要だと思い、mqoファイルをjsonっぽくするコンバータを作ってみました。
Mayaにもpythonが搭載されたことだし、勉強も兼ねてpythonで。
mqo2json.py
# vim: fileencoding=utf-8 """ mqo > json のコンバータ Objectチャンクのvertexチャンクとfaceチャンクのみ対応 faceにmaterialIndexとかtextureCoordとか入っているけどMaterialチャンクに対応していないので意味無し mqoファイルは綺麗なテキストになってないと上手くコンバートできません BVertexチャンクあるとマズイかも… mqoファイルのフォーマットについては http://www.metaseq.net/ を参照させていただきました """ import re, sys #----------------------------- class Vertex(object): """ Vertexクラス 頂点情報を格納 """ def __init__( self ): self.x = 0.0 self.y = 0.0 self.z = 0.0 def setXYZ( self, x, y, z ): self.x = x self.y = y self.z = z return self def setFromList( self, list ): self.x = list[0] self.y = list[1] self.z = list[2] return self def toList( self ): return [ self.x, self.y, self.z ] def toJsonStr( self ): return '[ ' + str(self.x) + ', ' + str(self.y) + ', ' + str(self.z) + ' ]' #----------------------------- class Face(object): """ Faceクラス 面情報を格納 vertexIndex : 面を形成する頂点のインデックス materialIndex : 面のマテリアルのインデックス textureCoord : テクスチャのUV座標 """ def __init__( self ): self.vertexIndex = None self.materialIndex = -1 self.textureCoord = None def toJsonStr( self ): return '{ "vertexIndex" : [' + ",".join( [str(s) for s in self.vertexIndex] ) + '], "materialIndex" : ' + str(self.materialIndex) + ', "textureCoord" : [' + ",".join( [str(s) for s in self.textureCoord] ) + '] }' #----------------------------- class Mesh(object): """ Meshクラス mqoファイルでいうところのObjectチャンク相当 vertexとfaceしかもっていません """ def __init__( self ): self.vertices = [] self.faces = [] self.name = "unknown" def create( self, chunk ): objNameReg = re.compile(r'"(?P<name>([\w]+))"') m = objNameReg.search( chunk.head ) if m != None: self.name = m.group("name") for child in chunk.children: if child.type == "vertex": self.parseVertexChunk( child ) elif child.type == "face": self.parseFaceChunk( child ) return self def parseVertexChunk( self, chunk ): for d in chunk.data: vtx = Vertex() vtx.setFromList( [ float(s) for s in d.split() ] ) self.vertices.append( vtx ) return self.vertices def parseFaceChunk( self, chunk ): sizeReg = re.compile(r"^(?P<size>([-+]?\d+))") vtxIdxReg = re.compile(r"V\((?P<indices>([^\)]+))\)") matReg = re.compile(r"M\((?P<index>([^\)]+))\)") texCoordReg = re.compile(r"UV\((?P<texCoord>([^\)]+))\)") for d in chunk.data: m = sizeReg.search(d) if m != None: f = Face() m = vtxIdxReg.search(d) if m != None: f.vertexIndex = tuple( [ int(s) for s in m.group("indices").split() ] ) m = matReg.search(d) if m != None: f.materialIndex = int(m.group("index")) m = texCoordReg.search(d) if m != None: f.textureCoord = tuple( [ float(s) for s in m.group("texCoord").split() ] ) self.faces.append(f) return self.faces def toJsonStr( self ): result = '{\n' result += '"name" : "' + self.name + '",\n' result += '"vertex" : [\n' result += ',\n'.join( [ v.toJsonStr() for v in self.vertices ] ) result += '\n],\n' result += '"face" : [\n' result += ',\n'.join( [ f.toJsonStr() for f in self.faces ] ) result += '\n]\n' result += '}' return result #----------------------------- class Chunk(object): """ Chunkクラス mqoファイルのチャンク """ def __init__( self ): self.type = "" self.data = [] self.children = [] self.head = "" self.tail = "" #----------------------------- class MQO(object): """ MQOクラス mqoファイル loadでmqoファイルをロード saveでデータをjson形式でセーブ """ def __init__( self ): self.filepath = "" self.meshes = [] def load( self, path ): self.filepath = path f = open( path ) topLevelChunks = self.parseChunk( f.readlines() ) f.close() for chunk in topLevelChunks: if chunk.type == "Object": m = Mesh() m.create( chunk ) self.meshes.append( m ) def parseChunk( self, lines ): chkStartReg = re.compile(r"(?P<type>(^[\w]+))[^{]+{") chkEndReg = re.compile(r"}$") result = [] stack = [] for l in lines: l = l.strip() sm = chkStartReg.search(l) em = chkEndReg.search(l) if sm != None: chk = Chunk() chk.type = sm.group("type") chk.head = l stack.append(chk) elif em != None: chk = stack.pop() chk.tail = l if len(stack) == 0: result.append(chk) else: stack[-1].children.append(chk) else: if len(stack) != 0: stack[-1].data.append(l) return result def save( self, path, sceneName ): f= open( path, "w" ) jsonStr = sceneName + ' = {\n' jsonStr += '"meshes" : [\n' jsonStr += ',\n'.join( [ m.toJsonStr() for m in self.meshes ] ) jsonStr += '\n]\n' jsonStr += '}' f.write( jsonStr ) f.close() #----------------------------- if __name__ == "__main__": mqo = MQO() mqo.load( sys.argv[1] ) mqo.save( sys.argv[2], sys.argv[3] )
まだまだ勉強不足故に見苦しいコード…
jsonのテキスト作るあたりが特に…
使い方
python mqo2json.py hoge.mqo hoge.js hoge
みたいな感じで使えます。
テスト
ちゃんと出来てるかどうか確かめるために、以前作ったcanvasオブジェクトのヤツをちょろっと書き換え。
元データはhttp://nanoha.kirara.st/3dcg/のアップローダから、はちゅねミクのデータを使わせていただきました。
ポリ数2000ちょいのワイヤーフレーム。
注意:以下のページは自前描画なので激重です(IEだと特に!)
っていうかcolladaでいいんじゃね?
collada(COLLADA Overview - The Khronos Group Inc)ってxmlじゃね?
DOMで使えるんじゃね?
コレ意味なくね?
orz
まぁ、それはそれとして
3DかじってるプログラマとしてはOpenGL搭載は結構楽しみ。
ライティングとかテクスチャマッピングとかできるようになるのかなー。
スキニングとかアニメーションもしたいなー。
プログラマブルシェーダもできるといいなー。