blenderで作ったボーンのアニメーションつきデータをPapervision3Dで表示

Dycoon2010-09-19

ちょっと急ぎでFlash上で3Dを表示しなければいけない状態になった
と思ったらそうでもなくなったのですが、
blenderで作ったボーンのアニメーションつきデータをPapervision3Dで表示させてみました。

blenderは2.49bを使ったいました。
このバージョンまでのColladaエクスポーターだと
ボーンのアニメーションをPapervision3Dで読み込むことができないもようです。
(いろんなところで最終的にあきらめている様子)
(補間がLinearなのがいけないのだろうか?と思っているが原因は究明していない)
blenderでfbxを出力してから以下においてある
http://usa.autodesk.com/adsk/servlet/pc/item?siteID=123112&id=10775855
FBX 2011.3 Converter for WindowsColladaを出力させると
ボーンアニメーションが表示されるようになった代わりに
テクスチャーが表示されなくなってしまいました。
ただ、これをPapervision3Dで表示されるように修正するのは比較的簡単であったので
方法を書いておきます。

とりあえず、表示しているFlashはこちら
http://www.rmake.net/dycoon/files/papervisionsample/index.html

ソースコードやデータなどのファイル一式は以下においてあります。
http://www.rmake.net/dycoon/files/papervisionsample/PapervisionSample.zip

Papervision3DのライブラリはPapervision3D_2.1.932.swcを使いました。
http://code.google.com/p/papervision3d/downloads/detail?name=Papervision3D_2.1.932.swc&can=2&q=


詳細は以下のとおりです。

このデータの場合
書き換える場所はまずここら辺と

...
  <library_images>
    <image name='testmirror_body_tga' id='testmirror_body_tga-image'>
      <init_from>testmirror_body.png</init_from><!-- パスとかを削除します -->
    </image>
...
  </library_images>
...

ここら辺

    <effect name='Grey__testmirror_face_tga' id='Grey__testmirror_face_tga-fx'>
      <profile_COMMON>
        <technique sid='standard'>
          <lambert>
            <emission>
              <color sid='emission'>0.224032  0.226426 0.224032 1.000000</color>
            </emission>
            <ambient>
              <color sid='ambient'>0.000000  0.000000 0.000000 1.000000</color>
            </ambient>
            <diffuse>
              <texture texcoord='CHANNEL1' texture='testmirror_face_tga-sampler'/><!-- ここをテクスチャーからとってくるように -->
            </diffuse>
            <transparent>
              <color sid='transparent'>1.000000  1.000000 1.000000 1.000000</color>
            </transparent>
            <transparency>
              <float sid='transparency'>0.000000</float>
            </transparency>
          </lambert>
        </technique>
<!-- ここから -->
        <newparam sid='testmirror_face_tga-surface'>
          <surface type='2D'>
            <init_from>testmirror_face_tga-image</init_from>
            <format>A8R8G8B8</format>
          </surface>
        </newparam>
        <newparam sid='testmirror_face_tga-sampler'>
          <sampler2D>
            <source>testmirror_face_tga-surface</source>
            <minfilter>LINEAR_MIPMAP_LINEAR</minfilter>
            <magfilter>LINEAR</magfilter>
          </sampler2D>
        </newparam>
<!-- ここまでを追加 -->
      </profile_COMMON>
    </effect>

でした。
あまりいろいろな条件で試していないので(というかこのデータでしか試していない)
これ以外に何かおこなう必要がある場合もあるかもしれません。

一応この変換を自動でおこなう、rubyスクリプトは以下のような感じです。
(ファイル一式にも含まれています。)
bin/data/cvt.rb

# Written by Kuroda Daisuke(Dycoon).
# This file is PUBLIC DOMAIN.

require "rexml/document"
include REXML


#
fname = ARGV[0]

f = open(fname, 'r')
doc = f.read.to_s
f.close

#print doc

#
xmldoc = REXML::Document.new(doc)


elems = xmldoc.elements

images = []

elems.each("COLLADA/library_images/image"){|i|
  print "#{i.attributes["name"]}\n"

  images.push(i.attributes["name"])
}

elems.each("COLLADA/library_images/image/init_from"){|i|
  print "#{i.text}\n"

  i.text = i.text.gsub("file://", "")
  i.text = i.text.gsub(".tga", ".png")

  print "#{i.text}\n"
}

pat = "(" + images.join(")|(") + ")"
print "pat = #{pat}\n"
pat = Regexp.new(pat)

elems.each("COLLADA/library_effects/effect"){|i|
  mch = pat.match(i.attributes["name"])
  if mch
    e = i.elements
    e.each("profile_COMMON"){|j|
      #
      newparam = Element.new("newparam")
      newparam.attributes["sid"] = mch[0] + "-surface"
      
      surface = Element.new("surface")
      surface.attributes["type"] = "2D"

      init_from = Element.new("init_from")
      init_from.text = mch[0] + "-image"

      _format = Element.new("format")
      _format.text = "A8R8G8B8"

      surface.add_element(init_from)
      surface.add_element(_format)

      newparam.add_element(surface)

      j.add_element(newparam)

      #
      newparam = Element.new("newparam")
      newparam.attributes["sid"] = mch[0] + "-sampler"

      sampler2D = Element.new("sampler2D")

      source = Element.new("source")
      source.text = mch[0] + "-surface"

      minfilter = Element.new("minfilter")
      minfilter.text = "LINEAR_MIPMAP_LINEAR"

      magfilter = Element.new("magfilter")
      magfilter.text = "LINEAR"

      sampler2D.add_element(source)
      sampler2D.add_element(minfilter)
      sampler2D.add_element(magfilter)

      newparam.add_element(sampler2D)

      j.add_element(newparam)

      j.elements.each("technique/lambert/diffuse"){|k|
        k.elements.delete_all("color")

        texture = Element.new("texture")
        texture.attributes["texcoord"] = "CHANNEL1"
        texture.attributes["texture"] = mch[0] + "-sampler"

        k.add_element(texture)
      }

    }
  end
}

#
fname = ARGV[1]

f = open(fname, 'w')
f.binmode
f.write xmldoc.to_s
f.close

あと、足のアニメーションはIKでおこなっているのですが
エクスポートするファイルによってはFKにプロットしない感じだったので
(fbxエクスポーターはFKにプロットするようです。)
FKにプロットするプラグインを書きました。
(これもファイル一式に入っています。)
plotmotion/plotmotion.py
を見てください。