3Dモデルの簡単な読み込み

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
KEYONN_

3Dモデルの簡単な読み込み

#1

投稿記事 by KEYONN_ » 15年前

wavefrontのObjファイルを自作3Dエンジンで読み込ませようとしているのですが、
表示が上手くいかず、困っております。

3DモデルはShade8でモデリングしました。

読み込む時のソースは以下のような感じです。

どうすれば、読み込めるようになるでしょうか?

教えてください。


void LoadModifyOBJFile(char filename[/url])
{
FILE *fp;
static int count=0,count2=0;
char s;
float x,y,z;
fp=fopen(filename,"r");

while(fscanf(fp,"%c,%f,%f,%f",&s,&x,&y,&z)!=EOF)//EndOfFileまで一行ずつ読み取る
{
switch(s)
{
case '#'://コメント行は無視
break;
case 'v'://頂点座標を代入(小さすぎるので100倍する)ついでにY座標を反転
_3D.SetPnt(count,x*100,-y*100,z*100);
count++;
break;
case 'f'://三角形の番号を読み取る
//ここでエラー?
//_3D.SetNum(count2,(int)x,(int)y,(int)z);
count2++;
break;
}
}
fclose(fp);
MaxPoint=count-1;
}

ModifyObjファイルとは、私が勝手に名付けたファイル名で、Objファイルをメモ帳で
読み込み、スペースを,(カンマ)に全て置換したファイルのことです。
スペースがあると、fscanfは上手くファイルの中身を読み込んでくれないからです。 画像

KEYONN_

Re:3Dモデルの簡単な読み込み

#2

投稿記事 by KEYONN_ » 15年前

自作3Dエンジンじゃなくても、DXライブラリにフラットシェーディングの機能があれば十分なのですが、
やり方が良く分かりません。

ookami

Re:3Dモデルの簡単な読み込み

#3

投稿記事 by ookami » 15年前

while(fscanf(fp,"%c,%f,%f,%f",&s,&x,&y,&z)!=EOF)
あたりにブレークポイントを仕掛けて、一行一行ステップ実行してみてはいかがでしょうか。

//ここでエラー?
というのが、本当にそこでエラーになっているかどうかたぶん分かると思います。

あと、
DXライブラリも3Dに対応しているようです。
http://homepage2.nifty.com/natupaji/DxL ... nc_3d.html
このリファレンスは知っているけどもやり方がわからない、ということでしょうか?

KEYONN_

Re:3Dモデルの簡単な読み込み

#4

投稿記事 by KEYONN_ » 15年前

ookamiさんへ
ありがとうございます。解決しました。
DXライブラリの3D機能を使ってもshade8でxファイルに出力したファイルで表示しても
自作3DエンジンのOBJファイル読み込みも両方上手くいきました。
                     ・
どうやら、MidifyOBJファイルの先頭の行でwavefrontのfで間違った座標を入力してたみたいです。
先頭の行を消したらうまくいきました。

ただ、三角形が上手く描画されないというバグはありますが…これは解決しそうなので大丈夫です。

と思ったら、

fで指定で始まる番号は、0ではなく、1から始まるそうです。

という事は、1ずつ番号がずれているのは分かるのですが、
どうすれば上手く表示がされるのか分かりません。

どうすれば、三角形が上手く描画されますでしょうか?

とりあえず、現状のスクリーンショットを張っておきます。 画像

KEYONN_

Re:3Dモデルの簡単な読み込み

#5

投稿記事 by KEYONN_ » 15年前

現状のソースコードを添付します。
行列演算を使っていない自作3Dエンジンですが、ここはこうすればいいとか
あればそれもよろしくお願いします。

ookami

Re:3Dモデルの簡単な読み込み

#6

投稿記事 by ookami » 15年前

_3D.SetNum(count2,(int)x,(int)y,(int)z);

_3D.SetNum(count2+1,(int)x,(int)y,(int)z);
に変更されているってことですね?

objファイルのフォーマットをもうちょっと詳しく
説明してもらってもいいですか?

予想では、

v,x,y,z:3次元座標(頂点データ)
f,n1,n2,n3:ポリゴンデータ(n1,n2,n3番目のvで示される座標を頂点とする三角形)
#:コメント

だと思いますが、合ってますか?

> fで指定で始まる番号は、0ではなく、1から始まるそうです。
とのことですが、
HUMAN.obj
の307行目には、0があるし...
v,f,それぞれ、0スタートなのか1スタートなのか、というあたりも詳しくお願いします。

よろしくお願いします。

KEYONN_

Re:3Dモデルの簡単な読み込み

#7

投稿記事 by KEYONN_ » 15年前

ああ、すみません。
HUMAN.objファイルを勝手に改造してしまった後、アップロードしたのを忘れてました。
0から始めるように改造すれば上手く読み込むのではないかと思い、やってしまいました。
正しい、objファイルはこれです。(添付しました)

objファイルのフォーマットなのですが、私も詳しく知らないまま実装してました。
概ね、ookamiさんの予想通りのフォーマットだとばかり、思ってました。

フォーマットの詳しい解説URLは、こちらです。
ttp://www.hiramine.com/programming/3dmodelfileformat/objfileformat.html
(先頭のhを抜いています)

なお、実装には、フラットシェーディングを使うので、
mtllib g usemtl vt vnは使いませんでした。
vとfだけ使っています。

それで、この解説を見た後、しばらく考え込んでいたんですが、
vは、頂点フォーマットだと思いました。それで、
 0からスタートしても、1からスタートしても良いと思います。
fは、ポリゴンの番号指定だと思いました。その解説に書いてある通り、1からスタートです。

一応、答える事だけ答えてみましたが、よろしくお願いします。

KEYONN_

Re:3Dモデルの簡単な読み込み

#8

投稿記事 by KEYONN_ » 15年前

あれ、この掲示板システムは
中身がテキストデータだと勝手に拡張子を.txtにしてしまうみたいです。
ファイルを保存するときは、.objにしてください。

ookami

Re:3Dモデルの簡単な読み込み

#9

投稿記事 by ookami » 15年前

うーん、「ゴチャっとしてはいるものの、
表示はできている」という感じからして、
配列の添え字の問題だとは思うんですけどね。

ソースもサンプルデータも、
何しろ物量がでかくて、私スミズミまで見れていませんが、

少なくとも、これはまずいですね。
vertex MakeVector(double x,double y,double z)//ベクトルを作成する関数
{
vertex temp;
temp.x=x;
temp.y=y;
temp.z=z;
return (temp);
}
returnしたときには実体は破棄されています。
私の環境では強制終了されてしまい、
細かいデバッグにいたりませんでした。


ためしに、
human.objを以下のようにして実行すると、
どのような描画結果になりますか?

v,87,18,0
v,75,052,0
v,99,052,0
v,30,074,0
v,18,108,0
v,42,108,0
f,1,2,3
f,4,5,6

これは、
添付のような画像をペイントで作成し、
二つの三角形の頂点をひろっていったものです。

--
ついでにこっちも試してもらえますか?

v,87,18,0
v,75,052,0
v,99,052,0
v,30,074,0
v,18,108,0
v,42,108,0
f,0,1,2
f,3,4,5

これで、
0スタートか1スタートか、はっきりすると思います。

-- 追記

あれ?「少なくとも、これはまずいですね。」と言いましたが、
まずくないかも?すいません、頭が回らないので明日考えます。

すいません、
ポインタを返すわけではないので、
多分、問題ないですね!
ごめんなさい!またやっちまいましたよ。

...じゃぁ何で強制終了したんだろう...?? 画像

Justy

Re:3Dモデルの簡単な読み込み

#10

投稿記事 by Justy » 15年前

 このファイルフォーマットで文字列解析に何の予備解析もなしに fscanfを使うのは止めましょう。
 一端 std::getline/fgetsで受けるなどバッファにためて最初の1文字を見て分岐、その後あらためて
sscanfなどで個別に解析を行ってください。
 これだけで正確なデータを扱えるはずですし、doubleを intにキャストするなどしなくて済むはずです。


 あとはほとんど影響はないでしょうが、1000固定じゃなくてちゃんと三角形の数分だけ表示する、とか。

スキマ妖怪

Re:3Dモデルの簡単な読み込み

#11

投稿記事 by スキマ妖怪 » 15年前

まず、LoadModifyOBJFile()から直してみてはどうでしょうか?(他はあまり見てないので…)
読み取ったデータをそのまま別のファイルに書き出してみると分かると思いますが
正しくデータを読めてませんよ;

少なくとも行単位で(簡易的な)構文解析みたいな事しないとダメでは?
(fscanf()って行単位に読み込んでくれたりしましたっけ? ←うろ覚えでスイマセンorz)

KEYONN_

Re:3Dモデルの簡単な読み込み

#12

投稿記事 by KEYONN_ » 15年前

ookamiさんへ

先に示したデータの方も後のデータも、大きすぎたので、座標値を100倍するのをやめました。
というか、僕のデータが小さすぎたということでしょうか。

それで、先に示したデータのほうが正確に読み取れました。

100倍するのをやめたり、y座標反転をやめたりしましたが、うまくいきました。


Justyさんへ
スキマ妖怪さんへ

LoadModifyOBJFile()を改造しました。
それがこれです。
一見スクリーンショットを見ると上手く行っているように思われますが、
上手く描画されてません。

void LoadModifyOBJFile(char filename[/url])
{
FILE *fp;
static int count=0,count2=0;
char buf[300];
char p;
float x,y,z;
int n1,n2,n3;
fp=fopen(filename,"r");
int i,j;

while(fgets(buf,300,fp)!=NULL)//EndOfFileまで一行ずつ読み取る
{
switch(buf[0])
{
case '#'://コメント行は無視
break;
case 'v'://頂点座標を代入(場合分けで拡大)ついでにY座標を反転
sscanf(buf,"%c,%f,%f,%f",&p,&x,&y,&z);
if(x<0 || y<0 || z<0)
_3D.SetPnt(count+1,x*100,-y*100,z*100);

else
_3D.SetPnt(count+1,x,-y,z);

count++;
break;
case 'f'://三角形の番号を読み取る
//ここでエラー?
sscanf(buf,"%c,%d,%d,%d",&p,&n1,&n2,&n3);
_3D.SetNum(count2+1,n1,n2,n3);
count2++;
break;
}
}
fclose(fp);

//ファイル出力
char filename2[30];
sprintf(filename2,"%s_",filename);
fp=fopen(filename2,"w");
for(i=0;i<count-1;i++)
{
fprintf(fp,"%c,%f,%f,%f\n",'v',v[i+1].x,v[i+1].y,v[i+1].z);
}
fprintf(fp,"# %dpoints\n",count-1);
for(j=0;j<1000;j++)
{
if(Tri[j+1].n1==0 && Tri[j+1].n2==0 && Tri[j+1].n3==0) break;
fprintf(fp,"%c,%d,%d,%d\n",'f',Tri[j+1].n1,Tri[j+1].n2,Tri[j+1].n3);
}
fprintf(fp,"# %dfaces\n",j-1);
fclose(fp);

MaxPoint=count-1;
} 画像

スキマ妖怪

Re:3Dモデルの簡単な読み込み

#13

投稿記事 by スキマ妖怪 » 15年前

objファイルのフォーマットはよくは知りませんが
リンク先のフォーマットを見てみると

v、vt、vn

vで始まるキーワードが(少なくとも)3種類ありますよね;
vに関しては、2文字分見ないといけないのでは?



----------------------------------------------
よく考えたらsscanf()してるんで関係ないですねorz

このレスはスルーしてください…
画像

ookami

Re:3Dモデルの簡単な読み込み

#14

投稿記事 by ookami » 15年前

えーと、

もし私が示したobjファイルでは思ったとおりに描画され、
TKOZさんのhuman.objではぐちゃぐちゃになるとしたら、
human.objのデータ自体がおかしいか、

あるいは逆に、
「思ったとおり」という判断基準が間違っているかのどちらかですよね。

どうしましょう...

私が上で貼った、「三角形二つ」を、
①wavefrontでつくり、
②「メモ帳で置換」し、
③TKOZさんオリジナルライブラリで描画したときの、

それぞれ①のスクリーンショット、②objファイル、③のスクリーンショットを貼ってもらっていいですか?

Justy

Re:3Dモデルの簡単な読み込み

#15

投稿記事 by Justy » 15年前

>上手く描画されてません
>_3D.SetPnt(count+1,x,-y,z);
 100倍していないのは何か理由があるのでしょうか?

KEYONN_

Re:3Dモデルの簡単な読み込み

#16

投稿記事 by KEYONN_ » 15年前

ookamiさんへ

wavefrontはインストールされていないのですが、Shade8ならインストールされています。
そして、Shade8には、objファイル入出力機能があります。
それでも構わないなら、そのスクリーンショットを添付します。

Justyさんへ
100倍しているのは、頂点座標がxまたは、y、zが0より下の場合です。
ですから、頂点座標が0より下じゃないと100倍しません。
何故かというと、小さすぎて見えないからです。
100倍しない理由は、大きすぎて見えないからです。 画像

ookami

Re:3Dモデルの簡単な読み込み

#17

投稿記事 by ookami » 15年前

おや、そうでしたか^^;
最初の投稿でwavefrontとあったので、てっきりそうかと…

それなら、Shade8で結構ですよw

ケータイなので添付を見れてないかもなので、後ほど拝見いたします。

KEYONN_

Re:3Dモデルの簡単な読み込み

#18

投稿記事 by KEYONN_ » 15年前

やっと、バグがわかりました。
みなさま、ご協力、ありがとうございました。

ウィンドウプロシージャー内のWM_PAINTイベント内で、
if(a>0)
_3D.DrawSankakukei(Tri.n1,Tri.n2,Tri.n3,RGB(Blue,Blue,Blue));
のこのif文を忘れていました。
あとは、陰面消去が不完全ですが、大体目的を達成できたので、解決といたします。

KEYONN_

報告

#19

投稿記事 by KEYONN_ » 15年前

やっと陰面消去が出来るようになりました。
C言語掲示板のJusty様、ookami様、スキマ妖怪様、その他みなさんのおかげです。
スクリーンショットを添付しておきます。
ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る