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だと特に!)

http://www.geocities.jp/anderson_luis_de_souza/mqo2json/

っていうかcolladaでいいんじゃね?

colladaCOLLADA Overview - The Khronos Group Inc)ってxmlじゃね?
DOMで使えるんじゃね?
コレ意味なくね?

orz

まぁ、それはそれとして

3DかじってるプログラマとしてはOpenGL搭載は結構楽しみ。
ライティングとかテクスチャマッピングとかできるようになるのかなー。
スキニングとかアニメーションもしたいなー。
プログラマブルシェーダもできるといいなー。

プラグインとスクリプト間の値のやりとりメモ

Photoshopスクリプトプラグインのようにパラメータ込みでアクションに記録する方法が分からないので、仕方なくAutomationPluginと組み合わせて力技でアクションに記録できるようにしているのだけど…何かスマートじゃない。

プラグインスクリプト間の値の受け渡しも、それらしき機構が用意されていないっぽいので仕方なくテンポラリにiniファイルみたいなテキスト形式のフォーマットでっち上げて一時ファイルとして吐かせて読み書きする、という泥臭い状態に…。


せめて値のやり取りだけでもスマートにしたいってことでJSON形式を使ってみることに。

スクリプトjavascriptだから問題ないけど、プラグイン側はC++なのでパーサ必要だよなーと思って探してみたら結構あった。


とりあえず良さげなやつ2つ。

http://www.codeproject.com/cpp/JSON_Spirit.asp
json-cpp download | SourceForge.net


テキトーにサンプル作って動かしてみたら、期待通りに動いてくれたので、過去に作ったプラグインとかチマチマと修正。

スクリプトプラグイン両方ともちょっとだけコードが綺麗になって満足。

今更canvasオブジェクト

普段はブラウザのjavascriptなんて全く触らないんだけど、もしかしたら少しやることになるかもしれないので必要そうなモノをチマチマと調べてみる。

んで今更ながらcanvasオブジェクトなるものの存在を知ったので、むか〜し作って絶望したヤツをcanvasIE互換にしてくれるらしいライブラリExplorerCanvas download | SourceForge.netを使ってちょろっと書き直してみた。

http://www.geocities.jp/anderson_luis_de_souza/canvastest/canvastest.html

Firefoxだと思ったより速い。
IEだと妙に遅いけど使い方間違ってるんかな…。



世の中には凄い人もいる。

レイトレ
http://journal.mycom.co.jp/articles/2007/03/19/flog/index.html

ウォークスルー?
Untitled Film Works | Professional Film Makers

テクスチャ付きウォークスルー?
Untitled Film Works | Professional Film Makers



というかブラウザのjavascriptは大変そうだ。
prototypeとかブラウザ依存とか名前汚染とか関数言語的な考え方とか…
C言語脳な俺にはムズカシーorz

PhotoshopのjavascriptでピクセルのRGB値を取得する方法があった

Photoshopjavascriptには直接ピクセルのRGBを取得できるようなオブジェクトが用意されていないので無理やりやらないといけない。
以下転載。

getColorAt = function(doc, x, y) {

   function selectBounds(doc, b) {
      doc.selection.select([[ b[0], b[1] ],
                           [ b[2], b[1] ],
                           [ b[2], b[3] ],
                           [ b[0], b[3] ]]);
   }
    function findPV(h) {
      for (var i = 0; i <= 255; i++ ) {
        if (h[i]) { return i; }
      }
      return 0;
    }

   selectBounds(doc, [x, y, x+1, y+1]);
    var pColour = new SolidColor();
   
    pColour.rgb.red   = findPV(doc.channels["Red"].histogram);
    pColour.rgb.green = findPV(doc.channels["Green"].histogram);
    pColour.rgb.blue  = findPV(doc.channels["Blue"].histogram);

   doc.selection.deselect(); // or, even better, undo
};

転載元はココ。
http://www.ps-scripts.com/bb/viewtopic.php?t=411


Photoshopjavascriptは便利なんだけど地味に痒いところに手が届いてないので困る。
1ピクセル選択してチャンネルのヒストグラム調べるとかどんだけー

EffectのRenderメソッドをシングルスレッドで実行する方法

public SampleEffect()
    : base("Text3D", null, "sub menu", PaintDotNet.Effects.EffectDirectives.SingleThreaded, true)
{
}

派生クラスでベースクラスのコンストラクタを呼ぶときにEffectDirectivesの値をSingleThreadedにすればRenderメソッドがシングルスレッドで呼ばれるっぽい。
当然のことながら重い処理をする場合はレスポンスが悪くなる。
プレビューを自分で組む場合やプレビューしなくてもいい場合はこっちのがいいのかな?

Paint.NETのプラグインを作ってみた

http://www.getpaint.net/

マイクロソフトが開発を支援してるらしきペイントソフト。
ソースが公開されていて、C#メインで作られてる。


従来どおり、この手のソフトはプラグインで機能拡張できるので、とりあえずハイトマップ→ノーマルマップ変換Effectプラグインを作ってみた。

http://www.geocities.jp/anderson_luis_de_souza/


インストールしたディレクトリにあるPaintDotNet.Effects.dllとかが外部公開向けのアセンブリで、こいつらにプラグインの基底クラスが入っている。
それらを派生して実装すればプラグインができる。


プラグイン作成向けのドキュメントが見当たらなかったので、簡単にメモ

  • Effectプラグインの本体はPaintDotNet.Effects.Effectを継承して実装。Renderメソッドが肝
  • プラグインのパラメータを操作するダイアログはPaintDotNet.Effects.EffectConfigDialogを継承して実装
  • プラグインのパラメータはPaintDotNet.Effects.EffectConfigTokenを継承して実装。こいつでダイアログとプラグイン本体間のパラメータのやりとりをする
  • PaintDotNet.Effects.Effect.RenderはPaint.NET本体から別スレッドで呼ばれるっぽいのでスレッドセーフにしておかないとダメ


最後のスレッドセーフ云々はRenderArgsのSurfaceを直に弄る分には意識しなくても大丈夫っぽいけど、GDIのGraphics経由で弄るならlock(dstArgs.Graphics)としておかないと実行時に落ちるので注意。


大体こんなところかなー。

はてな開始

自分用のメモをカテゴライズして残しておきたい衝動に駆られたので、はてな開始。
とりあえず使いそうな記法テスト。

小見出し

テキスト

小見出し

テキスト


ソース

class CTest
{
public:
  int _value;
};


アマゾン

VOCALOID2 HATSUNE MIKU

VOCALOID2 HATSUNE MIKU


リンク
Yahoo! JAPAN


引用

グーグル先生

http://www.google.co.jp/webhp?hl=ja