Maya のシミュレート 4

シンプルなモデリングツール 4

シンプルなモデリングツール 2 にTimeノードを追加して、アニメーションデータを作成できるようにしてみます。

以下のスクリプトでは、Timeノードの追加以外に以下の変更を加えています。

  1. 以下のPythonスクリプトをnmaya4.pyというファイル名で保存します。
    import sys
    import copy
    
    class ObjectSet(object):
        def __init__(self, sobjs=None):
            self.objs = []
            self.saveobjs = sobjs
    
        def setObj(self, obj):
            self.objs.append(obj)
    
        def save(self, fn):
            if not self.saveobjs:
                return
            self.saveobjs(self.objs, fn)
    
    
    class Point(object):
        def __init__(self, x=0, y=0):
            self.x = x
            self.y = y
    
    
    class TriPoly(object):
        def __init__(self, p1, p2, p3):
            self.p = [[p1, p2, p3]]
    
    
    class Observer(object):
        def __init__(self):
            self.observer = {}
    
        def append(self, src, node, dest):
            if self.observer.has_key(src):
                self.observer[src].append([node, dest])
            else:
                self.observer[src] = [[node, dest]]
    
        def get(self, src):
            if self.observer.has_key(src):
                return self.observer[src]
            return {}
    
        def delete(self, src, node, dest):
            if not self.observer.has_key(src):
                return
            nlist = []
            for nd in self.observer[src]:
                if node is nd[0] and src is nd[1]:
                    continue
                nlist.append(nd)
            self.observer[src] = nlist
    
    
    class Nodebase(object):
        def __init__(self, attr={}):
            self.attr = copy.copy(attr)
            self.observer = Observer()
    
        def _update(self, node, src, dest):
            if node != self:
                self.setAttr(dest, node.getAttr(src))
            self.compute()
    
        def _notify_observers(self, src):
            for node,dest in self.observer.get(src):
                node._update(self, src, dest)
    
        def compute(self):
            pass
    
        def attributeAffects(self, src, dest):
            self.connectAttr(src, self, dest)
    
        def connectAttr(self, src, node, dest):
            self.observer.append(src, node, dest)
            self._notify_observers(src)
    
        def getAttr(self, aname):
            return copy.deepcopy(self.attr[aname])
    
        def setAttr(self, aname, val):
            self.attr[aname] = val
            self._notify_observers(aname)
    
        def addAttr(self, aname, default=0.0):
            self.attr[aname] = default
    
    
    class MakeTriPoly(Nodebase):
        def __init__(self):
            tp = TriPoly(Point(0, 0), Point(0, 1), Point(1, 0))
            attr = {'out': tp}
            super(MakeTriPoly, self).__init__(attr)
    
    
    class MoveTriPoly(Nodebase):
        def __init__(self, n=0, x=0.0, y=0.0):
            attr = {'in': None, 'out': None, 'num': n, 'mx': x, 'my': y}
            super(MoveTriPoly, self).__init__(attr)
            self.attributeAffects('num', 'out')
            self.attributeAffects('mx', 'out')
            self.attributeAffects('my', 'out')
            self.attributeAffects('in', 'out')
    
        def compute(self):
            tp = self.getAttr('in')
            if not tp :
                return
            f = tp.p[0]
            num = self.getAttr('num')
            f[num].x += self.getAttr('mx')
            f[num].y += self.getAttr('my')
            self.setAttr('out', tp)
            self._notify_observers('out')
    
    
    class Shape(Nodebase):
        objset = None
        def __init__(self):
            if self.objset:
                self.objset.setObj(self)
            attr = {'in': None, 'out': None}
            super(Shape, self).__init__(attr)
            self.attributeAffects('in', 'out')
    
        def compute(self):
            tp = self.getAttr('in')
            self.setAttr('out', tp)
            self._notify_observers('out')
    
    
    class Time(Nodebase):
        def __init__(self):
            attr = {'outTime': 0}
            super(Time, self).__init__(attr)
    
    
    def saveAllObjs(objs, fn):
        fp = open(fn, 'w')
        n = 0
        for o in objs:
            fp.write('g tri' + str(n) + '\n')
            fs = o.getAttr('out')
            for p in fs.p:
                fp.write('vn 0 1 0\n')
                fp.write('v ' + str(p[0].x) +  ' 0 ' + str(p[0].y) + '\n')
                fp.write('v ' + str(p[1].x) +  ' 0 ' + str(p[1].y) + '\n')
                fp.write('v ' + str(p[2].x) +  ' 0 ' + str(p[2].y) + '\n')
                face = 'f '
                for i in range(1, 4):
                    face += str(3*n+i) + '//' + str(n+1) + ' '
                face += '\n'
                fp.write(face)
            n += 1
        fp.close()
    
    
    Shape.objset = ObjectSet(saveAllObjs)
    
    time1 = Time()
    
    def saveAnimData(s, e, fn):
        for f in range(s, e+1):
            time1.setAttr('outTime', f)
            Shape.objset.save(fn + str(f) + '.obj')
    
    execfile(sys.argv[1])
    
  2. 以下のPythonスクリプトを作成し、spoly7.pyというファイル名で保存します。
    m1 = MakeTriPoly()
    mv1 = MoveTriPoly(0)
    m1.connectAttr('out', mv1, 'in')
    mv2 = MoveTriPoly(1)
    mv1.connectAttr('out', mv2, 'in')
    mv3 = MoveTriPoly(2)
    mv2.connectAttr('out', mv3, 'in')
    s1 = Shape()
    mv3.connectAttr('out', s1, 'in')
    
    time1.connectAttr('outTime', mv1, 'mx')
    time1.connectAttr('outTime', mv2, 'mx')
    time1.connectAttr('outTime', mv3, 'mx')
    
    saveAnimData(1, 3, "tmp")
    
  3. シェル上で、以下のコマンドを実行します。
    % python nmaya4.py spoly7.py
  4. tmp1.obj, tmp2.obj, tmp3.obj という3つのファイルが作成されます。
    tmp1.obj が1フレーム目、 tmp2.obj が2フレーム目、 tmp3.obj が3フレーム目のデータです。
  5. Maya上で、 ファイル → インポート によって tmp1.obj, tmp2.obj, tmp3.obj を読み込みます。
    3つの三角ポリゴンが表示されます。

ノードの追加

後からnmaya4.py にノードを追加したいときは、Nodebaseを親クラスとするクラスを作成し、必要なメソッドを上書きします。

練習問題

参考


Prev
Home | Contents
Mail