SetDrawScreenとカメラの設定について

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

SetDrawScreenとカメラの設定について

#1

投稿記事 by Priest » 13年前

DXライブラリ+C言語を用いています。
下記のように、1ループ中に裏画面とMakeScreenで作った画像の両方に同じものを描写しようとしています。
ですが、描写されるものが互いに異っています。
cameranoijiwaru.png
具体的に表現すると、カメラの方向はあっていますが、視野角か何かが変わってしまったのか、カメラの座標が少しずれたように見えます。
しかし、カメラの座標位置とそのアングルを表示させてみたところ、それは同じ値でした。

視野角を明示的に設定してみましたが、結果は変わらず。
以下に示すもの以外はカメラの調整は一切行っていません。

どうも気になって夜しか眠れません。
分かりにくいかもと思いますがよろしくお願いします。

コード:

    // 裏画面に描写対象を変更してキャラクタを描写
    SetDrawScreen(DX_SCREEN_BACK);
    カメラの座標や視点の角度を設定;
    // カメラの設定を反映
    SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t);
    背景やキャラクタ等のモデルの描写;

    // 描写対象にMakeScreenで作った描写可能な画像を設定し、同じ物を描写
    SetDrawScreen(Screen.GraphHandle);
    // SetDrawScreenするとカメラがリセットされると聞いたので再設定
    SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t);
    背景やキャラクタ等のモデルの描写;

    SetDrawScreen(DX_SCREEN_BACK); // 描写対象を元にもどす
 

コード:

#include <Priest.h>
int MyPolicy ( void ) { printf( "何事も楽しくね!" ); return 0; }

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

Re: SetDrawScreenとカメラの設定について

#2

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

コンパクトで動く再現できるコードを張ってもらってよいでしょうか?
モデルは使わずに、DrawTriangle3D()やDrawSphere3D()などを使ってください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Priest
記事: 123
登録日時: 13年前
住所: 愛知

Re: SetDrawScreenとカメラの設定について

#3

投稿記事 by Priest » 13年前

これでいかがでしょうか?
コードを切り張りしまくったので、見にくいところもあるかもしれませんが、よろしくお願いします。
シェーダ―ファイルも添付しておきます。
111行目に示しました通り、"Shader/GrayScale.pso"がpsoファイルの相対パスとなってます。

コード:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "DxLib.h"

#define WINDOWWIDTH 960
#define WINDOWHEIGHT 540
#define COLORBIT 32
#define REFRESHRATE 60
#define PCNUM 16
#define STAGESIZE 4000

#define M_PI 3

// 座標
struct VEC {
	double x; // x軸 
	double y; // y軸
	double z; // z軸
};

// 回転
struct ROT {
	double v; // 垂直
	double h; // 水平
	double t; // 捻り
};

// 画像用ハンドル
struct GRAPHHANDLE {
	int Screen; // 画面
};

// キャラ情報
struct PC {
	VEC PPos; // 一つ前の位置の座標
	VEC Pos; // 現在位置の座標
	VEC NPos; // 移動先の座標
	ROT Rot;    // 角度
	ROT RotTar; // 目標角度
};

// カメラ情報
struct CAMERA {
	VECTOR Pos,NPos; // 現在座標
	ROT Rot,RotTar; // 角度
	ROT Spd; //回転速度
	double Radius; //周回半径 
};

// ゲーム情報
struct GAME {
	int Frame;
};

// シェーダ管理用
struct SHADER {
	int Gray;	
};

// 構造体実体
PC Pc[PCNUM];
CAMERA Camera;
GAME Game;
SHADER Shader;
GRAPHHANDLE GraphHandle;

// その他グローバル変数
int PlayerID; // 私の操るキャラクタ(カメラはこのキャラクタを軸にして移動する

//キャラを描画
void PcDraw(void){
	for(int i=0;i<PCNUM;i++){
		DrawSphere3D(VGet(Pc[i].Pos.x,Pc[i].Pos.y,Pc[i].Pos.z),30,32,GetColor(0,255,0),GetColor(255,255,0),1);
	
	}
}

//マップを描画(マップの端を示す線を引くだけ)
void MapDraw(void){
	// 標準ライトの方向
	SetLightDirection(VGet(0.29f,-0.58f,-0.58f));

	//ステージ範囲区域を描画
	DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(-STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(-STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),VGet(STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(-STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),VGet(-STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(-STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
	DrawLine3D(VGet(-STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),VGet(-STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
}

// 初期化
void Init(void){
	// 初期設定
	SetGraphMode(WINDOWWIDTH,WINDOWHEIGHT,COLORBIT,REFRESHRATE);
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);

	// Zバッファへの書き込みを有効にする
	SetUseZBuffer3D(TRUE);
	SetWriteZBuffer3D(TRUE);

	// ピクセルシェーダバイナリコードの読み込み
	Shader.Gray = LoadPixelShader("Shader/GrayScale.pso");
}

// キャラクタの初期化
void PcInit(void){
	// ゲームに存在するすべてのキャラに対して
	for(int i=0;i<PCNUM;i++){
		// 座標
		Pc[i].Pos.x=GetRand(30000)/10.0-1500.0;
		Pc[i].Pos.y=GetRand(10000)/10.0-500.0;
		Pc[i].Pos.z=GetRand(30000)/10.0-1500.0;
		Pc[i].PPos=Pc[i].Pos;
		
		// 向き
		Pc[i].Rot.v=-atan2(-Pc[i].Pos.y,hypot(-Pc[i].Pos.z,-Pc[i].Pos.x));
		Pc[i].Rot.h=atan2(-Pc[i].Pos.x,-Pc[i].Pos.z);
		Pc[i].Rot.t=0.0;
	}
}

// カメラの初期化
void CameraInit(void){
	// 視点角度
	Camera.Rot=Pc[PlayerID].Rot;
	Camera.RotTar=Camera.Rot;

	// 周回半径
	Camera.Radius=300.0f;

	// 座標
	Camera.Pos.x = Pc[PlayerID].Pos.x-(Camera.Radius*sin(Camera.Rot.v+1.0f/2.0f*M_PI)*cos(1.0f/2.0f*M_PI-Camera.Rot.h))+(100.0f*sin(Camera.Rot.v)*sin(Camera.Rot.h));
	Camera.Pos.z = Pc[PlayerID].Pos.z-(Camera.Radius*sin(Camera.Rot.v+1.0f/2.0f*M_PI)*sin(1.0f/2.0f*M_PI-Camera.Rot.h))+(100.0f*sin(Camera.Rot.v)*cos(Camera.Rot.h));
	Camera.Pos.y = Pc[PlayerID].Pos.y-(Camera.Radius*cos(Camera.Rot.v+1.0f/2.0f*M_PI))+100.0f*cos(Camera.Rot.v);

	// カメラ反映
	SetupCamera_Perspective(M_PI/3);
	SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t);

}

// ゲーム情報の初期化
void PlayInit(void){
	// 初期化
	PlayerID=0; // 私の操るキャラクタ(カメラはこのキャラクタを軸にして移動する
	PcInit();
	CameraInit();
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	static VERTEX2DSHADER Vert[6];
    // 初期化
	Init();
	PlayInit();

	// ループ処理
    while(ScreenFlip()==0&&ProcessMessage()==0&&ClearDrawScreen()==0){
		static VERTEX2DSHADER Vert[6];
	
		// 頂点データの準備
		if(Game.Frame==0){
			// 描写可能な画像を作成
			SetUseDivGraphFlag(FALSE);
			SetDrawValidAlphaChannelGraphCreateFlag(TRUE);
			int ScreenWidth=1;
			do{ ScreenWidth*=2; }while(ScreenWidth<WINDOWWIDTH);
			GraphHandle.Screen=MakeScreen(ScreenWidth,ScreenWidth,0);
			SetDrawValidAlphaChannelGraphCreateFlag(FALSE);
			SetUseDivGraphFlag(TRUE);

			Vert[ 0 ].pos = VGet(   0.0f,   0.0f, 0.0f ) ;
			Vert[ 1 ].pos = VGet( 1024.0f,   0.0f, 0.0f ) ;
			Vert[ 2 ].pos = VGet(   0.0f, 1024.0f, 0.0f ) ;
			Vert[ 3 ].pos = VGet( 1024.0f, 1024.0f, 0.0f ) ;
			Vert[ 0 ].dif = GetColorU8( 255,255,255,255 ) ;
			Vert[ 0 ].spc = GetColorU8( 0,0,0,0 ) ;
			Vert[ 1 ].dif = GetColorU8( 255,255,255,255 ) ;
			Vert[ 1 ].spc = GetColorU8( 0,0,0,0 ) ;
			Vert[ 2 ].dif = GetColorU8( 255,255,255,255 ) ;
			Vert[ 2 ].spc = GetColorU8( 0,0,0,0 ) ;
			Vert[ 3 ].dif = GetColorU8( 255,255,255,255 ) ;
			Vert[ 3 ].spc = GetColorU8( 0,0,0,0 ) ;
			Vert[ 0 ].u = 0.0f ; Vert[ 0 ].v = 0.0f ;
			Vert[ 1 ].u = 1.0f ; Vert[ 1 ].v = 0.0f ;
			Vert[ 2 ].u = 0.0f ; Vert[ 2 ].v = 1.0f ;
			Vert[ 3	].u = 1.0f ; Vert[ 3 ].v = 1.0f ;
			Vert[ 0	].su = 0.0f ; Vert[ 0 ].sv = 0.0f ;
			Vert[ 1	].su = 1.0f ; Vert[ 1 ].sv = 0.0f ;
			Vert[ 2	].su = 0.0f ; Vert[ 2 ].sv = 1.0f ;
			Vert[ 3 ].su = 1.0f ; Vert[ 3 ].sv = 1.0f ;
			Vert[ 0 ].rhw = 1.0f ;
			Vert[ 1 ].rhw = 1.0f ;	
			Vert[ 2 ].rhw = 1.0f ;
			Vert[ 3 ].rhw = 1.0f ;
			Vert[ 4 ] = Vert[ 2 ] ;
			Vert[ 5 ] = Vert[ 1 ] ;
		}
	
		// グレースケール化した画像を作成
		SetDrawScreen(GraphHandle.Screen);
		ClearDrawScreen();

		// カメラの再設定
		SetupCamera_Perspective(M_PI/3);
		SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t) ;
		
		// 描写
		MapDraw(); // マップ描画
		PcDraw();  // キャラクタ描写
		
		// 描写対象を元に戻す
		SetDrawScreen(DX_SCREEN_BACK);
		
		// カメラも元に戻す
		SetupCamera_Perspective(M_PI/3);
		SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t);
		
		// 使用するテクスチャをセット
		SetUseTextureToShader(0, GraphHandle.Screen);
	
		// 使用するピクセルシェーダをセット
		SetUsePixelShader(Shader.Gray);

		// シェーダに定数セット(単に徐々に透明になる処理
		int cindex = GetConstIndexToShader("Alpha", Shader.Gray);
		float alpha;
		alpha=((float)(300.0f-Game.Frame)/255.0f);
		FLOAT4 Alpha = {1.0f, 1.0f, 1.0f, alpha};
	    SetPSConstF(cindex, Alpha);

		// 描画
		SetDrawBlendMode(DX_BLENDMODE_ALPHA,0);
		DrawPrimitive2DToShader( Vert, 6, DX_PRIMTYPE_TRIANGLELIST );
		SetDrawBlendMode(DX_BLENDMODE_NOBLEND,0);

		// ↑の描画と↓の描画は完全に重なるはず! なのに重ならない。のが今回の質問の本質。

		MapDraw();            // マップ描画
		PcDraw();             // キャラクタ描写

		// ゲーム内時間加算
		Game.Frame++;
	}

	DxLib_End(); // 後処理
	return 0;
} 
添付ファイル
Shader.zip
(367 バイト) ダウンロード数: 149 回

コード:

#include <Priest.h>
int MyPolicy ( void ) { printf( "何事も楽しくね!" ); return 0; }

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: SetDrawScreenとカメラの設定について

#4

投稿記事 by h2so5 » 13年前

いろいろ試しても解決しないので問題点だけ指摘しておくと、
  • 二回目にGraphHandle.Screenを裏画面に描画するときもパース付きで描画している
  • 最初に描画する時と二回目に描画するときで画面の比率が違う
両方またはどちらかが原因になっていると思われます。

「GraphHandle.Screenを裏画面に描画するときもパース付きで描画している」については、
カメラで写真を撮ってその写真をカメラの前に置いてまた撮影する状況を想像してください。
写真をカメラに平行に置いてあっても距離によってサイズが変わってしまいます。

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

Re: SetDrawScreenとカメラの設定について

#5

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

私の結論も同様です。同じサイズにしてDrawGraph(0,0,GraphHandle.Screen,FALSE);で描画すればピタリと重なり合います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Priest
記事: 123
登録日時: 13年前
住所: 愛知

Re: SetDrawScreenとカメラの設定について

#6

投稿記事 by Priest » 13年前

h2so5さん、softyaさん、

お二人のご指摘の通り、画像の大きさや比率をウィンドウサイズに合わせて描写した所、うまくいきました。
どこかで2^nを満たす大きさにするべきだよという過去ログを見たので今までのような実装になっていました。

「GraphHandle.Screenを裏画面に描画するときもパース付きで描画している」については、
本プログラムの仕様でナチュラルに回避してました。おかげさまで、ここを配慮する必要は現時点ではなさそうです。
念頭に入れておきます!

これで無事昼寝も堪能できるようになります。
ホントにありがとうございました。

コード:

#include <Priest.h>
int MyPolicy ( void ) { printf( "何事も楽しくね!" ); return 0; }

閉鎖

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