トップページ > 過去ログ > 記事閲覧
別ポリゴンの影を映すには
名前:wisteria 日時: 2010/05/16 18:26

以前、別のポリゴンに阻まれてライトの光が 当たらない(影が映る)ような表現をする方法はございますでしょうか、という質問に ライトのある位置にカメラを移動して、更にライトの方向をカメラの位置にして 影を付けたいオブジェクトを黒色で影用テクスチャに描画、カメラの位置を戻して影が映りこむ物体( 地面や壁など )を 形成する各頂点が作成した影用テクスチャの何処に位置( テクスチャ座標値 )するかを計算して割り出し影を描画、 というようなことをします という回答をいただきましたが、すみませんが、いまいちよく理解できません。 ライトの方向をカメラの位置にする、とは具体的にどのような処理なのでしょうか?。 また、単純に、 光源と光を阻むほうのテクスチャの各頂点を通る直線が、 影が映りこむほうのテクスチャと同じ平面上においてどこの座標にくるかを計算し、 その平面上で影が映りこむほうのテクスチャのある部分だけに、 光源と光を阻むほうのテクスチャと同じ形の真っ黒なものと、 影が映りこむほうのテクスチャを描画する。 という方法では、前回教えていただきました方法より重くなってしまいますでしょうか? 後半は教えていただいた方法と同じようなことをしているような気もするのですが・・・。

Page: 1 |

Re: 別ポリゴンの影を映すには ( No.1 )
名前:管理人 日時:2010/05/16 20:44

文章でご説明するのは大変なのでサンプルを作ってみました https://dxlib.xsrv.jp/file/TextureShadow.zip サンプルではディレクショナルライトを使用していて「ライトのある位置にカメラを移動する」 ことはできないので、影を表示したいキャラクターの中心から「ライトの方向」と逆方向に移動した 位置からキャラクターの中心を見るようにして影用のテクスチャを描画しています 影用テクスチャの描画はサンプル内の「// プレイヤーの影用テクスチャの準備」という注釈が ある辺りで行っていて、実際にそれを使って影を描画しているところは「// 影の描画」という 注釈がある辺りで行っています > また、単純に、 > 光源と光を阻むほうのテクスチャの各頂点を通る直線が、 > 影が映りこむほうのテクスチャと同じ平面上においてどこの座標にくるかを計算し、 > その平面上で影が映りこむほうのテクスチャのある部分だけに、 > 光源と光を阻むほうのテクスチャと同じ形の真っ黒なものと、 > 影が映りこむほうのテクスチャを描画する。 > という方法では、前回教えていただきました方法より重くなってしまいますでしょうか? 「テクスチャ」は「ポリゴンに貼り付けるもの」で、「テクスチャ」単体での描画というと ビルボードや2Dで画像を描画するというイメージなのですが、もしかして wisteriaさんが やられようとしているのは何千ポリゴンも使って形成される3Dモデルの影を表示するというのとは 違うのでしょうか?  今回私が作成したサンプルでは1千ポリゴン以上使っている3Dモデルの影を描画していますので、 そのポリゴン一つ一つと影が映りこむポリゴン群との当たり判定をしていると処理に時間が掛かりすぎるので まず3Dモデルの影を1枚の「影テクスチャ」に書き込むことで、影が映りこむポリゴン群との 当たり判定を「影テクスチャ」1枚分で済む様にしていますが、もし何千ポリゴンも使う3Dモデル の影ではなく、影を付けたいオブジェクトそれぞれが1〜2ポリゴンで形成されているのでしたら wisteriaさんがお考えになられた方法の方が高速に影を描画できると思います ( しかも影用テクスチャを使う必要が無いので動作環境も多くなります )
( No.Y )
名前: 日時:

Re: 別ポリゴンの影を映すには ( No.2 )
名前:wisteria 日時:2010/05/17 13:18

わざわざサンプルまで作成していただきありがとうございます。 モデルは使わず、すべてDrawPolygonIndexed3Dでテクスチャを貼ったポリゴンを多数描画しています。 テクスチャには透明部分もあったりするので、 透明部分以外が光を阻み影が映る、ということをしたかったのです。 お察しのとおり建物などに使用する、光を阻む可能性のあるポリゴンは各数枚程度です。 とは言ったものの、その平面上で影が映りこむほうのテクスチャのある部分だけに描画、 というのもどうすればいいか、悩みどころなのですが・・・。 また、作成していただいたサンプルやリファレンスにも行列というものがでてきますが、 辞書やwikipediaを見てもよくわかりませんでした。 この辺を理解せずに3次元空間のさまざまな計算が必要なプログラムを組むことに無理があるのでしょうか?
Re: 別ポリゴンの影を映すには ( No.3 )
名前:管理人 日時:2010/05/20 00:50

> また、作成していただいたサンプルやリファレンスにも行列というものがでてきますが、 > 辞書やwikipediaを見てもよくわかりませんでした。 確か高校数学で登場したような・・・ 「高校 行列」で検索すると、wikipedia より分りやすい解説ページが見つかると思います > この辺を理解せずに3次元空間のさまざまな計算が必要なプログラムを組むことに無理があるのでしょうか? 今回のサンプルではそもそもDXライブラリにまだない影表現を実装しようとしたので 行列を使いましたが、実際にDXライブラリに影機能を付けたとした場合は行列の知識が無くても 実装できるようになると思います ただ、今回の wisteria さんが実装されようとしているような、DXライブラリの 機能には無い独自の3D表現をしようとした場合は確かに線形代数や行列の知識が無いと 難しいかもしれません・・・
Re: 別ポリゴンの影を映すには ( No.4 )
名前:wisteria 日時:2010/05/23 08:57

わかりました。調べてみます。数Cなので学校で習うのはかなり先のようですから・・・。 遠近法カメラを用いたかったのですが、 // カメラの設定をしなおす の部分を SetCameraNearFar( 100.0f, 8000.0f ) ; SetCameraPositionAndTarget_UpVecY( VGet( 0.0f, 500.0f, -2000.0f ), VGet( 0.0f, 0.0f, 0.0f ) ) ; SetupCamera_Perspective(60.0*3.1415926/180.0); と変更したらうまくいきました。 自分が作成中のプログラムに組み込んで見ます。 ありがとうございました。
Re: 別ポリゴンの影を映すには ( No.5 )
名前:wisteria 日時:

サンプルを参考に(というかほとんどコピペ)作成中のプログラムに組み込んでみたのですが、 とりあえず、半分だけ描画させたのですが、まったく表示されませんでした。 影に関する部分のソースです。 class texture { public: double x[4],y[4],z[4];//各頂点座標 int graph;//テクスチャ画像ハンドル double r,g,b;//エミッシブカラー }; int ShadowTexture; MATRIX LightMatrix; VERTEX3D **shadow; void init_shadow(void) { int l=drawn_end[0]-drawn_start[0]+1; shadow=(VERTEX3D **)malloc(sizeof(VERTEX3D *)*l); for(int i=0;i<l;i++) { shadow[i]=(VERTEX3D *)malloc(sizeof(VERTEX3D)*4); } SetDrawValidGraphCreateFlag(true); SetDrawValidAlphaChannelGraphCreateFlag(true); ShadowTexture=MakeGraph(512,512); SetDrawValidAlphaChannelGraphCreateFlag(false); SetDrawValidGraphCreateFlag(false); return; } void del_shadow(void) { int l=drawn_end[0]-drawn_start[0]+1; for(int i=0;i<l;i++)free(shadow[i]); free(shadow); return; } int draw_shadow(texture *textures) { int l=drawn_end[0]-drawn_start[0]+1; for(int a=180;a<l;a++)//ポリゴンが多すぎるので一部に関して。 { texture t=textures[a+drawn_start[0]]; double dx[4],dy[4],dz[4]; for(int i=0;i<4;i++) { double xc=t.x[i]-cam.x; double yc=t.y[i]-cam.y; double zc=t.z[i]-cam.z; double D=sqrt(xc*xc+zc*zc); if(D==0.0)return -1; if(D>=MAX_draw_far)return 0; if(D<=MAX_draw_near)return 0; double A=atan2(zc,xc)-radian(cam.angle_xz); xc=cos(A)*D; zc=sin(A)*D; if(cam.incine!=0.0) { D=sqrt(yc*yc+zc*zc); A=atan2(yc,zc)-radian(cam.incine); zc=c
( No.os(A)*D;
yc=sin(A)*D;
}
if(cam.cant!=0.0)
{
D=sqrt(xc*xc+yc*yc);
A=atan2(yc,xc)+radian(cam.cant);
xc=cos(A)*D;
yc=sin(A)*D;
}
dx[i]=xc;
dy[i]=yc;
dz[i]=zc;
}


shadow[a][0].pos=VGet(dx[0],dy[0],dz[0]);
shadow[a][0].dif=GetColorU8(0,0,0,0);
shadow[a][0].spc=GetColorU8(0,0,0,0);
shadow[a][0].u=0.0F;
shadow[a][0].v=0.0F;
shadow[a][0].su=0.0F;
shadow[a][0].sv=0.0F;

shadow[a][1].pos=VGet(dx[1],dy[1],dz[1]);
shadow[a][1].dif=GetColorU8(0,0,0,0);
shadow[a][1].spc=GetColorU8(0,0,0,0);
shadow[a][1].u=1.0F;
shadow[a][1].v=0.0F;
shadow[a][1].su=0.0F;
shadow[a][1].sv=0.0F;

shadow[a][2].pos=VGet(dx[2],dy[2],dz[2]);
shadow[a][2].dif=GetColorU8(0,0,0,0);
shadow[a][2].spc=GetColorU8(0,0,0,0);
shadow[a][2].u=1.0F;
shadow[a][2].v=1.0F;
shadow[a][2].su=0.0F;
shadow[a][2].sv=0.0F;

shadow[a][3].pos=VGet(dx[3],dy[3],dz[3]);
shadow[a][3].dif=GetColorU8(0,0,0,0);
shadow[a][3].spc=GetColorU8(0,0,0,0);
shadow[a][3].u=0.0F;
shadow[a][3].v=1.0F;
shadow[a][3].su=0.0F;
shadow[a][3].sv=0.0F;
}

VECTOR LightDir,LightTargetPos,LightPos;

for(int i=0;i<l;i++)
{
SetUseLighting(false);
SetDrawScreen(ShadowTexture);
SetupCamera_Ortho(1000.0);
ClearDrawScreen();

LightDir=GetLightDirection();
LightTargetPos=VGet((shadow[i][0].pos.x+shadow[i][2].pos.x)/2.0,
(shadow[i][0].pos.y+shadow[i][2].pos.y)/2.0,
(shadow[i][0].pos.z+shadow[i][2].pos.z)/2.0) )
名前: 日時:

2010/06/06 16:23 ( No.;
LightPos=VSub(LightTargetPos,VScale(LightDir,1500));
SetCameraPositionAndTarget_UpVecY(LightPos,LightTargetPos);
LightMatrix=MMult(GetCameraViewMatrix(),GetCameraProjectionMatrix());
unsigned short int index[6]={0,1,3,1,3,2};

DrawPolygonIndexed3D(shadow[i],4,index,2,textures[i+drawn_start[0]].graph,true);

SetUseLighting(true);
SetDrawScreen(DX_SCREEN_BACK);
SetupCamera_Perspective(radian(60.0));
SetCameraPositionAndTarget_UpVecY(VGet(0.0,200.0,-50.0),VGet(0.0,200.0,-49.0));//運転台モード実装時に注意!

VERTEX3D sh[4];
sh[0].dif=GetColorU8(255,255,255,255);
sh[0].spc=GetColorU8(0,0,0,0);
sh[0].sv=sh[0].su=0.0;
sh[3]=sh[2]=sh[1]=sh[0];
for(int j=0;j<l;j++)
{
sh[0].u= (LightMatrix.m[0][0]*shadow[j][0].pos.x+LightMatrix.m[1][0]*shadow[j][0].pos.y+LightMatrix.m[2][0]*shadow[j][0].pos.z+LightMatrix.m[3][0]+1.0f)*0.5f;
sh[0].v=1.0f-(LightMatrix.m[0][1]*shadow[j][0].pos.x+LightMatrix.m[1][1]*shadow[j][0].pos.y+LightMatrix.m[2][1]*shadow[j][0].pos.z+LightMatrix.m[3][1]+1.0f)*0.5f;
sh[1].u= (LightMatrix.m[0][0]*shadow[j][1].pos.x+LightMatrix.m[1][0]*shadow[j][1].pos.y+LightMatrix.m[2][0]*shadow[j][1].pos.z+LightMatrix.m[3][0]+1.0f)*0.5f;
sh[1].v=1.0f-(LightMatrix.m[0][1]*shadow[j][1].pos.x+LightMatrix.m[1][1]*shadow[j][1].pos.y+LightMatrix.m[2][1]*shadow[j][1].pos.z+LightMatrix.m[3][1]+1.0f)*0.5f;
sh[2].u= (LightMatrix.m[0][0]*shadow[j][2].pos.x+LightMatrix.m[1][0]*shadow[j][2].pos.y+LightMatrix.m[2][0]*shadow[j][2].pos.z+LightMatrix.m[3][0]+1.0f)*0.5f;
sh[2].v=1.0f-(LightMatrix.m[0][1]*shadow[j][2].pos.x+LightMatrix.m[1][1]*shadow[j][2].pos.y+LightMatrix.m[2][1]*shadow[j][2].pos.z+LightMatrix.m[3][1]+1.0f)*0.5f;

DrawPolygon3D(sh,1,ShadowTexture,true);
}
}
return 0;
} )
名前:115.37.228 日時:

hxgYsHPmD75dk ( No..223 )
名前: 日時:

Re: 別ポリゴンの影を映すには ( No.6 )
名前:いっち 日時:2010/06/08 01:01

良くわかっていないのですが、 > DrawPolygonIndexed3D(shadow[i],4,index,2,textures[i+drawn_start[0]].graph,true); この段階で、 ShadowTexture にwisteriaさんのイメージ通りの画像が作られているか確認なさってみてはどうでしょうか?
Re: 別ポリゴンの影を映すには ( No.7 )
名前:管理人 日時:2010/06/13 03:22

こちらでお試しすることができないので掲載していただいたソースから判断するしかありませんが まずいっちさんも仰られていますが ShadowTexture を普通の2D画像として DrawGraph したら 影の元となるものは描画されますでしょうか? 次に sh[0].u= (LightMatrix.m[0][0]*shadow[j][0].pos.x+LightMatrix.m[1][0]*shadow[j][0].pos.y+LightMatrix.m[2][0]*shadow[j][0].pos.z+LightMatrix.m[3][0]+1.0f)*0.5f; sh[0].v=1.0f-(LightMatrix.m[0][1]*shadow[j][0].pos.x+LightMatrix.m[1][1]*shadow[j][0].pos.y+LightMatrix.m[2][1]*shadow[j][0].pos.z+LightMatrix.m[3][1]+1.0f)*0.5f; sh[1].u= (LightMatrix.m[0][0]*shadow[j][1].pos.x+LightMatrix.m[1][0]*shadow[j][1].pos.y+LightMatrix.m[2][0]*shadow[j][1].pos.z+LightMatrix.m[3][0]+1.0f)*0.5f; sh[1].v=1.0f-(LightMatrix.m[0][1]*shadow[j][1].pos.x+LightMatrix.m[1][1]*shadow[j][1].pos.y+LightMatrix.m[2][1]*shadow[j][1].pos.z+LightMatrix.m[3][1]+1.0f)*0.5f; sh[2].u= (LightMatrix.m[0][0]*shadow[j][2].pos.x+LightMatrix.m[1][0]*shadow[j][2].pos.y+LightMatrix.m[2][0]*shadow[j][2].pos.z+LightMatrix.m[3][0]+1.0f)*0.5f; sh[2].v=1.0f-(LightMatrix.m[0][1]*shadow[j][2].pos.x+LightMatrix.m[1][1]*shadow[j][2].pos.y+LightMatrix.m[2][1]*shadow[j][2].pos.z+LightMatrix.m[3][1]+1.0f)*0.5f; こちらの計算で行列と shadow 配列の座標を掛け合わせていますが、こちらの行列と掛け合わせる座標は 「影を映りこませたいポリゴン」の座標です そして、VECTOR 構造体の配列 sh には座標( pos )が設定されていませんが、こちらの配列の pos にも 「影を映りこませたいポリゴン」の座標を代入する必要があります 私が作成したサンプルもそうなっていますので、よろしければご覧になってみてください
Re: 別ポリゴンの影を映すには ( No.8 )
名前:wisteria 日時:2010/06/13 13:38

表示されず atan2: DOMAIN error を量産しています(汗 ( 「-w」パラメータをつけず int main() { return WinMain(0,0,0,0); } ということをしているためプロンプトは生きています。 )
Re: 別ポリゴンの影を映すには ( No.9 )
名前:管理人 日時:2010/06/13 14:57

> 表示されず > atan2: DOMAIN error > を量産しています(汗 ShadowTexture を DrawGraph で描画しても何も表示されないと言うことでしょうか? ふと疑問に思ったのですが、 for(int a=180;a<l;a++)//ポリゴンが多すぎるので一部に関して。 { こちらのループで作成している shadow 頂点配列の座標( pos )に代入する値をカメラとの位置関係を 考慮して導き出していますが、そうではなく textures の x,y,z をそのまま shadow の pos に代入 してしまってもよいかもしれません と、いいますのも影テクスチャを作成する工程 SetUseLighting(false); SetDrawScreen(ShadowTexture); SetupCamera_Ortho(1000.0); ClearDrawScreen(); LightDir=GetLightDirection(); LightTargetPos=VGet((shadow[i][0].pos.x+shadow[i][2].pos.x)/2.0, (shadow[i][0].pos.y+shadow[i][2].pos.y)/2.0, (shadow[i][0].pos.z+shadow[i][2].pos.z)/2.0); LightPos=VSub(LightTargetPos,VScale(LightDir,1500)); SetCameraPositionAndTarget_UpVecY(LightPos,LightTargetPos); LightMatrix=MMult(GetCameraViewMatrix(),GetCameraProjectionMatrix()); unsigned short int index[6]={0,1,3,1,3,2}; DrawPolygonIndexed3D(shadow[i],4,index,2,textures[i+drawn_start[0]].graph,true); で使用する座標( 上記で言うところの shadow[][].pos )はカメラからの相対座標ではなく、ワールド座標だからです ただ、「運転台モード」という注釈が気になります、こちらでのカメラ設定では cam 構造体の値を使用していない ようですので、もしかして全ての描画物をカメラ座標系に変換してから描画しているのでしょうか? うーん、プログラムの全体を拝見しないと私から正確な解決策を申し上げるのは難しそうです
Re: 別ポリゴンの影を映すには ( No.10 )
名前:wisteria 日時:2010/06/20 10:16

>ShadowTexture を DrawGraph で描画しても何も表示されないと言うことでしょうか? その通りです。 電GO!のようなゲームを作ろうとしていたのですが、 「運転台モード」は運転士の目線(フロントガラスの左寄り) なのですが、そうではなくど真ん中から見る設定をつけたときに 切り替え忘れないようにしなければ、という意味です。 >もしかして全ての描画物をカメラ座標系に変換してから描画しているのでしょうか? その通りです。
Re: 別ポリゴンの影を映すには ( No.11 )
名前:管理人 日時:2010/06/21 01:17

> >ShadowTexture を DrawGraph で描画しても何も表示されないと言うことでしょうか? > その通りです。 うーん何も表示されませんか・・・ > 電GO!のようなゲームを作ろうとしていたのですが、 > 「運転台モード」は運転士の目線(フロントガラスの左寄り) > なのですが、そうではなくど真ん中から見る設定をつけたときに > 切り替え忘れないようにしなければ、という意味です。 > > >もしかして全ての描画物をカメラ座標系に変換してから描画しているのでしょうか? > その通りです。 そうでしたか 今回お書き込みいただいたことを踏まえて改めて載せていただいたソースを拝見しましたが、 現状のままでも ShadowTexture を DrawGraph で描画したら影の元が表示されそうです これ以上は掲示板に載せていただいた部分だけで原因を突き止めるのは難しい感じなので、 もし不都合が無ければ wisteria さんが開発中のプログラムを必要な画像ファイル等も含めて BQE00322(あっとまーく)nifty.com まで送っていただけないでしょうか?

Page: 1 |