3D アプリケーション間でデータを交換するためのファイルフォーマットの一つに COLLADA (COLLAborative Design Activity) があります。コンピュータグラフィックスのレンダリングに必要な情報およびその他付随する情報を格納できます。COLLADA の仕様にしたがった XML スキーマファイルの拡張子は通常 .dae
(digital asset exchange) です。3D アプリケーションの例としては以下のようなものがあります。
COLLADA ファイルをプログラミング言語から扱うためのライブラリには以下のようなものがあります。
以下に Debian9 における FreeCAD および pycollada を利用した、COLLADA ファイル (dae ファイル) の簡単な扱い方を記載します。その際、COLLADA のバージョンは 1.5 とします。
v1.5 対応版をインストールするためには以下のようにします。setuptools の setup.py を利用します。
git clone https://github.com/pycollada/pycollada.git
cd pycollada/
git checkout collada15spec
sudo python setup.py install
以下のような場所にインストールされます。
ls /usr/local/lib/python2.7/dist-packages/pycollada-0.4.1-py2.7.egg/
ipython
import collada
collada.__path__
collada.__file__
アンインストール方法は以下のようになります。
sudo python setup.py install --record files.txt
cat files.txt | xargs -I{} sudo rm -rf {}
sudo apt install freecad
meshlab も同様に apt で提供されています。
sudo apt install meshlab
FreeCAD は dae ファイルを操作するために、内部的に pycollada を利用します。
上記手順で既にインストール済みであれば dae ファイルの読み込みおよび書き出しが可能です。
duck_triangles.dae を読み込んでみます。おおよそ以下のような構造をしています。
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset></asset>
<library_cameras></library_cameras>
<library_lights></library_lights>
<library_images></library_images>
<library_materials></library_materials>
<library_effects></library_effects>
<library_geometries>
<geometry id="LOD3spShape-lib" name="LOD3spShape">
<mesh>
<source id="LOD3spShape-lib-positions" name="position"></source>
<source id="LOD3spShape-lib-normals" name="normal"></source>
<source id="LOD3spShape-lib-map1" name="map1"></source>
<vertices id="LOD3spShape-lib-vertices">
<input semantic="POSITION" source="#LOD3spShape-lib-positions"/>
</vertices>
<triangles count="4212" material="blinn3SG">
<input offset="0" semantic="VERTEX" source="#LOD3spShape-lib-vertices"/>
<input offset="1" semantic="NORMAL" source="#LOD3spShape-lib-normals"/>
<input offset="2" semantic="TEXCOORD" source="#LOD3spShape-lib-map1" set="0"/>
<p></p>
</triangles>
</mesh>
</geometry>
</library_geometries>
<library_visual_scenes>
<visual_scene id="VisualSceneNode" name="untitled"></visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#VisualSceneNode"/>
</scene>
</COLLADA>
バージョンは 1.4.1 であることが確認できます。これを読み込む際に指定します。また、pycollada は内部的に NumPy を利用しています。更に、参照できないオブジェクト ID が指定されていたり、pycollada がサポートしていない機能が存在する場合にエラーではなく無視するように設定しています。
from collada import Collada, DaeBrokenRefError, DaeUnsupportedError, set_collada_version, set_number_dtype
import numpy as np
set_collada_version('1.4.1')
set_number_dtype(np.float64)
mesh = Collada('duck_triangles.dae', ignore=[DaeBrokenRefError, DaeUnsupportedError])
ipython で読み込んだ場合の例です。形状 geometries 情報が一つ格納されている DAE ファイルであることが分かります。
In [2]: mesh
Out[2]: <Collada geometries=1, articulated_systems=0, kinematics_models=0>
形状 geometry は三角形となっています。フェイスとして三角形が利用されている mesh ということになります。
In [3]: mesh.geometries
Out[3]: [<Geometry id=LOD3spShape-lib, 1 primitives>]
In [6]: mesh.geometries[0].primitives
Out[6]: [<TriangleSet length=4212>]
In [7]: triset = mesh.geometries[0].primitives[0]
ファイル作成日時や作者、単位、軸の向き
mesh.filename #=> 'duck_triangles.dae'
mesh.assetInfo.contributors[0].author
mesh.assetInfo.contributors[0].authoring_tool
mesh.assetInfo.created #=> datetime.datetime(2006, 8, 23, 22, 29, 59, tzinfo=tzutc())
mesh.assetInfo.modified
mesh.assetInfo.unitname #=> 'centimeter'
mesh.assetInfo.unitmeter #=> 0.01
mesh.assetInfo.upaxis #=> 'Y_UP'
library_xxx
へのアクセス
mesh.cameras
mesh.lights
mesh.images[0] #=> <CImage id=file2 path=./duckCM.tga>
mesh.materials
mesh.effects
mesh.geometries
mesh.scenes[0] # == mesh.scene
形状 geometries から三角形フェイスの set を取得
mesh.geometries #=> [<Geometry id=LOD3spShape-lib, 1 primitives>]
mesh.geometries[0].primitives #=> [<TriangleSet length=4212>]
triset = mesh.geometries[0].primitives[0]
len(triset) #=> 4212
三角形フェイスの集合は、こちらのページに記載した場合と同様に、頂点座標や頂点法線の情報をソースとして持ちます。
triset.sources['VERTEX'] #=> [(0, 'VERTEX', '#LOD3spShape-lib-positions', None, <FloatSource size=2108>)]
triset.sources['NORMAL'] #=> [(1, 'NORMAL', '#LOD3spShape-lib-normals', None, <FloatSource size=2290>)]
len(triset.vertex) #=> 2108
len(triset.normal) #=> 2290
それらソースは一つ以上の三角形フェイスから参照されます。各フェイスが参照する頂点座標や頂点法線の情報を格納したインデックスが以下の二つです。
len(triset) #=> 4212
len(triset.vertex_index) #=> 4212
len(triset.normal_index) #=> 4212
インデックスを用いて、各三角形フェイスが利用する三つの頂点座標、および各頂点の頂点法線ベクトルを取得できます。
triset.vertex[triset.vertex_index][0]
array([[-23.9364, 11.5353, 30.6125], #=> (x,y,z)
[-18.7264, 10.108 , 26.6814], #=> (x,y,z)
[-15.6992, 11.4278, 34.2321]]) #=> (x,y,z)
triset.normal[triset.normal_index][0]
array([[-0.192109, -0.934569, 0.299458], #=> 長さ1
[-0.06315 , -0.993623, 0.093407], #=> 長さ1
[-0.11695 , -0.921313, 0.370816]]) #=> 長さ1