モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

工作HardwareHub ロゴ画像 (Laptop端末利用時)
工作HardwareHub ロゴ画像 (Mobile端末利用時)
目次目次を開く/閉じる

COLLADA ファイルの扱い方 (.dae file)

モーダルを閉じる

ステッカーを選択してください

モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2018/10/16
最終更新最終更新
2023/12/17
記事区分記事区分
一般公開

目次

    アカウント プロフィール画像 (サイドバー)

    組み込みエンジニア

    0
    ステッカーを贈るとは?

    3D アプリケーション間でデータを交換するためのファイルフォーマットの一つに COLLADA (COLLAborative Design Activity) があります。コンピュータグラフィックスのレンダリングに必要な情報およびその他付随する情報を格納できます。COLLADA の仕様にしたがった XML スキーマファイルの拡張子は通常 .dae (digital asset exchange) です。3D アプリケーションの例としては以下のようなものがあります。

    COLLADA ファイルをプログラミング言語から扱うためのライブラリには以下のようなものがあります。

    以下に Debian9 における FreeCAD および pycollada を利用した、COLLADA ファイル (dae ファイル) の簡単な扱い方を記載します。その際、COLLADA のバージョンは 1.5 とします。

    インストール

    pycollada

    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 {}
    

    FreeCAD

    Debian の場合は apt でインストールできます

    sudo apt install freecad
    

    meshlab も同様に apt で提供されています。

    sudo apt install meshlab
    

    dae ファイルを読み込むための pycollada 設定

    FreeCAD は dae ファイルを操作するために、内部的に pycollada を利用します。

    上記手順で既にインストール済みであれば dae ファイルの読み込みおよび書き出しが可能です。

    duck_polylist.dae

    pycollada サンプルコード

    読み込み

    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
    

    立方体の作成サンプル

    立方体の各面は三角形フェイス二つで表現できるため、立方体の表現に必要なフェイス数は 2 x 6 で 12 です。

    import collada
    import numpy as np
    
    # 空のメッシュを作成
    mesh = collada.Collada()
    
    ##### mesh.geometries
    
    # 立方体の 8 頂点 (x,y,z) → 8 x 3 = 24
    vert_floats = [-50,50,50,50,50,50,-50,-50,50,50,-50,50,-50,50,-50,50,50,-50,-50,-50,-50,50,-50,-50]
    
    # 頂点法線ベクトル (x,y,z) を 8 頂点それぞれに対して向き 3 つ分用意 → 3 x 8 x 3 = 72
    normal_floats = [0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1]
    
    # 頂点座標と頂点法線をソースとして登録
    vert_src = collada.source.FloatSource("cubeverts-array", np.array(vert_floats), ('X','Y', 'Z'))
    normal_src = collada.source.FloatSource("cubenormals-array", np.array(normal_floats), ('X', 'Y', 'Z'))
    
    # id `geometry0`, name `mycube` の geometry をソース情報を含めて新規作成
    geom = collada.geometry.Geometry(mesh, "geometry0", "mycube", [vert_src, normal_src])
    
    # 作成した geometry をもとにフェイス情報 triset を新規作成
    input_list = collada.source.InputList()
    input_list.addInput(0, 'VERTEX', "#cubeverts-array")
    input_list.addInput(1, 'NORMAL', "#cubenormals-array")
    indices = np.array([0,0,2,1,3,2,0,0,3,2,1,3,0,4,1,5,5,6,0,4,5,6,4,7,6,8,7,9,3,10,6,8,3,10,2,11,0,12,4,13,6,14,0,12,6,14,2,15,3,16,7,17,5,18,3,16,5,18,1,19,5,20,7,21,6,22,5,20,6,22,4,23])
    triset = geom.createTriangleSet(indices, input_list, "materialref")
    
    # geometry にフェイス情報 triset を追加
    geom.primitives.append(triset)
    
    # mesh に geometry を追加
    mesh.geometries.append(geom)
    
    ##### mesh.effects, mesh.materials
    
    # 簡単のため Phong の反射モデルを利用するように設定
    effect = collada.material.Effect("effect0", [], "phong", diffuse=(1,0,0), specular=(0,1,0))
    
    # id `material0`, name `mymaterial` として material を新規作成
    mat = collada.material.Material("material0", "mymaterial", effect)
    
    # mesh に effect と material を追加
    mesh.effects.append(effect)
    mesh.materials.append(mat)
    
    ##### scene の設定
    
    # scene を作成
    matnode = collada.scene.MaterialNode("materialref", mat, inputs=[])
    geomnode = collada.scene.GeometryNode(geom, [matnode])
    node = collada.scene.Node("node0", children=[geomnode])
    myscene = collada.scene.Scene("myscene", [node])
    
    # scene リストへの追加および既定値の設定
    mesh.scenes.append(myscene)
    mesh.scene = myscene
    
    # ファイルへの書き出し
    mesh.write('/tmp/test.dae')
    

    作成結果例 test.dae

    <COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
      <asset>
        <created>2018-10-21T00:20:01.203446</created>
        <modified>2018-10-21T00:20:01.203468</modified>
        <up_axis>Y_UP</up_axis>
      </asset>
      <library_effects>
        <effect name="effect0" id="effect0">
          <profile_COMMON>
            <technique sid="common">
              <phong>
                <emission>
                  <color>0 0 0 1</color>
                </emission>
                <ambient>
                  <color>0 0 0 1</color>
                </ambient>
                <diffuse>
                  <color>1 0 0 1</color>
                </diffuse>
                <specular>
                  <color>0 1 0 1</color>
                </specular>
                <shininess>
                  <float>0</float>
                </shininess>
                <reflective>
                  <color>0 0 0 1</color>
                </reflective>
                <reflectivity>
                  <float>0</float>
                </reflectivity>
                <transparent>
                  <color>0 0 0 1</color>
                </transparent>
                <transparency>
                  <float>1</float>
                </transparency>
              </phong>
            </technique>
            <extra>
              <technique profile="GOOGLEEARTH">
                <double_sided>0</double_sided>
              </technique>
            </extra>
          </profile_COMMON>
        </effect>
      </library_effects>
      <library_geometries>
        <geometry id="geometry0" name="mycube">
          <mesh>
            <source id="cubenormals-array">
              <float_array count="72" id="cubenormals-array-array">0 0 1 0 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0 -1 0 0 -1 0 0 -1 0 0 -1</float_array>
              <technique_common>
                <accessor count="24" source="#cubenormals-array-array" stride="3">
                  <param type="float" name="X"/>
                  <param type="float" name="Y"/>
                  <param type="float" name="Z"/>
                </accessor>
              </technique_common>
            </source>
            <source id="cubeverts-array">
              <float_array count="24" id="cubeverts-array-array">-50 50 50 50 50 50 -50 -50 50 50 -50 50 -50 50 -50 50 50 -50 -50 -50 -50 50 -50 -50</float_array>
              <technique_common>
                <accessor count="8" source="#cubeverts-array-array" stride="3">
                  <param type="float" name="X"/>
                  <param type="float" name="Y"/>
                  <param type="float" name="Z"/>
                </accessor>
              </technique_common>
            </source>
            <vertices id="cubeverts-array-vertices">
              <input source="#cubeverts-array" semantic="POSITION"/>
            </vertices>
            <triangles count="12" material="materialref">
              <input source="#cubenormals-array" semantic="NORMAL" offset="1"/>
              <input source="#cubeverts-array-vertices" semantic="VERTEX" offset="0"/>
              <p>0 0 2 1 3 2 0 0 3 2 1 3 0 4 1 5 5 6 0 4 5 6 4 7 6 8 7 9 3 10 6 8 3 10 2 11 0 12 4 13 6 14 0 12 6 14 2 15 3 16 7 17 5 18 3 16 5 18 1 19 5 20 7 21 6 22 5 20 6 22 4 23</p>
            </triangles>
          </mesh>
        </geometry>
      </library_geometries>
      <library_materials>
        <material name="mymaterial" id="material0">
          <instance_effect url="#effect0"/>
        </material>
      </library_materials>
      <library_visual_scenes>
        <visual_scene id="myscene">
          <node id="node0">
            <instance_geometry url="#geometry0">
              <bind_material>
                <technique_common>
                  <instance_material symbol="materialref" target="#material0"/>
                </technique_common>
              </bind_material>
            </instance_geometry>
          </node>
        </visual_scene>
      </library_visual_scenes>
      <scene>
        <instance_visual_scene url="#myscene"/>
      </scene>
    </COLLADA>
    
    0
    詳細設定を開く/閉じる
    アカウント プロフィール画像 (本文下)

    組み込みエンジニア

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    さらに詳しく →
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      関連記事