ODE講座22:ODEでポリゴンを簡単に表示する方法

ODE texture

 Archive3D.netからダウンロードした3DSフォーマットの「うさちゃん」。lib3dsライブラリを使うことでODE付属のdrawstuffで表示できました。

 早いものでもう11月ですね。卒業研究や修士研究に取り組んでいる方はお尻に火か着くころではないでしょうか。

さて、ODE (Open Dynamics Engine)講座の22回目です。ODEに付属している3次元グラフィクスライブラリdrawstuffでは3Dモデルのファイルを読み込みません。ひびきのさんはXファイル(あの謎が謎を呼ぶTV番組ではありません。最も最近はPrison Breakに夢中ですが...)を読み込むX File Loaderを公開しています。 ここではもう一つの標準的な3Dファイルである3DSを読み込むサンプルプログラムをテスト公開します。

3dsファイルを読み込むライブラリとしてlib3dsを使います。これはJan Eric Kyprianidisさんが開発したものでLGPLで公開されています。lib3dsのウェブサイトはここです。

まず、lib3dsをインストールしましょう。方法はODEと同じで 以下の要領です。MSYS+MinGW+Windows Vista環境で問題なくできました。

  • ./configure
  • make
  • make install

後は、このode3dsloader-0.0.tgzファイルを次のリンクからダウンロードして、

今までのサンプルプログラムと同じように展開し、make、実行してください。ただし、このプログラムは完全ではなく、複数の部品で構成されるモデルを表示しようとするとエラーになります。また、テクスチャも表示できません。そのためにはdrawstuffのソースを変更しなければなりません。今後の宿題とします。

なお、3dsファイルを表示するためには、そのファイルが必要になります。上図のうさちゃんArchive3D.netここからダウンロードしました。 

以下にソースコードの主要部分を掲載します。3dsファイルを読み込む関数がload3dsModel()です。読み込みが終わると頂点配列Vertices[]とインデックス配列Indices[]にデータが格納されるので、後はODE付属のdemoプログラムdemo_moving_trimesh.cppと同じようにプログラムするとポリゴンデータを扱うことができます。

つまり、一般ユーザはload3dsModel()を一行入れるだけで3dsファイルを読み込むことができます。簡単ですね。

まだ、テスト公開中で不完全です。複数のオブジェクトで構成される3dsデータを表示できなければなりません。コメント頂ければありがたいです。


 

// main.cppから抜粋  by Kosei Demura 2007-11-1 
//

#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "ode3dsloader.h"

extern int MeshCount; // オブジェクト数

void makeModel()
{
  static dReal weight = 10.0;
  dReal x0 = 0, y0 = 0, z0 = 1.0;
  dMass m;

// 3dsファイルをロードする関数。引数は3dsファイル名
 load3dsModel("../models/rabbit.3DS"); 

 TriData = (dTriMeshDataID *) malloc(MeshCount * sizeof(dTriMeshDataID));

 model  = (MyObject *) malloc (MeshCount * sizeof(MyObject));

 for (int i = 0; i < MeshCount; i++) {
   // rigid body
   model[i].body = dBodyCreate(world);
   dBodySetPosition(model[i].body, x0, y0, z0);

   // for a trimesh object
    TriData[i] = dGeomTriMeshDataCreate();  

    dGeomTriMeshDataBuildSingle(TriData[i], trimesh[i].vertices, 3 * sizeof(float), trimesh[i].vertexCount, trimesh[i].indices, trimesh[i].indexCount * 3, 3 * sizeof(int));
  
    model[i].geom = dCreateTriMesh(space, TriData[i], 0, 0, 0);

   // remember the mesh's dTriMeshDataID on its userdata for convenience.
   dGeomSetData(model[i].geom, TriData[i]);   

   dMassSetTrimeshTotal(&m, weight, model[i].geom);
    dGeomSetPosition(model[i].geom, -m.c[0], -m.c[1], -m.c[2]);
    dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);

   dGeomSetBody(model[i].geom, model[i].body);
   dBodySetMass(model[i].body, &m);
  
   dMatrix3 Rotation;
    dRFromAxisAndAngle(Rotation, 0, 0, 1, -M_PI/4);
    dBodySetRotation(model[i].body, Rotation);
  }
}

 


// ode3dsloader.cpp by Kosei Demura 2007-11-01
// 3dsフォーマットで作られたオブジェクトを読み込むプログラム
// このファイルでload3dsModel()関数を実装している。
// Todo:1つの3Dモデルが複数のオブジェクトで構成されているとエラーになる。
// lib3dsライブラリが必要
http://lib3ds.sourceforge.net/
#include "ode3dsloader.h"
#define BASE_LENGTH  1.0      // メッシュモデルのバウンディングボックスの最大長さ[m]
#define MAX_OBJECTS  1000   // オブジェクトの数

typedef struct
{
    float *vertices;
    unsigned int vertexCount;
    int *indices;
    unsigned int indexCount;
} MyTrimesh;

extern MyTrimesh *trimesh;

dReal MIN_X = dInfinity, MAX_X = - dInfinity;
dReal MIN_Y = dInfinity, MAX_Y = - dInfinity;
dReal MIN_Z = dInfinity, MAX_Z = - dInfinity;
dReal ADJUST; 
Lib3dsFile *file=0;

int MeshCount  = 0;

int vCount[MAX_OBJECTS], iCount[MAX_OBJECTS];

void calModel(Lib3dsMesh *mesh, int *points, int *faces)
{
  *points = mesh->points;
  *faces  = mesh->faces;
}

int meshDump(int no, Lib3dsMesh *mesh)
{
  if (mesh->points == 0) return 0;

   for (int i=0; i< (int) mesh->points; i++) {
    trimesh[no].vertices[3*i]   = mesh->pointL[i].pos[0];
    trimesh[no].vertices[3*i+1] = mesh->pointL[i].pos[1];
    trimesh[no].vertices[3*i+2] = mesh->pointL[i].pos[2];
   if (MIN_X > mesh->pointL[i].pos[0]) MIN_X = mesh->pointL[i].pos[0];
   if (MIN_Y > mesh->pointL[i].pos[1]) MIN_Y = mesh->pointL[i].pos[1];
  if (MIN_Z > mesh->pointL[i].pos[2]) MIN_Z = mesh->pointL[i].pos[2];
   if (MAX_X < mesh->pointL[i].pos[0]) MAX_X = mesh->pointL[i].pos[0];
   if (MAX_Y < mesh->pointL[i].pos[1]) MAX_Y = mesh->pointL[i].pos[1];
   if (MAX_Z < mesh->pointL[i].pos[2]) MAX_Z = mesh->pointL[i].pos[2];
  }
 
for (int i=0; i< (int) mesh->faces; i++) {
     trimesh[no].indices[3*i]   = mesh->faceL[i].points[0];
     trimesh[no].indices[3*i+1] = mesh->faceL[i].points[1];
     trimesh[no].indices[3*i+2] = mesh->faceL[i].points[2];
   }
  return 1;
}

// トライメッシュデータのサイズ変更
int normalize(int no, Lib3dsMesh *mesh)
{
 if (mesh->points == 0) return 0;

 for (int i=0; i< (int) mesh->points; i++) {
   trimesh[no].vertices[3*i]    *= (dReal) ADJUST;
   trimesh[no].vertices[3*i+1] *= (dReal) ADJUST;
   trimesh[no].vertices[3*i+2] *= (dReal) ADJUST;
 }
 return 1;
}

void load3dsModel(const char *filename)
{
  int points, faces, no;
  Lib3dsMesh *p;
 
  file = lib3ds_file_load(filename);
  if (!file) {
    puts("3dsplayer: Error: Loading 3DS file failed.\n");
    exit(1);
  }

 for (p=file->meshes; p!=0; p=p->next) {
    calModel(p, &points, &faces);
    if (points == 0) continue;
    MeshCount++;
  }

 trimesh   = (MyTrimesh *) malloc(MeshCount * sizeof(MyTrimesh));
 no = 0;
  for (p=file->meshes; p!=0; p=p->next) {
    calModel(p, &points, &faces);
   if (points == 0) continue;

    vCount[no] = points;
    iCount[no] = faces; 
    trimesh[no].vertices = (float *) malloc(vCount[no]  * sizeof(float) * 3);
    trimesh[no].indices  = (int *)    malloc(iCount[no]   * sizeof(int)    * 3);
    trimesh[no].vertexCount = vCount[no];
    trimesh[no].indexCount  = iCount[no];
    no++;
  }

  no = 0;
  for (p=file->meshes; p!=0; p=p->next) {
   if (meshDump(no, p)) no++;
  }

 dReal maxLength;

 if (MAX_X - MIN_X >= MAX_Y - MIN_Y) {
   if (MAX_X - MIN_X >= MAX_Z - MIN_Z) maxLength = MAX_X - MIN_X;
   else                                                      maxLength = MAX_Z - MIN_Z;
 }
 else {
    if (MAX_Y - MIN_Y >= MAX_Z - MIN_Z) maxLength = MAX_Y - MIN_Y;
    else                                maxLength = MAX_Z - MIN_Z;
 }

  ADJUST = BASE_LENGTH / maxLength;
 
  no = 0;
  for (p=file->meshes; p!=0; p=p->next) {
    if (normalize(no, p)) no++;
 }
}

// ode3dsloader.h

#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
// for lib3ds
#include <lib3ds/chunk.h>
#include <lib3ds/file.h>
#include <lib3ds/camera.h>
#include <lib3ds/mesh.h>
#include <lib3ds/node.h>
#include <lib3ds/material.h>
#include <lib3ds/matrix.h>
#include <lib3ds/vector.h>
#include <lib3ds/light.h>

void load3dsModel(const char *filename);



 

 

Trackback Pings

TrackBack URL for this entry:

No trackbacks found.

Comments

Posted by ミルトン

lib3ds-examples.tgzを試してみましたが下記のとおりとなってしまいました。msysのトップからのディレクトリ構成と主要ライブラリのメモ書きがあったらメールに添付していただけますでしょうか?

$ make
g++ -Wall -fno-exceptions -fno-rtti -g -DWIN32 -c 3dsplay.c -L/lib -L/usr/lib -L../lib -L../../drawstuff/src -L/usr/local/lib -I/include -I/usr/include -I../include -I. -I../../include -I/usr/local/include
In file included from ../../include/lib3ds/types.h:51,
from ../../include/lib3ds/background.h:27,
from ../../include/lib3ds/file.h:27,
from 3dsplay.c:27:
../include/stdint.h:24:20: stddef.h: No such file or directory
In file included from ../../include/lib3ds/types.h:78,
from ../../include/lib3ds/background.h:27,
from ../../include/lib3ds/file.h:27,
from 3dsplay.c:27:
../include/stdio.h:28:20: stdarg.h: No such file or directory
In file included from ../../include/lib3ds/types.h:78,
from ../../include/lib3ds/background.h:27,
from ../../include/lib3ds/file.h:27,
from 3dsplay.c:27:
../include/stdio.h:191: error: `size_t' has not been declared
../include/stdio.h:191: error: ISO C++ forbids declaration of `parameter' with no type
../include/stdio.h:202: error: `size_t' has not been declared

Posted by でむ

ミルトンさん、

ディレクトリ構成全体とは、msysのトップディレクトリからですか? それでも/home/ユーザ名/src/ode-0.9からでしょうか?

でむ

Posted by でむ

ミルトンさん、

3dsplay.cはそのままではエラーになるので、ソースを変更する必要があります。C言語のソースコードをg++というC++のコンパイラーでコンパイルしているのも原因の一つですが、gccでコンパイルしてもエラーは残ります。

これは、demura.netのサンプルプログラムをVisual C++でもコンパイルできるようにするためです。C++の方がCより型チェックが厳しいですから。

なお、コンパイルできるようにしたファイル一式をまとめて以下に置きましたのでゲットしてください。makeしてください。http://demura.net/archives/images/ode/lib3ds-examples.tgz

でむ

Posted by ミルトン

おそれいりますが、ディレクトリ構成全体をワードなどに貼り付けて送っていただけますでしょうか?
最初から確認しなおします。

Posted by ミルトン

ライブラリの位置が原因なのかincludeの位置が悪いのかと思い、makeで指定しているフォルダのファイルを自分のディレクトリにコピーしたりして様子を見ていますが、主だった成果が得られていません。
自分のディレクトリというのは/msys/1.0/home/username/src/ode-0.9/mytestここです。

環境自体がめちゃくちゃになっていたと思い、MinGW,Msysをマニュアルで解凍、展開、make installしなおしました。腑に落ちないのが、MinGW,Msysをdownloadするときに同時にダウンロードされる圧縮ファイルをインストールしたほうがよいのかと思い、インストールしましたが内容は変わらないようでした。問題ないとおもいました。

コメントいただければおねがいします。

Posted by ミルトン

修正したのですが3dsplay.exeはまだできていません。ode3rdloader rabbit.3dsも動きません
恐れ入りますが、コメントいただきたく。

$make

$ g++ -Wall -fno-exceptions -fno-rtti -g -DWIN32 -c 3dsplay.c -L/lib -L/usr/li
b -L../lib -L../../drawstuff/src -L/usr/local/lib -I/include -I/usr/include -I

../include -I. -I../../include -I/usr/local/include
3dsplay.c: In function `void toggle_bool(int, int, void*)':
3dsplay.c:178: error: invalid conversion from `void*' to `int*'
3dsplay.c: In function `void render_node(Lib3dsNode*)':
3dsplay.c:479: error: invalid conversion from `void*' to `float (*)[3]'
3dsplay.c:515: error: invalid conversion from `void*' to `Player_texture*'
3dsplay.c:540: warning: unused variable 'upload_format'
3dsplay.c: In function `void display()':
3dsplay.c:790: error: expected unqualified-id before ',' token
3dsplay.c:790: error: expected unqualified-id before ',' token
3dsplay.c:834: error: expected primary-expression before '=' token
3dsplay.c:835: error: expected primary-expression before '=' token
3dsplay.c:858: error: expected primary-expression before '<=' token
3dsplay.c:858: error: expected primary-expression before '=' token
3dsplay.c:858: error: invalid type argument of `unary *'
3dsplay.c:860: error: expected primary-expression before ',' token
3dsplay.c:860: error: expected primary-expression before ')' token
3dsplay.c: In function `void create_icons()':

Posted by でむ

ミルトンさん、

セパレータエラーはmakefileの中でTABが入っていないからです。
TABというのはキーボードのTABキーのことです。
私も初めてこのエラーに出会ったときは意味不明でした。

このウェブサイトの性質上で、カットアンドペーストでTABをコピーできないのでエラーになります。
以前のコメントのmakefileでTABをいれる場所に[TAB]と書きましたのでコピーしてからTABを入れてください。

わからなければ、また質問お願いします。

でむ

Posted by ミルトン

msys/1.0/home/username/src/lib3ds-1.3.0/example/3dsplay.c
を掲載のmake文で実行しようとmakefileとしてセーブして、msysでmakeしたら
セパレータエラーが起こってしまいました。全角半角変換は完了しても再び下記の
メッセージがでました。

$ make
makefile:14: *** missing separator. Stop.

Posted by でむ

ミルトンさん、

補足します。

3dsplay.cのコンパイルにはmakefileを使ってください。
また、3dsplay.cはglutを使っているのでglutをインストールする必要があります。

glutのインストール法は
http://www-sens.sys.es.osaka-u.ac.jp/wakate/tutorial/group3/glui/glui3.html
の記事のWindows XP, MinGWのgccが参考になります。


# makefile
CC = g++ -Wall -fno-exceptions -fno-rtti -g -DWIN32
TARGET = 3dsplay
OBJS = 3dsplay.o
SOURCE = 3dsplay.c
HEADER =
WINDRES = windres
LIBS = -L/lib -L/usr/lib -L../lib -L../../drawstuff/src -L/usr/local/lib
INDS = -I/include -I/usr/include -I../include -I. -I../../include -I/usr/local/include
OPTS = -lstdc++ -lcomctl32 -lkernel32 -luser32 -lgdi32 -lopengl32 -lglu32 -lglut32 -lwinmm -lm -l3ds


$(TARGET):$(OBJS) $(RESOURCE_FILE) $(HEADER)
[TAB] $(CC) -mwindows -o $@ $(OBJS) $(LIBS) $(INDS) $(OPTS)

$(OBJS): $(SOURCE) $(HEADER)
[TAB] $(CC) -c $(SOURCE) $(LIBS) $(INDS)

clean:
[TAB] rm $(TARGET) $(OBJS) *.*~ *~ *.exe *.*.stackdump

Posted by でむ

ミルトンさん、

頂いたrabbit.3DSをode3dsloader-0.0で実行したところ問題なくできました。
rabbit3DSのパスの指定が悪いと思われます。
rabbit3DSをmain.cppと同じディレクトリに置いて、main.cppのmakeModelの170行目にある行を以下のように設定して試してください。

load3dsModel("./rabbit.3DS");

または、lib3dsライブラリが正しくインストールされていない可能性もあります。
lib3ds-1.3.0/examples/3dsplay.exeがうまく実行できますか?

でむ

Posted by でむ

ミルトンさん、

makeできなかった原因を教えて頂けますか?
また、表示に使用した3dsファイルをメールに添付して私に送ってください。
メールアドレスはナビゲーションバーのProfileに記載しています。

でむ

Posted by ミルトン

make は正常に終了しターゲットができました。しかし、肝心のデータを入れても下記のエラーが発生してしまいます。rabbit データはhome/usernale/modelの中にあります。

home/username/src/ode-0.9/mytest/ode3dsloader-0.0
$ 3dsloader ../model/rabbit.3DS
3dsplayer: Error: Loading 3DS file failed.


ode3dsloaderのソースファイルを分析すればわかると思いますが、ファイルの形式の問題だったらわかりません。申し訳ありませんが、ご指導いただきたく。

Posted by でむ

ミルトンさん、

パスが通っていればどこでも良いと思いますが、このODE講座ではc:¥msys¥1.0¥home¥ユーザ名¥src¥ode-0.9としています。

本講座で使用しているmakefileは場所に依存します。これはdrawstuffのリソースファイルresources.rcを相対パスで指定しているためです。

お勧めは以下のディレクトリを作り、そこで展開してください。
/home/ユーザ名/src/ode-0.9/myprog/

展開すると次のようになります。
/home/ユーザ名/src/ode-0.9/myprog/ode3dsloader-0.0/{ode3dsloader-0.0.cpp, ode3dsloader-0.0.h, ...}

なお、本講座のサンプルプログラムが問題なくmake並びに実行できる場合は、その問題ないmakefileと入れ替えて、makefileのファイル名を書き直しmakeしてください。

Posted by ミルトン

ODE-0.9はどのディレクトリにおくべきでしょうか?
msysのhome/*****の下でよいのでしょうか? それもーともminGWのしたでしょうか?

Posted by ミルトン

ODEをインストールする際にmake install できなく、VisualC++2005で設定しました。他のodeのsanple prpogramを実行して特認台はありませんでした。
http://demura.net/archives/9ode/lecture/ode22.htmlに従うように、ode/pde.h,drawatuff/drawstuffを移動して、エラーを回避していたら、このエラーに遭遇しました。

ODEをインストールする際にmake installで、/usr/local/include/odeにodeのヘッダファイル群、/usr/local/libにlibode.a, libode.dllがインストールされていますか?に対しては、ODEはmake Installしていません。したがって、記述のディレクトリにファイルが入っていません。ode-srcからインストールをしたほうがよいようですね。

また、他のサンプルプログラムはMinGWで問題なくコンパイルできるのでしょうか?わかりません。
ode-0.9をインストールする際、,sysでインストールはしていません。

Posted by でむ

ミルトンさん テストして頂きありがとうございます。

私の環境 MSYS1.0.10+ MinGW5.1.3+Windows Vista Businessでは問題なくmakeできます。 ちなみにmake 3.79.1、gcc3.4.2です。

ODEをインストールする際にmake installで、/usr/local/include/odeにodeのヘッダファイル群、/usr/local/libにlibode.a, libode.dllがインストールされていますか?

また、他のサンプルプログラムはMinGWで問題なくコンパイルできるのでしょうか?

Posted by ミルトン

ode3dsloader-0.0をmakeするとき、下記のエラーが発生してしまいます。バックスラッシュが/だとよいのですが、どうやって解決したらよいのかご指導いただければと思っています。環境はMinGW+MSYS+WinX PPro SP2
です。よろしくお願いします。

c:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: cannot find -lode

Post a Comment

(サインインしなくてもコメントできますが、スパム対策のため表示されるまで時間がかかります。サインインしてからコメントし、このブログのオーナーの承認を受けるとコメントがすぐ表示されるようになります。)

Remember personal info?

カウンタ (since 2007-5-20)