ousttrue / pymeshio

3d model reader/writer for python
http://pypi.python.org/pypi/pymeshio/
92 stars 26 forks source link

BUG (export_pmd/export_pmx) : morph problem on scaled object #7

Closed griffon-9 closed 12 years ago

griffon-9 commented 12 years ago

ShapeKeyを持つMeshオブジェクトを拡大・縮小してApply Scaleしないままでエクスポートした場合、頂点モーフの頂点の移動量がおかしくなる問題があります。 PMDエディタで挙動を観察すると、モーフ変形する前の初期状態の頂点データとしてはScaleした後のMeshオブジェクトの状態が出力され、モーフ変形のオフセット量としてはScaleする前のMeshオブジェクトの状態が出力されているように見えました。 Scaleの影響のしかたが異なっているのは気持ちが悪いので、利便性の向上も兼ねてScaleした後の状態でモーフも出力できるようにするコードを作成させていただきました。

コード差分は元々のExporterの設計変更と新規追加コードとから構成されます。

まず、元々のコードに対する設計変更について説明します。 要点としてはOneSkinMeshクラス内における skin()メソッドの呼び出しタイミング変更と言うことになります。 元の実装では mesh()メソッドが内部で入力Meshオブジェクトを複製し、複製されたオブジェクトを処理するようになっていたため、結果的に mesh()メソッドと skin()メソッドとが別々のMeshオブジェクトを処理している状態になっていたと思います。 この状態では本件の問題の対策を行うのは容易でないように思えましたので、 skin()メソッドを mesh()メソッドの中から呼び出すように変更し、 __ mesh()メソッドが複製したMeshオブジェクトを処理するようにしました。

次に新規追加コードですが、重要なのは下記の部分です。

                matrix=obj.matrix_world
                for key in copyMesh.shape_keys.key_blocks:
                    for point in key.data:
                        point.co=matrix*point.co

Blenderの内部でShapeKeyがどのように保持されているのかは理解していないのですが、挙動からするとMeshクラスのtransform()メソッドではShapeKeyの各頂点の位置が座標変換されないままになっているように思えましたので、直接座標変換するコードを追加してしまいました。 私の環境ですと、このコードの追加で今のところ上手く動いています。

最後に、本件の問題の再現方法ですが、かなり強引な方法ではありますが「初音ミクVer2」をimport_pmdでインポートした後で縮小し、そのままexport_pmdでエクスポートしてPMDエディタで変形確認するという方法があります。縮小して出力すると、モーフの変形量が縮小前のままになっているせいで極端な変形となり、モーフがおかしくなっていることを容易に確認できるはずです。