[Dx_lib]3D描画で画像をループ、フェードインさせたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ようすけ
記事: 12
登録日時: 13年前

[Dx_lib]3D描画で画像をループ、フェードインさせたい

#1

投稿記事 by ようすけ » 13年前

今、龍神録をベースにSTGを作ろうとしており、龍神録59章にあるように画像を連続でループ、3D表示をさせようとしています。
VC+2010を使って開発を行っています。プログラミング暦はC++は半年程度です。あまり良く分かっていません。

しかし画像のフェードインの入り方が非常に不恰好な状態です。
59章にあるように「フェードイン開始場所(fy、59章ではFromZにあたる部分)」「フェードイン終了場所(start_y、59章ではFadeFromZ)」を定め、
以下のような関数でフェードインを設定しています。
x,y,zを中心とし、lenによって画像の大きさを制御、端の4点を計算し描画している状態になります。
画像はy方向の負に向かって進み、徐々に小さくなっていきます。
len=25、fy=105、start_y=55、でyが徐々に小さくなっていくと思っていただければいいかと思います。
この後で、DrawPolygon3Dbaseで描画するのですが、
具体的に何が起こるかというと、fyに、yの下端が重なった瞬間に全体が表示されてしまいます。
結果、本当はfyよりもyの値が大きい場合には表示されて欲しくない画像がfyよりも前にあるときにも画面に出てしまい
画像が急にぼうっと現れた状態になってしまいます。

コード:

//VECTOR_3Dに値を渡す関数
void Vector_ins(VERTEX_3D v[4],VECTOR &rot, float x, float y,float z, float len,float fy,float start_y, float angle)
{
            v[0].pos.x = x-len;    v[0].pos.y = y+len ;   v[0].pos.z = z;
            v[0].u = 0.0F ;
            v[0].v = 0.0F ;

			v[1].pos.x = x-len;    v[1].pos.y = y-len ;   v[1].pos.z = z;
            v[1].u = 0.0F ;
            v[1].v = 1.0F ;

            v[2].pos.x = x+len;    v[2].pos.y = y+len ;   v[2].pos.z = z;
            v[2].u = 1.0F ;
            v[2].v = 0.0F ;
            
			v[3].pos.x = x+len;    v[3].pos.y = y-len ;   v[3].pos.z = z;
            v[3].u = 1.0F ;
            v[3].v = 1.0F ;

            v[0].r = v[0].g = v[0].b = 255 ;
            v[1].r = v[1].g = v[1].b = 255 ;
            v[2].r = v[2].g = v[2].b = 255 ;
            v[3].r = v[3].g = v[3].b = 255 ;

			//指定された値より小さければフェードアウト
			if(type == 1)
			{
				for(int i = 0; i<4;i++)
				{
					if(start_y<=v[i].pos.y)
					{
						v[i].a = (unsigned char)0.f;
					}
					else if(fy <v[i].pos.y && start_y > v[i].pos.y)
					{
						v[i].a =255.f*(start_y-v[i].pos.y)/(start_y-fy) ;
					}
					else
					{
						v[i].a = 255.f;
					}
				}
			}
}

そこで、自分なりにDrawPolygon3Dbaseの透過度によるグラデーションの仕様を考えてみたのですが、
添付する画像と同じイメージで合っているでしょうか?
もしこうなっているのであれば、画像の下端がfyと同じになった瞬間に画像全体が表示されてしまうこともうなづけます。
もしそうであれば、どうすれば第59章の地面のように綺麗にフェードインさせることが出来るでしょうか?
59章のサンプルでは画像を限りなく遠くでフェードアウトさせることでごまかしているように見えるのですが
どうやっているかは完全にはまだ理解できていません。

分かりにくい質問で申し訳ありません、できればソース全文を貼りたいのですがコードが大規模になってしまっているため、
もし質問に具体的にお答えいただける方がいらっしゃるようであればすぐにソースコードをZipで貼らせて頂きます。
添付ファイル
test.png
test.png (21.97 KiB) 閲覧数: 5958 回

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#2

投稿記事 by softya(ソフト屋) » 13年前

みなさん答えづらいと思うので単体で動く短くしたサンプルコードは作れないでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#3

投稿記事 by ISLe » 13年前

良く分からないですが『急にぼうっと現れる』という点から想像するに、半透明のポリゴンは奥から順に描画する必要がありますが、そうなってないところがあるのでは?

ようすけ
記事: 12
登録日時: 13年前

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#4

投稿記事 by ようすけ » 13年前

softya(ソフト屋)様
大変お待たせしていました申し訳ございません。
サンプルコード単体で起動するものを作るのに手間取ってしまいました。
以下がそのコードになります、Dxlib.hの場所は適宜変更してください。
サンプルとして仕様している画像も添付させていただきますので
名前をtest3Dgrとして実行ファイルの場所に入れてください。

コード:

#include "../../include/DxLib.h"

//1種類あたり描画できる3D背景の枚数
#define TD_BASE_MAX 10
//描画できる3D背景の種類数
#define TD_CORE_MAX 10
//3D統括する構造体の種類数
#define TD_MAX 10
//π
#define PI 3.1415926535898
//フィールドの広さ
#define FMX 384
#define FMY 448
//フィールドの左上の座標
#define FX 32
#define FY 16

//描画用ベクトルの定義
VECTOR p = { 0, 0, 0 }, rot[3] = {{0,0,0},{0,0,0},{0,0,0}};
//背景用画像
int img_back[20];
int func_state=0;

//実際に描画する構造体
typedef struct{
	//現在の座標
	float x,y,z;
	//描画点
    VERTEX_3D vertex[4];
}td_base_t;

//3D描画集合体
typedef struct{
	td_base_t base[TD_BASE_MAX];
	//描画するかどうか、描画する枚数(縦に何枚やるか)、描画する画像のナンバー
	int flag,num,img_id;
	//画像の基本となる位置xyz、描画の大きさ、角度、どこからフェードインするか、どこからスタートするか、どこで描画を消すか
	float sx,sy,sz,len,angle,from_y,start_y,end_y;
}td_core_t;

typedef struct{
	//縦にどれだけごとに描画するか、横にどれだけごとに並べるか、セット中心、XYZ方向へ移動させるスピード
	float every,set,center,spd_x,spd_y,spd_z;
	//描写する絵に割り当てる構造体の数(横に何枚並べるか)、スライド方向(今のとこ1で水平方向,2は空中の水平方向)
	int str_num,type,flag;
	td_core_t core[TD_CORE_MAX];
}td_t;

td_t td[TD_CORE_MAX];//3D管理

//3D要素配列のxyzに値を入れていく関数、numにはtdの番号を入れる、num2にはtd.coreの番号を入れる(tdのnum)すなわちi、num3にはtd.core.baseの番号
void td_ins_first(float x,float y,float z,float every,int num,int num2,int num3,int type){
	if(type==1)
	{
		td[num].core[num2].base[num3].x=x;
		td[num].core[num2].base[num3].y=y-num3*every;
		td[num].core[num2].base[num3].z=z;
	}
	else if(type == 2)
	{
		td[num].core[num2].base[num3].x=x;
		td[num].core[num2].base[num3].y=y+num3*every;
		td[num].core[num2].base[num3].z=z;
	}
}

//スワップ関数
void SwapObChild(td_base_t *Ob1,td_base_t *Ob2){
    td_base_t t = *Ob1;
    *Ob1 = *Ob2;
    *Ob2 = t;
}

//比較関数
void SortObject(int n){
    int i,j,k;
	for (i = 0; i < td[n].str_num; i++) {
			if(td[n].core[i].flag==1)
			{
				for(j = 0; j < td[n].core[i].num;j++)
				{
					for (k = j + 1; k < td[n].core[i].num ; k++) {
						if(td[n].type==1)//地上のとき
						{
							if (td[n].core[i].base[j].y < td[n].core[i].base[k].y ) {
								SwapObChild( &td[n].core[i].base[j],  &td[n].core[i].base[k] );
						}
							else if(td[n].type == 2)//上空のとき
							if (td[n].core[i].base[j].y > td[n].core[i].base[k].y ) {
								SwapObChild( &td[n].core[i].base[j],  &td[n].core[i].base[k] );
						}
					}
				}
			}
		}
	}
}

//td_base内のxyz座標を更新するプログラム。numにはtd_massの配列番号を渡す
void Vector_slide(float *x,float *y,float *z,int num,int type,float from_y,float sy,float end_y)
{
	*x+=td[num].spd_x;
	*y+=td[num].spd_y;
    *z+=td[num].spd_z;
	if(type==1)
	{
		if(*y<=end_y)
		{
			*y=sy;
		}
	}
	else if(type == 2)
	{
		if(*y>=end_y)
		{
			*y=sy;
		}
	}
}

//VECTOR_3Dに値を渡す関数
void Vector_ins(VERTEX_3D v[4],VECTOR &rot, float x, float y,float z, float len,float fy,float start_y, float angle,int type)
{
            v[0].pos.x = x-len;    v[0].pos.y = y+len ;   v[0].pos.z = z;
            v[0].u = 0.0F ;
            v[0].v = 0.0F ;

			v[1].pos.x = x-len;    v[1].pos.y = y-len ;   v[1].pos.z = z;
            v[1].u = 0.0F ;
            v[1].v = 1.0F ;

            v[2].pos.x = x+len;    v[2].pos.y = y+len ;   v[2].pos.z = z;
            v[2].u = 1.0F ;
            v[2].v = 0.0F ;
            
			v[3].pos.x = x+len;    v[3].pos.y = y-len ;   v[3].pos.z = z;
            v[3].u = 1.0F ;
            v[3].v = 1.0F ;


            // 輝度は全要素100%
            v[0].r = v[0].g = v[0].b = 255 ;
            v[1].r = v[1].g = v[1].b = 255 ;
            v[2].r = v[2].g = v[2].b = 255 ;
            v[3].r = v[3].g = v[3].b = 255 ;

			//指定された値より小さければフェードアウト
			if(type == 1)
			{
				for(int i = 0; i<4;i++)
				{
					if(start_y<=v[i].pos.y)
					{
						v[i].a = (unsigned char)0.f;
					}
					else if(fy <v[i].pos.y && start_y > v[i].pos.y)
					{
						v[i].a =255.f*(start_y-v[i].pos.y)/(start_y-fy) ;
					}
					else
					{
						v[i].a = 255.f;
					}
				}
			}

			rot.x=angle;
			rot.y=0;
			rot.z=0;
}


// 行列計算 
void CalcRotateMatrix(MATRIX *pMatResult, const VECTOR& pos, const VECTOR &rot) 
{ 
    // 移動 
    MATRIX m; 
    CreateTranslationMatrix(pMatResult, pos.x, pos.y, pos.z); 

    // 回転Z 
    CreateRotationZMatrix(&m, rot.z); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 

    // 回転Y 
    CreateRotationYMatrix(&m, rot.y); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 

    // 回転X 
    CreateRotationXMatrix(&m, rot.x); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 
}

// ワールド行列を変更して表示 
void DrawTransRotatePolygon1(int img, VERTEX_3D *vertex, int vertexNum, const VECTOR& pos, const VECTOR &rot) 
{ 
    // 行列計算 
    MATRIX  matResult, matOrgWorld; 
    CalcRotateMatrix(&matResult, pos, rot); 
    GetTransformToWorldMatrix(&matOrgWorld); 

    // 描画 
    SetTransformToWorld(&matResult); 
    DrawPolygon3DBase(vertex, vertexNum, DX_PRIMTYPE_TRIANGLESTRIP, img, TRUE); 
    SetTransformToWorld(&matOrgWorld); 
}

//3Dにおける中心点制御
void move_view(){
	float X=640.f, Y=480.f; // ウィンドウのサイズ
	float Xd=-(X/2-FMX/2-FX), Yd=0.f ; // 消失点の移動量
	MATRIX mat;
	CreateViewportMatrix(&mat, X/2.f+Xd, Y/2.f+Yd, X, Y);
	SetTransformToViewport(&mat);
}

//カメラの初期設定
void SetDefaultCamera() 
{ 
	move_view();
    MATRIX cam; 
	float Fx=0,Fy=0;
	//カメラの位置、注視点、上方向
    VECTOR vCamPos = { Fx, Fy, 100 }, vCamAt = { 0, 0, 0 }, vCamUp = { 0, 1, 0 }; 
    CreateLookAtMatrix(&cam, &vCamPos, &vCamAt, &vCamUp); 
    SetTransformToView(&cam); 
}


void load(){
		img_back[1] = LoadGraph("test3Dgr.png");

	//カメラ位置の初期設定(元関数はgraph_back.cppに)
	SetDefaultCamera();

		//描画画像初期値(ステージごとや道中でも変える必要?)

	//全体描画を統括する構造体の初期値
	//横、縦、中心
	td[0].set=50.0f;
	td[0].every=50.0f;
	td[0].center=19.2f;

	//横枚数、速度、タイプ、フラグ
	td[0].str_num=5;
	td[0].spd_x=0.f;
	td[0].spd_y=-1.0f;
	td[0].spd_z=0.f;
	td[0].type=1;
	td[0].flag=1;

	//地上側の描画
	for(int i=0;i<td[0].str_num;i++)
	{
			td[0].core[i].flag=1;
			td[0].core[i].img_id=1;
			td[0].core[i].num=5;
			td[0].core[i].angle=-13*PI/36;

			//画面に平行な場合はXが基準となる

			td[0].core[i].sy=80.0f;
			td[0].core[i].sz=-23.f;
			td[0].core[i].len=25.0f;

			td[0].core[i].from_y=td[0].core[i].sy-3.0f*td[0].core[i].len;
			td[0].core[i].start_y=td[0].core[i].sy-1.0f*td[0].core[i].len;
			td[0].core[i].end_y=-170.f;

			//横に並べる枚数に応じて、並べる方向(今回はX)ごとの中心を計算
			td[0].core[i].sx=td[0].center+td[0].set*(i-td[0].str_num/2);

			//以上のXYZを実際に各baseに入れていく。
			for(int j=0; j< td[0].core[i].num;j++)
			{
				td_ins_first(td[0].core[i].sx,td[0].core[i].sy,td[0].core[i].sz,td[0].every,0,i,j,td[0].type);
			}
	}
}

void graph_back00(){//通常背景

	SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//ポリゴンが荒く見えないような描画の仕方「バイリニア法」
	for(int n=0;n<TD_MAX;n++)
	{
		if(td[n].flag==1)
		{
			SortObject(n);
			for(int i=0;i<td[0].str_num;i++)
			{
				if(td[n].core[i].flag==1)
				{
					for(int j=0;j<td[n].core[i].num;j++)
					{
						Vector_ins(td[n].core[i].base[j].vertex,rot[n],td[n].core[i].base[j].x,td[n].core[i].base[j].y,td[n].core[i].base[j].z,
							td[n].core[i].len,td[n].core[i].from_y,td[n].core[i].start_y,td[n].core[i].angle,td[n].type);

						DrawTransRotatePolygon1(img_back[td[n].core[i].img_id], td[n].core[i].base[j].vertex, 4, p, rot[n]);
						Vector_slide(&td[n].core[i].base[j].x,&td[n].core[i].base[j].y,&td[n].core[i].base[j].z,n,
							td[n].type,td[n].core[i].from_y,td[n].core[i].sy,td[n].core[i].end_y);
					}
				}
			}
		}
	}

	SetDrawMode(DX_DRAWMODE_NEAREST);//描画方法を元に戻す
}

void graph_back_main(){
                graph_back00();
}
	
//ゲームの初期化
void ini(){
		memset(td,0,sizeof(td_t)*TD_MAX);
}

//ループで必ず行う3大処理
int ProcessLoop(){
	if(ProcessMessage()!=0)return -1;//プロセス処理がエラーなら-1を返す
	if(ClearDrawScreen()!=0)return -1;//画面クリア処理がエラーなら-1を返す
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
        ChangeWindowMode(TRUE);//ウィンドウモード
        if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

        while(ProcessLoop()==0){//メインループ
                switch(func_state){
                        case 0://初回のみ入る処理
								ini();
                                load();         //データロード
                                func_state=100;
                                break;

                        case 100://通常処理

                                graph_back_main();

                                break;
                        default:
                                printfDx("不明なfunc_state\n");
                                break;
                }
                ScreenFlip();//裏画面反映
        }
        DxLib_End();//DXライブラリ終了処理
        return 0;
}
ISLe様
一応ソートはしているのですがだめなようです。
コードは上記にて貼らせて頂きました。
添付ファイル
test3Dgr2.png

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#5

投稿記事 by softya(ソフト屋) » 13年前

とりあえず背景黒で溶けこませるのならフォグが簡単ですよ。

フォグのサンプル。

コード:

#include "DxLib.h"
 
//1種類あたり描画できる3D背景の枚数
#define TD_BASE_MAX 10
//描画できる3D背景の種類数
#define TD_CORE_MAX 10
//3D統括する構造体の種類数
#define TD_MAX 10
//π
#define PI 3.1415926535898
//フィールドの広さ
#define FMX 384
#define FMY 448
//フィールドの左上の座標
#define FX 32
#define FY 16
 
//描画用ベクトルの定義
VECTOR p = { 0, 0, 0 }, rot[3] = {{0,0,0},{0,0,0},{0,0,0}};
//背景用画像
int img_back[20];
int func_state=0;
 
//実際に描画する構造体
typedef struct{
    //現在の座標
    float x,y,z;
    //描画点
    VERTEX_3D vertex[4];
}td_base_t;
 
//3D描画集合体
typedef struct{
    td_base_t base[TD_BASE_MAX];
    //描画するかどうか、描画する枚数(縦に何枚やるか)、描画する画像のナンバー
    int flag,num,img_id;
    //画像の基本となる位置xyz、描画の大きさ、角度、どこからフェードインするか、どこからスタートするか、どこで描画を消すか
    float sx,sy,sz,len,angle,from_y,start_y,end_y;
}td_core_t;
 
typedef struct{
    //縦にどれだけごとに描画するか、横にどれだけごとに並べるか、セット中心、XYZ方向へ移動させるスピード
    float every,set,center,spd_x,spd_y,spd_z;
    //描写する絵に割り当てる構造体の数(横に何枚並べるか)、スライド方向(今のとこ1で水平方向,2は空中の水平方向)
    int str_num,type,flag;
    td_core_t core[TD_CORE_MAX];
}td_t;
 
td_t td[TD_CORE_MAX];//3D管理
 
//3D要素配列のxyzに値を入れていく関数、numにはtdの番号を入れる、num2にはtd.coreの番号を入れる(tdのnum)すなわちi、num3にはtd.core.baseの番号
void td_ins_first(float x,float y,float z,float every,int num,int num2,int num3,int type){
    if(type==1)
    {
        td[num].core[num2].base[num3].x=x;
        td[num].core[num2].base[num3].y=y-num3*every;
        td[num].core[num2].base[num3].z=z;
    }
    else if(type == 2)
    {
        td[num].core[num2].base[num3].x=x;
        td[num].core[num2].base[num3].y=y+num3*every;
        td[num].core[num2].base[num3].z=z;
    }
}
 
//スワップ関数
void SwapObChild(td_base_t *Ob1,td_base_t *Ob2){
    td_base_t t = *Ob1;
    *Ob1 = *Ob2;
    *Ob2 = t;
}
 
//比較関数
void SortObject(int n){
    int i,j,k;
    for (i = 0; i < td[n].str_num; i++) {
            if(td[n].core[i].flag==1)
            {
                for(j = 0; j < td[n].core[i].num;j++)
                {
                    for (k = j + 1; k < td[n].core[i].num ; k++) {
                        if(td[n].type==1)//地上のとき
                        {
                            if (td[n].core[i].base[j].y < td[n].core[i].base[k].y ) {
                                SwapObChild( &td[n].core[i].base[j],  &td[n].core[i].base[k] );
                        }
                            else if(td[n].type == 2)//上空のとき
                            if (td[n].core[i].base[j].y > td[n].core[i].base[k].y ) {
                                SwapObChild( &td[n].core[i].base[j],  &td[n].core[i].base[k] );
                        }
                    }
                }
            }
        }
    }
}
 
//td_base内のxyz座標を更新するプログラム。numにはtd_massの配列番号を渡す
void Vector_slide(float *x,float *y,float *z,int num,int type,float from_y,float sy,float end_y)
{
    *x+=td[num].spd_x;
    *y+=td[num].spd_y;
    *z+=td[num].spd_z;
    if(type==1)
    {
        if(*y<=end_y)
        {
            *y=sy;
        }
    }
    else if(type == 2)
    {
        if(*y>=end_y)
        {
            *y=sy;
        }
    }
}
 
//VECTOR_3Dに値を渡す関数
void Vector_ins(VERTEX_3D v[4],VECTOR &rot, float x, float y,float z, float len,float fy,float start_y, float angle,int type)
{
            v[0].pos.x = x-len;    v[0].pos.y = y+len ;   v[0].pos.z = z;
            v[0].u = 0.0F ;
            v[0].v = 0.0F ;
 
            v[1].pos.x = x-len;    v[1].pos.y = y-len ;   v[1].pos.z = z;
            v[1].u = 0.0F ;
            v[1].v = 1.0F ;
 
            v[2].pos.x = x+len;    v[2].pos.y = y+len ;   v[2].pos.z = z;
            v[2].u = 1.0F ;
            v[2].v = 0.0F ;
            
            v[3].pos.x = x+len;    v[3].pos.y = y-len ;   v[3].pos.z = z;
            v[3].u = 1.0F ;
            v[3].v = 1.0F ;
 
 
            // 輝度は全要素100%
            v[0].r = v[0].g = v[0].b = 255 ;
            v[1].r = v[1].g = v[1].b = 255 ;
            v[2].r = v[2].g = v[2].b = 255 ;
            v[3].r = v[3].g = v[3].b = 255 ;
 
            //指定された値より小さければフェードアウト
            if(type == 1)
            {
                for(int i = 0; i<4;i++)
                {
					/*
                    if(start_y<=v[i].pos.y)
                    {
                        v[i].a = (unsigned char)0.f;
                    }
                    else if(fy <v[i].pos.y && start_y > v[i].pos.y)
                    {
                        v[i].a =255.f*(start_y-v[i].pos.y)/(start_y-fy) ;
                    }
                    else
                    */
                    {
                        v[i].a = 255.f;
                    }
                }
            }
 
            rot.x=angle;
            rot.y=0;
            rot.z=0;
}
 
 
// 行列計算 
void CalcRotateMatrix(MATRIX *pMatResult, const VECTOR& pos, const VECTOR &rot) 
{ 
    // 移動 
    MATRIX m; 
    CreateTranslationMatrix(pMatResult, pos.x, pos.y, pos.z); 
 
    // 回転Z 
    CreateRotationZMatrix(&m, rot.z); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 
 
    // 回転Y 
    CreateRotationYMatrix(&m, rot.y); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 
 
    // 回転X 
    CreateRotationXMatrix(&m, rot.x); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 
}
 
// ワールド行列を変更して表示 
void DrawTransRotatePolygon1(int img, VERTEX_3D *vertex, int vertexNum, const VECTOR& pos, const VECTOR &rot) 
{ 
    // 行列計算 
    MATRIX  matResult, matOrgWorld; 
    CalcRotateMatrix(&matResult, pos, rot); 
    GetTransformToWorldMatrix(&matOrgWorld); 
 
    // 描画 
    SetTransformToWorld(&matResult); 
    DrawPolygon3DBase(vertex, vertexNum, DX_PRIMTYPE_TRIANGLESTRIP, img, TRUE); 
    SetTransformToWorld(&matOrgWorld); 
}
 
//3Dにおける中心点制御
void move_view(){
    float X=640.f, Y=480.f; // ウィンドウのサイズ
    float Xd=-(X/2-FMX/2-FX), Yd=0.f ; // 消失点の移動量
    MATRIX mat;
    CreateViewportMatrix(&mat, X/2.f+Xd, Y/2.f+Yd, X, Y);
    SetTransformToViewport(&mat);
}
 
//カメラの初期設定
void SetDefaultCamera() 
{ 
    move_view();
    MATRIX cam; 
    float Fx=0,Fy=0;
    //カメラの位置、注視点、上方向
    VECTOR vCamPos = { Fx, Fy, 100 }, vCamAt = { 0, 0, 0 }, vCamUp = { 0, 1, 0 }; 
    CreateLookAtMatrix(&cam, &vCamPos, &vCamAt, &vCamUp); 
    SetTransformToView(&cam); 
}
 
 
void load(){
        img_back[1] = LoadGraph("test3Dgr2.png");
 
    //カメラ位置の初期設定(元関数はgraph_back.cppに)
    SetDefaultCamera();
 
        //描画画像初期値(ステージごとや道中でも変える必要?)
 
    //全体描画を統括する構造体の初期値
    //横、縦、中心
    td[0].set=50.0f;
    td[0].every=50.0f;
    td[0].center=19.2f;
 
    //横枚数、速度、タイプ、フラグ
    td[0].str_num=5;
    td[0].spd_x=0.f;
    td[0].spd_y=-1.0f;
    td[0].spd_z=0.f;
    td[0].type=1;
    td[0].flag=1;
 
    //地上側の描画
    for(int i=0;i<td[0].str_num;i++)
    {
            td[0].core[i].flag=1;
            td[0].core[i].img_id=1;
            td[0].core[i].num=5;
            td[0].core[i].angle=-13*PI/36;
 
            //画面に平行な場合はXが基準となる
 
            td[0].core[i].sy=80.0f;
            td[0].core[i].sz=-23.f;
            td[0].core[i].len=25.0f;
 
            td[0].core[i].from_y=td[0].core[i].sy-3.0f*td[0].core[i].len;
            td[0].core[i].start_y=td[0].core[i].sy-1.0f*td[0].core[i].len;
            td[0].core[i].end_y=-170.f;
 
            //横に並べる枚数に応じて、並べる方向(今回はX)ごとの中心を計算
            td[0].core[i].sx=td[0].center+td[0].set*(i-td[0].str_num/2);
 
            //以上のXYZを実際に各baseに入れていく。
            for(int j=0; j< td[0].core[i].num;j++)
            {
                td_ins_first(td[0].core[i].sx,td[0].core[i].sy,td[0].core[i].sz,td[0].every,0,i,j,td[0].type);
            }
    }
}
 
void graph_back00(){//通常背景
 
    SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//ポリゴンが荒く見えないような描画の仕方「バイリニア法」
    for(int n=0;n<TD_MAX;n++)
    {
        if(td[n].flag==1)
        {
            SortObject(n);
            for(int i=0;i<td[0].str_num;i++)
            {
                if(td[n].core[i].flag==1)
                {
                    for(int j=0;j<td[n].core[i].num;j++)
                    {
                        Vector_ins(td[n].core[i].base[j].vertex,rot[n],td[n].core[i].base[j].x,td[n].core[i].base[j].y,td[n].core[i].base[j].z,
                            td[n].core[i].len,td[n].core[i].from_y,td[n].core[i].start_y,td[n].core[i].angle,td[n].type);
 
                        DrawTransRotatePolygon1(img_back[td[n].core[i].img_id], td[n].core[i].base[j].vertex, 4, p, rot[n]);
                        Vector_slide(&td[n].core[i].base[j].x,&td[n].core[i].base[j].y,&td[n].core[i].base[j].z,n,
                            td[n].type,td[n].core[i].from_y,td[n].core[i].sy,td[n].core[i].end_y);
                    }
                }
            }
        }
    }
 
    SetDrawMode(DX_DRAWMODE_NEAREST);//描画方法を元に戻す
}
 
void graph_back_main(){
                graph_back00();
}
    
//ゲームの初期化
void ini(){
        memset(td,0,sizeof(td_t)*TD_MAX);
}
 
//ループで必ず行う3大処理
int ProcessLoop(){
    if(ProcessMessage()!=0)return -1;//プロセス処理がエラーなら-1を返す
    if(ClearDrawScreen()!=0)return -1;//画面クリア処理がエラーなら-1を返す
    return 0;
}
 
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
        ChangeWindowMode(TRUE);//ウィンドウモード
        if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
        
	 	// フォグを有効にする
		SetFogEnable( TRUE ) ;

		// フォグの色を黒にする
		SetFogColor( 0, 0, 0 ) ;

		// フォグの開始距離を100、終了距離を150にする
		SetFogStartEnd( 100.0f, 150.0f ) ;
	
        while(ProcessLoop()==0){//メインループ
                switch(func_state){
                        case 0://初回のみ入る処理
                                ini();
                                load();         //データロード
                                func_state=100;
                                break;
 
                        case 100://通常処理
 
                                graph_back_main();
 
                                break;
                        default:
                                printfDx("不明なfunc_state\n");
                                break;
                }
                ScreenFlip();//裏画面反映
        }
        DxLib_End();//DXライブラリ終了処理
        return 0;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ようすけ
記事: 12
登録日時: 13年前

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#6

投稿記事 by ようすけ » 13年前

softya(ソフト屋)様
お早いお返事ありがとうございます。
早速頂いたコードで実行してみたのですが、フェード位置の開始が不自然なのには変わりありませんでした。
そちらではこのコードで違和感なく連続して表示されているのでしょうか?
また後学のためにお伺いしたいのですが、背景が黒でなく、別の2D画像であったり、3Dの描画であった場合になにか解決策はあるのでしょうか?
実際の画面では水平線などを表示して空との境界を作りたいと思っているのですが・・・

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#7

投稿記事 by ISLe » 13年前

『急にぼうっと現れ』ているのではなくて、明るくなったり暗くなったりしていますね。

ポリゴンの上端から下端までのグラデーションなので、下端がα値255でも、ズレているときはfyを境に255とはなりません。
ちょうどfyのあたりは128と255のあいだを行ったり来たりしています。

y軸方向にポリゴンを3分割してfyと交差する点のuv座標を調整してα値を255にする必要があります。
start_yと交差する点のuv座標も調整しないといけないです。
こういうときはポリゴンの座標を固定してuv座標をずらしてスクロールするのが王道ですね。
複数タイルまとめて描画して高速化もできますよ。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#8

投稿記事 by softya(ソフト屋) » 13年前

白~青い色で調整すれば水平線に溶けこむことは可能だと思います。
逆に半透明に消すと違和感があるかも知れませんし、頂点カラーで半透明にしているよりもフォグのほうが自然なはずですが・・・。

>早速頂いたコードで実行してみたのですが、フェード位置の開始が不自然なのには変わりありませんでした。
>そちらではこのコードで違和感なく連続して表示されているのでしょうか?

フォグの境界面は綺麗に消えていると思うんですけどね。
違和感は何処なのでしょうか? フォグとか半透明とか関係のない問題ではないのでしょうか?

スペースキーでフォグ版と半透明版を切り替えるようにしました。
背景は白っぽい水色にしてあります。

コード:

#include "DxLib.h"
 
//1種類あたり描画できる3D背景の枚数
#define TD_BASE_MAX 10
//描画できる3D背景の種類数
#define TD_CORE_MAX 10
//3D統括する構造体の種類数
#define TD_MAX 10
//π
#define PI 3.1415926535898
//フィールドの広さ
#define FMX 384
#define FMY 448
//フィールドの左上の座標
#define FX 32
#define FY 16
 
//描画用ベクトルの定義
VECTOR p = { 0, 0, 0 }, rot[3] = {{0,0,0},{0,0,0},{0,0,0}};
//背景用画像
int img_back[20];
int func_state=0;

//	フォグ
int FogSW = 1;

//実際に描画する構造体
typedef struct{
    //現在の座標
    float x,y,z;
    //描画点
    VERTEX_3D vertex[4];
}td_base_t;
 
//3D描画集合体
typedef struct{
    td_base_t base[TD_BASE_MAX];
    //描画するかどうか、描画する枚数(縦に何枚やるか)、描画する画像のナンバー
    int flag,num,img_id;
    //画像の基本となる位置xyz、描画の大きさ、角度、どこからフェードインするか、どこからスタートするか、どこで描画を消すか
    float sx,sy,sz,len,angle,from_y,start_y,end_y;
}td_core_t;
 
typedef struct{
    //縦にどれだけごとに描画するか、横にどれだけごとに並べるか、セット中心、XYZ方向へ移動させるスピード
    float every,set,center,spd_x,spd_y,spd_z;
    //描写する絵に割り当てる構造体の数(横に何枚並べるか)、スライド方向(今のとこ1で水平方向,2は空中の水平方向)
    int str_num,type,flag;
    td_core_t core[TD_CORE_MAX];
}td_t;
 
td_t td[TD_CORE_MAX];//3D管理

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey(){
        char tmpKey[256]; // 現在のキーの入力状態を格納する
        GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
        for( int i=0; i<256; i++ ){ 
                if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
                        Key[i]++;     // 加算
                } else {              // 押されていなければ
                        Key[i] = 0;   // 0にする
                }
        }
        return 0;
}
 
//3D要素配列のxyzに値を入れていく関数、numにはtdの番号を入れる、num2にはtd.coreの番号を入れる(tdのnum)すなわちi、num3にはtd.core.baseの番号
void td_ins_first(float x,float y,float z,float every,int num,int num2,int num3,int type){
    if(type==1)
    {
        td[num].core[num2].base[num3].x=x;
        td[num].core[num2].base[num3].y=y-num3*every;
        td[num].core[num2].base[num3].z=z;
    }
    else if(type == 2)
    {
        td[num].core[num2].base[num3].x=x;
        td[num].core[num2].base[num3].y=y+num3*every;
        td[num].core[num2].base[num3].z=z;
    }
}
 
//スワップ関数
void SwapObChild(td_base_t *Ob1,td_base_t *Ob2){
    td_base_t t = *Ob1;
    *Ob1 = *Ob2;
    *Ob2 = t;
}
 
//比較関数
void SortObject(int n){
    int i,j,k;
    for (i = 0; i < td[n].str_num; i++) {
            if(td[n].core[i].flag==1)
            {
                for(j = 0; j < td[n].core[i].num;j++)
                {
                    for (k = j + 1; k < td[n].core[i].num ; k++) {
                        if(td[n].type==1)//地上のとき
                        {
                            if (td[n].core[i].base[j].y < td[n].core[i].base[k].y ) {
                                SwapObChild( &td[n].core[i].base[j],  &td[n].core[i].base[k] );
                        }
                            else if(td[n].type == 2)//上空のとき
                            if (td[n].core[i].base[j].y > td[n].core[i].base[k].y ) {
                                SwapObChild( &td[n].core[i].base[j],  &td[n].core[i].base[k] );
                        }
                    }
                }
            }
        }
    }
}
 
//td_base内のxyz座標を更新するプログラム。numにはtd_massの配列番号を渡す
void Vector_slide(float *x,float *y,float *z,int num,int type,float from_y,float sy,float end_y)
{
    *x+=td[num].spd_x;
    *y+=td[num].spd_y;
    *z+=td[num].spd_z;
    if(type==1)
    {
        if(*y<=end_y)
        {
            *y=sy;
        }
    }
    else if(type == 2)
    {
        if(*y>=end_y)
        {
            *y=sy;
        }
    }
}
 
//VECTOR_3Dに値を渡す関数
void Vector_ins(VERTEX_3D v[4],VECTOR &rot, float x, float y,float z, float len,float fy,float start_y, float angle,int type)
{
            v[0].pos.x = x-len;    v[0].pos.y = y+len ;   v[0].pos.z = z;
            v[0].u = 0.0F ;
            v[0].v = 0.0F ;
 
            v[1].pos.x = x-len;    v[1].pos.y = y-len ;   v[1].pos.z = z;
            v[1].u = 0.0F ;
            v[1].v = 1.0F ;
 
            v[2].pos.x = x+len;    v[2].pos.y = y+len ;   v[2].pos.z = z;
            v[2].u = 1.0F ;
            v[2].v = 0.0F ;
            
            v[3].pos.x = x+len;    v[3].pos.y = y-len ;   v[3].pos.z = z;
            v[3].u = 1.0F ;
            v[3].v = 1.0F ;
 
 
            // 輝度は全要素100%
            v[0].r = v[0].g = v[0].b = 255 ;
            v[1].r = v[1].g = v[1].b = 255 ;
            v[2].r = v[2].g = v[2].b = 255 ;
            v[3].r = v[3].g = v[3].b = 255 ;
 
            //指定された値より小さければフェードアウト
            if(type == 1)
            {
                for(int i = 0; i<4;i++)
                {
					if( FogSW ) {
	                    v[i].a = 255.f;
	                } else {
	                    if(start_y<=v[i].pos.y)
	                    {
	                        v[i].a = (unsigned char)0.f;
	                    }
	                    else if(fy <v[i].pos.y && start_y > v[i].pos.y)
	                    {
	                        v[i].a =255.f*(start_y-v[i].pos.y)/(start_y-fy) ;
	                    }
	                    else
	                    {
	                        v[i].a = 255.f;
	                    }
					}
                }
            }
 
            rot.x=angle;
            rot.y=0;
            rot.z=0;
}
 
 
// 行列計算 
void CalcRotateMatrix(MATRIX *pMatResult, const VECTOR& pos, const VECTOR &rot) 
{ 
    // 移動 
    MATRIX m; 
    CreateTranslationMatrix(pMatResult, pos.x, pos.y, pos.z); 
 
    // 回転Z 
    CreateRotationZMatrix(&m, rot.z); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 
 
    // 回転Y 
    CreateRotationYMatrix(&m, rot.y); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 
 
    // 回転X 
    CreateRotationXMatrix(&m, rot.x); 
    CreateMultiplyMatrix(pMatResult, &m, pMatResult); 
}
 
// ワールド行列を変更して表示 
void DrawTransRotatePolygon1(int img, VERTEX_3D *vertex, int vertexNum, const VECTOR& pos, const VECTOR &rot) 
{ 
    // 行列計算 
    MATRIX  matResult, matOrgWorld; 
    CalcRotateMatrix(&matResult, pos, rot); 
    GetTransformToWorldMatrix(&matOrgWorld); 
 
    // 描画 
    SetTransformToWorld(&matResult); 
    DrawPolygon3DBase(vertex, vertexNum, DX_PRIMTYPE_TRIANGLESTRIP, img, TRUE); 
    SetTransformToWorld(&matOrgWorld); 
}
 
//3Dにおける中心点制御
void move_view(){
    float X=640.f, Y=480.f; // ウィンドウのサイズ
    float Xd=-(X/2-FMX/2-FX), Yd=0.f ; // 消失点の移動量
    MATRIX mat;
    CreateViewportMatrix(&mat, X/2.f+Xd, Y/2.f+Yd, X, Y);
    SetTransformToViewport(&mat);
}
 
//カメラの初期設定
void SetDefaultCamera() 
{ 
    move_view();
    MATRIX cam; 
    float Fx=0,Fy=0;
    //カメラの位置、注視点、上方向
    VECTOR vCamPos = { Fx, Fy, 100 }, vCamAt = { 0, 0, 0 }, vCamUp = { 0, 1, 0 }; 
    CreateLookAtMatrix(&cam, &vCamPos, &vCamAt, &vCamUp); 
    SetTransformToView(&cam); 
}
 
 
void load(){
        img_back[1] = LoadGraph("test3Dgr2.png");
 
    //カメラ位置の初期設定(元関数はgraph_back.cppに)
    SetDefaultCamera();
 
        //描画画像初期値(ステージごとや道中でも変える必要?)
 
    //全体描画を統括する構造体の初期値
    //横、縦、中心
    td[0].set=50.0f;
    td[0].every=50.0f;
    td[0].center=19.2f;
 
    //横枚数、速度、タイプ、フラグ
    td[0].str_num=5;
    td[0].spd_x=0.f;
    td[0].spd_y=-1.0f;
    td[0].spd_z=0.f;
    td[0].type=1;
    td[0].flag=1;
 
    //地上側の描画
    for(int i=0;i<td[0].str_num;i++)
    {
            td[0].core[i].flag=1;
            td[0].core[i].img_id=1;
            td[0].core[i].num=5;
            td[0].core[i].angle=-13*PI/36;
 
            //画面に平行な場合はXが基準となる
 
            td[0].core[i].sy=80.0f;
            td[0].core[i].sz=-23.f;
            td[0].core[i].len=25.0f;
 
            td[0].core[i].from_y=td[0].core[i].sy-3.0f*td[0].core[i].len;
            td[0].core[i].start_y=td[0].core[i].sy-1.0f*td[0].core[i].len;
            td[0].core[i].end_y=-170.f;
 
            //横に並べる枚数に応じて、並べる方向(今回はX)ごとの中心を計算
            td[0].core[i].sx=td[0].center+td[0].set*(i-td[0].str_num/2);
 
            //以上のXYZを実際に各baseに入れていく。
            for(int j=0; j< td[0].core[i].num;j++)
            {
                td_ins_first(td[0].core[i].sx,td[0].core[i].sy,td[0].core[i].sz,td[0].every,0,i,j,td[0].type);
            }
    }
}
 
void graph_back00(){//通常背景
 
    SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//ポリゴンが荒く見えないような描画の仕方「バイリニア法」
    DrawBox(0,0,640,480,GetColor(200,255,255),TRUE);
    for(int n=0;n<TD_MAX;n++)
    {
        if(td[n].flag==1)
        {
            SortObject(n);
            for(int i=0;i<td[0].str_num;i++)
            {
                if(td[n].core[i].flag==1)
                {
                    for(int j=0;j<td[n].core[i].num;j++)
                    {
                        Vector_ins(td[n].core[i].base[j].vertex,rot[n],td[n].core[i].base[j].x,td[n].core[i].base[j].y,td[n].core[i].base[j].z,
                            td[n].core[i].len,td[n].core[i].from_y,td[n].core[i].start_y,td[n].core[i].angle,td[n].type);
 
                        DrawTransRotatePolygon1(img_back[td[n].core[i].img_id], td[n].core[i].base[j].vertex, 4, p, rot[n]);
                        Vector_slide(&td[n].core[i].base[j].x,&td[n].core[i].base[j].y,&td[n].core[i].base[j].z,n,
                            td[n].type,td[n].core[i].from_y,td[n].core[i].sy,td[n].core[i].end_y);
                    }
                }
            }
        }
    }
 
    SetDrawMode(DX_DRAWMODE_NEAREST);//描画方法を元に戻す
}
 
void graph_back_main(){
                graph_back00();
}
    
//ゲームの初期化
void ini(){
        memset(td,0,sizeof(td_t)*TD_MAX);
}
 
//ループで必ず行う3大処理
int ProcessLoop(){
    if(ProcessMessage()!=0)return -1;//プロセス処理がエラーなら-1を返す
    if(ClearDrawScreen()!=0)return -1;//画面クリア処理がエラーなら-1を返す
    gpUpdateKey();
    return 0;
}
 
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
        ChangeWindowMode(TRUE);//ウィンドウモード
        if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
        
        while(ProcessLoop()==0){//メインループ
        	clsDx();
        	
        	//	切り替え?
        	if( Key[ KEY_INPUT_SPACE ] == 1 ){
        		FogSW = !FogSW;
			}

        	//	フォグが有効?
        	if( FogSW ) {
			 	// フォグを有効にする
				SetFogEnable( TRUE ) ;

				// フォグの色を背景に合わせる
				SetFogColor( 200, 255, 255 ) ;

				// フォグの開始距離と終了距離を設定する
				SetFogStartEnd( 100.0f, 160.0f ) ;
			} else {
			 	// フォグを無効にする
				SetFogEnable( FALSE ) ;
        	}
        
                switch(func_state){
                        case 0://初回のみ入る処理
                                ini();
                                load();         //データロード
                                func_state=100;
                                break;
 
                        case 100://通常処理
 
                                graph_back_main();
 
                                break;
                        default:
                                printfDx("不明なfunc_state\n");
                                break;
                }
                
        	if( FogSW ) {
				printfDx("フォグが有効。半透明が無効\n");
			} else {
				printfDx("フォグが無効。半透明が有効\n");
            }
            
            ScreenFlip();//裏画面反映
        }
        DxLib_End();//DXライブラリ終了処理
        return 0;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#9

投稿記事 by softya(ソフト屋) » 13年前

確かにUVスクロールにして頂点座標と頂点カラーを固定にするって手がありますね。少なくともパタパタすることは無くなります。背景次第では、そちらの方が自然でしょう。
どちらにしてもプログラムが無用に複雑なので整理したほうが良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ようすけ
記事: 12
登録日時: 13年前

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#10

投稿記事 by ようすけ » 13年前

softya(ソフト屋) 様
お早い返答本当にありがとうございます、ちょっとネットが固まってしまって返信が遅れました。

上手く口で伝えられないのですが、やはりstart_yに画像の下端がきたとき、fyを下端とした画像が急に現れているように見えます。
画像が区切りありの方なので分かりにくいのかもしれません。
マウスカーソルなどを画面に置いてみると、やはり今表示されている画像の上端(フェードインしてくる部分)が上下しているように見えます。
僕の目がおかしいだけなのでしょうか・・・w
区切りなしの画像も一応、いらないかもしれませんが添付しておきます。

>少なくともパタパタすることは無くなります。背景次第では、そちらの方が自然でしょう。
こちらでもfogの機能を調べてみましたが、空や壁にもなにかを表示させようとするとそうかもしれません。
fog自体は働いているようなので他になにか原因があるのでしょうか・・・?

ISLe様
ご返答本当にありがとうございます。

>ポリゴンの上端から下端までのグラデーションなので、下端がα値255でも、ズレているときはfyを境に255とはなりません。
>ちょうどfyのあたりは128と255のあいだを行ったり来たりしています。
コード上では1フレームにちょうど1ずつだけ変化するように指定しているのですが、ズレが発生するというのは
float型などを使っていて厳密には1ぴったりでないというのが原因ということでよろしいのでしょうか?
あまり細かいところを分かってなくてすいません。

>こういうときはポリゴンの座標を固定してuv座標をずらしてスクロールするのが王道ですね。
>複数タイルまとめて描画して高速化もできますよ。
なんとなくイメージは沸くのですがどうやればいいのかが分かりません・・・
特に、画像を固定したままでuvを動かすだけでなんでスクロールしているように見せられるかというところがよく分かりません。
大変あつかましいとは思うのですが、上のコードとは関係なくてもいいので
もしサンプルコードなどをいただければ幸いです。
高速化もできるとなると大変気になります。
添付ファイル
test3Dgr.png

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#11

投稿記事 by softya(ソフト屋) » 13年前

勉強になるので自分で組んでみてはどうでしょうか?
頂点をスクロールさせているのを止めて頂点位置を固定します。
代わりにUVで貼り込むテクスチャの位置を移動させることでスクロールします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#12

投稿記事 by ISLe » 13年前

ようすけ さんが書きました:コード上では1フレームにちょうど1ずつだけ変化するように指定しているのですが、ズレが発生するというのは
float型などを使っていて厳密には1ぴったりでないというのが原因ということでよろしいのでしょうか?
頂点を移動すると、fyを跨いでポリゴンを描画するときがありますよね。
fyの外側の頂点はα値255ですが、fy上のピクセルは内側の頂点のα値と距離の比率で決まります。その場合255より小さくなります。
ポリゴンの境目がfy上にあって跨いでないときはfy上のピクセルのα値は255です。
スクロールによってfy座標上のピクセルのα値が往復することになるわけです。

フォグで実装するときはα値を変化させてはいけないですけど、そのままになってないですか?

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#13

投稿記事 by ISLe » 13年前

サンプルプログラム作ってみました。
#ビューポートとカメラの調整にてこずった。

コード:

#include "DxLib.h"

int hBackgnd;
#define VERTEX_NUM 6
// 地表ポリゴン描画用頂点バッファ
VERTEX_3D v[VERTEX_NUM];
// 地表ポリゴンのテクスチャVテーブル
float v_table[VERTEX_NUM] = {
	0.0f, 0.0f,
	2.0f, 2.0f,
	4.0f, 4.0f
};
// スクロールオフセット
float scroll_offset;

void init()
{
	hBackgnd = LoadGraph("test3Dgr.png");

	for (int i=0; i<VERTEX_NUM; ++i) {
		v[i].r = v[i].g = v[i].b = 255;
		v[i].pos.z = 0.f;
	}
	// トライアングルストリップで4角形を2つ描く
	// 前半はフェード用にα値0~255
	v[0].pos.x = v[2].pos.x = v[4].pos.x = -100.f;
	v[1].pos.x = v[3].pos.x = v[5].pos.x =  100.f;
	v[0].pos.y = v[1].pos.y = -100.f;
	v[2].pos.y = v[3].pos.y =    0.f;
	v[4].pos.y = v[5].pos.y =  100.f;
	v[0].u = v[2].u = v[4].u = 0.0f;
	v[1].u = v[3].u = v[5].u = 4.0f;
	v[0].a = v[1].a = 0;
	v[2].a = v[3].a = 255;
	v[4].a = v[5].a = 255;

	MATRIX mat;
	float X=640.f, Y=480.f;
	float Xd=0.f, Yd=0.f;
	CreateViewportMatrix(&mat, X/2.f+Xd, Y/2.f+Yd, X, Y);
	SetTransformToViewport(&mat);
	VECTOR vCamPos = { 0, 200, 100 }, vCamAt = { 0, 0, 0 }, vCamUp = { 0, 0, 1 };
	CreateLookAtMatrix(&mat, &vCamPos, &vCamAt, &vCamUp);
	SetTransformToView(&mat);

	SetUseBackCulling(TRUE);
	// テクスチャを繰り返して描く
	SetTextureAddressModeUV(DX_TEXADDRESS_WRAP, DX_TEXADDRESS_WRAP);
}
void update()
{
	scroll_offset -= 0.05f;
	if (scroll_offset < -1.0f) {
		scroll_offset += 1.0f;
	}
	for (int i=0; i<VERTEX_NUM; ++i) {
		// 頂点バッファのテクスチャV座標を
		// スクロールオフセット分ズラす
		v[i].v = v_table[i] + scroll_offset;
	}
}
void render()
{
	// 一回の描画
	DrawPolygon3DBase(v, VERTEX_NUM, DX_PRIMTYPE_TRIANGLESTRIP, hBackgnd, TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	ChangeWindowMode(TRUE);
	if (DxLib_Init() != 0) return 0;
	SetDrawScreen(DX_SCREEN_BACK);
	init();
	while (ProcessMessage() == 0) {
		ClearDrawScreen();
		update();
		render();
		ScreenFlip();
	}
	DxLib_End();
	return 0;
}

ようすけ
記事: 12
登録日時: 13年前

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#14

投稿記事 by ようすけ » 13年前

softya(ソフト屋) 様
返信が遅れてしまい大変申し訳ございません。
その通りですね、一度自分なりにコードを改造してやってみようと思います。
fogのほうについてはこちらのミスでした、大変申し訳ございません。
もしuv系への修正で上手くいかない場合、またここで質問させていただいてもよろしいでしょうか。
それとも新規にトピックを立てた方がいいのでしょうか。

ISLe様
返信が遅れてしまい大変申し訳ございません。

>ポリゴンの境目がfy上にあって跨いでないときはfy上のピクセルのα値は255です。
>スクロールによってfy座標上のピクセルのα値が往復することになるわけです。

なるほど、やっぱりそういうことだったのですね。
現状のままではだめで、fogを使うかuv系を変化させる方向でないとダメそうです。
それにしても龍神録の方ではどうやっているんだろう・・・

>フォグで実装するときはα値を変化させてはいけないですけど、そのままになってないですか?

今確認してみたらその通りでした・・・本当に申し訳ございませんでした。


とりあえずuv系に組みなおしてみようと思います。サンプルコード、本当にありがとうございます。
これを見本として一度組みなおしてみようと思います。
もし上手くいかない場合、またここで質問させていただいてもよろしいでしょうか。
それとも新規にトピックを立てた方がいいのでしょうか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [Dx_lib]3D描画で画像をループ、フェードインさせたい

#15

投稿記事 by softya(ソフト屋) » 13年前

1~2週間の範囲ならOKですよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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