DxLibで3Dの海を作成する方法について
Posted: 2013年12月31日(火) 01:05
DxLibで3Dの戦艦や潜水艦などで艦隊戦を行うシミュレーションゲームを作ろうとしているのですが、どうしても海の処理がわかりません。
水中から海上を見た時や、波の作成などを教えてもらえませんか?
よろしくお願いします。
水中から海上を見た時や、波の作成などを教えてもらえませんか?
よろしくお願いします。
#include "DxLib.h"
#include <stdio.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
VERTEX3D Vertex[ 4 ] ;
WORD Index[ 6 ] ;
ChangeWindowMode(TRUE);
if( DxLib_Init() < 0 ) { return -1; }
SetDrawScreen( DX_SCREEN_BACK ) ;
// 4頂点分のデータをセット
Vertex[ 0 ].pos = VGet(-2000.0f, 0.0f,-2000.0f ) ;
Vertex[ 0 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 0 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 0 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 0 ].u = 0.0f ;
Vertex[ 0 ].v = 0.0f ;
Vertex[ 0 ].su = 0.0f ;
Vertex[ 0 ].sv = 0.0f ;
Vertex[ 1 ].pos = VGet( 2000.0f, 0.0f,-2000.0f) ;
Vertex[ 1 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 1 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 1 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 1 ].u = 0.0f ;
Vertex[ 1 ].v = 0.0f ;
Vertex[ 1 ].su = 0.0f ;
Vertex[ 1 ].sv = 0.0f ;
Vertex[ 2 ].pos = VGet( -2000.0f, 0.0f,2000.0f ) ;
Vertex[ 2 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 2 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 2 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 2 ].u = 0.0f ;
Vertex[ 2 ].v = 0.0f ;
Vertex[ 2 ].su = 0.0f ;
Vertex[ 2 ].sv = 0.0f ;
Vertex[ 3 ].pos = VGet( 2000.0f, 0.0f, 2000.0f ) ;
Vertex[ 3 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 3 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 3 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 3 ].u = 0.0f ;
Vertex[ 3 ].v = 0.0f ;
Vertex[ 3 ].su = 0.0f ;
Vertex[ 3 ].sv = 0.0f ;
// 2ポリゴン分のインデックスデータをセット
Index[ 0 ] = 0 ;
Index[ 1 ] = 1 ;
Index[ 2 ] = 2 ;
Index[ 3 ] = 3 ;
Index[ 4 ] = 2 ;
Index[ 5 ] = 1 ;
// カメラの座標
VECTOR CameraPos ;
CameraPos.x = 0.0f ;
CameraPos.y = 60.0f ;
CameraPos.z = -800.0f ;
// ブレンドを有効に。
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ;
// Zバッファを有効にする
SetUseZBuffer3D( TRUE ) ;
// Zバッファへの書き込みを有効にする
SetWriteZBuffer3D( TRUE ) ;
while( ProcessMessage() == 0 ) {
ClearDrawScreen() ;
// 方向キーでカメラの座標を移動
if( CheckHitKey( KEY_INPUT_UP ) == 1 )
{
CameraPos.y += 1.0f ;
}
if( CheckHitKey( KEY_INPUT_DOWN ) == 1 )
{
CameraPos.y -= 1.0f ;
}
if( CheckHitKey( KEY_INPUT_LEFT ) == 1 )
{
CameraPos.x -= 20.0f ;
}
if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 )
{
CameraPos.x += 20.0f ;
}
// カメラの設定
SetCameraNearFar( 100.0f, 15000.0f ) ;
SetCameraPositionAndTarget_UpVecY( CameraPos, VGet( 0.0f, 0.0f, 0.0f ) );
// 物体
DrawSphere3D( VGet( 0.0f, 0.0f, 0.0f ), 100.0f, 10, GetColor( 255,255,255 ), GetColor( 255, 255, 255 ), TRUE ) ;
// 仮定水面(部分)を描画
DrawPolygonIndexed3D( Vertex, 4, Index, 2, DX_NONE_GRAPH, TRUE );
// カメラのビューマトリクスを得る。
MATRIX viewMtx = GetCameraViewMatrix();
// カメラの方向のZが100fとちょっと先の位置を得る。つまりカメラに映る水面の端
MATRIX dirMtx = MInverse(viewMtx);
VECTOR dirVec = VTransformSR( VGet(0.0f,0.0f,10000.0f), dirMtx );
dirVec.y = 0;//y成分を消す
dirVec = VNorm(dirVec);//単位ベクトル化
dirVec = VScale(dirVec, 100.01f );//距離分拡大。少し奥。
// カメラの近くの仮想水面の座標
VECTOR TargetSeaPos = CameraPos;
TargetSeaPos.y = 0; //水面は高さ0
TargetSeaPos = VAdd(TargetSeaPos,dirVec); //ベクトルの加算
// ワールドから画面座標に変換。カメラの位置の水面。
VECTOR ScreenSeaPos = CameraPos;
ScreenSeaPos.y = 0; //水面は高さ0
VECTOR screen_pos = ConvWorldPosToScreenPos( ScreenSeaPos ) ;
// 値の表示
DrawFormatString( 0, 16, GetColor( 255,0,0 ), "camera (x,y,z)=(%7.1f,%7.1f,%7.1f)", CameraPos.x, CameraPos.y ,CameraPos.z ) ;
DrawFormatString( 0, 32, GetColor( 255,0,0 ), "target sea (x,y,z)=(%7.1f,%7.1f,%7.1f)", TargetSeaPos.x, TargetSeaPos.y ,TargetSeaPos.z ) ;
DrawFormatString( 0, 48, GetColor( 255,0,0 ), "screen_pos (x,y)=(%7.1f,%7.1f)", screen_pos.x, screen_pos.y ) ;
// カメラの近くの仮想水面の座標が画面内なら、海面下の描画を行う。
BOOL bDrawUnderSea = false;
if( CheckCameraViewClip( TargetSeaPos ) == FALSE ) {
// 画面内
DrawString( 0, 0, "Screen in", GetColor( 255,255,255 ) ) ;
bDrawUnderSea = true;
} else {
// 画面外
DrawString( 0, 0, "Screen out", GetColor( 255,255,255 ) ) ;
}
// 画面外でも座標がマイナスなら海面下の描画をを行う。
if( screen_pos.y < 0 ) {
bDrawUnderSea = true;
}
// screen_pos.y を元に海面下の描画
if( bDrawUnderSea ) {
// 海面下を半透明のBOXで塗りつぶす。
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 64 ) ;
DrawBox( 0, screen_pos.y, DEFAULT_SCREEN_SIZE_X, DEFAULT_SCREEN_SIZE_Y, GetColor( 0,0,255 ), TRUE ) ;
// DrawBox( 0, screen_pos.y, DEFAULT_SCREEN_SIZE_X, DEFAULT_SCREEN_SIZE_Y, GetColor( 255,255,0 ), TRUE ) ;
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ;
}
// 取得したスクリーン座標に四角形を描画
// DrawBox( ScreenPos.x - 2, ScreenPos.y - 2, ScreenPos.x + 2, ScreenPos.y + 2, GetColor( 255,0,0 ), TRUE ) ;
ScreenFlip() ;
}
DxLib_End() ;
return 0 ;
}
#include "DxLib.h"
#include <stdio.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
VERTEX3D Vertex[ 4 ] ;
WORD Index[ 6 ] ;
ChangeWindowMode(TRUE);
if( DxLib_Init() < 0 ) { return -1; }
SetDrawScreen( DX_SCREEN_BACK ) ;
// 4頂点分のデータをセット
Vertex[ 0 ].pos = VGet(-2000.0f, 0.0f,-2000.0f ) ;
Vertex[ 0 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 0 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 0 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 0 ].u = 0.0f ;
Vertex[ 0 ].v = 0.0f ;
Vertex[ 0 ].su = 0.0f ;
Vertex[ 0 ].sv = 0.0f ;
Vertex[ 1 ].pos = VGet( 2000.0f, 0.0f,-2000.0f) ;
Vertex[ 1 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 1 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 1 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 1 ].u = 0.0f ;
Vertex[ 1 ].v = 0.0f ;
Vertex[ 1 ].su = 0.0f ;
Vertex[ 1 ].sv = 0.0f ;
Vertex[ 2 ].pos = VGet( -2000.0f, 0.0f,2000.0f ) ;
Vertex[ 2 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 2 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 2 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 2 ].u = 0.0f ;
Vertex[ 2 ].v = 0.0f ;
Vertex[ 2 ].su = 0.0f ;
Vertex[ 2 ].sv = 0.0f ;
Vertex[ 3 ].pos = VGet( 2000.0f, 0.0f, 2000.0f ) ;
Vertex[ 3 ].norm = VGet( 0.0f, 0.0f, -1.0f ) ;
Vertex[ 3 ].dif = GetColorU8( 0,128,255,128 ) ;
Vertex[ 3 ].spc = GetColorU8( 0, 0, 0, 0 ) ;
Vertex[ 3 ].u = 0.0f ;
Vertex[ 3 ].v = 0.0f ;
Vertex[ 3 ].su = 0.0f ;
Vertex[ 3 ].sv = 0.0f ;
// 2ポリゴン分のインデックスデータをセット
Index[ 0 ] = 0 ;
Index[ 1 ] = 1 ;
Index[ 2 ] = 2 ;
Index[ 3 ] = 3 ;
Index[ 4 ] = 2 ;
Index[ 5 ] = 1 ;
// カメラの座標
VECTOR CameraPos ;
CameraPos.x = 0.0f ;
CameraPos.y = 60.0f ;
CameraPos.z = -800.0f ;
// ブレンドを有効に。
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ;
// Zバッファを有効にする
SetUseZBuffer3D( TRUE ) ;
// Zバッファへの書き込みを有効にする
SetWriteZBuffer3D( TRUE ) ;
while( ProcessMessage() == 0 ) {
ClearDrawScreen() ;
// 方向キーでカメラの座標を移動
if( CheckHitKey( KEY_INPUT_UP ) == 1 )
{
CameraPos.y += 1.0f ;
}
if( CheckHitKey( KEY_INPUT_DOWN ) == 1 )
{
CameraPos.y -= 1.0f ;
}
if( CheckHitKey( KEY_INPUT_LEFT ) == 1 )
{
CameraPos.x -= 20.0f ;
}
if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 )
{
CameraPos.x += 20.0f ;
}
// カメラの設定
SetCameraNearFar( 100.0f, 15000.0f ) ;
SetCameraPositionAndTarget_UpVecY( CameraPos, VGet( 0.0f, 0.0f, 0.0f ) );
// 物体
DrawSphere3D( VGet( 0.0f, 0.0f, 0.0f ), 100.0f, 10, GetColor( 255,255,255 ), GetColor( 255, 255, 255 ), TRUE ) ;
// 仮定水面(部分)を描画
DrawPolygonIndexed3D( Vertex, 4, Index, 2, DX_NONE_GRAPH, TRUE );
// カメラのビューマトリクスを得る。
MATRIX viewMtx = GetCameraViewMatrix();
// カメラの方向のZが100fとちょっと先の位置を得る。つまりカメラに映る水面の端
MATRIX dirMtx = MInverse(viewMtx);
VECTOR dirVec = VTransformSR( VGet(0.0f,0.0f,10000.0f), dirMtx );
dirVec.y = 0;//y成分を消す
dirVec = VNorm(dirVec);//単位ベクトル化
dirVec = VScale(dirVec, 100.01f );//距離分拡大。少し奥。
// カメラの近くの仮想水面の座標
VECTOR TargetSeaPos = CameraPos;
TargetSeaPos.y = 0; //水面は高さ0
TargetSeaPos = VAdd(TargetSeaPos,dirVec); //ベクトルの加算
// ワールドから画面座標に変換。こちらはマジックナンバーで調整した。
VECTOR ScreenSeaPos = CameraPos;
ScreenSeaPos.y = 0; //水面は高さ0
dirVec = VNorm(dirVec);//単位ベクトル化
dirVec = VScale(dirVec, 96.45f );//距離分拡大
ScreenSeaPos = VAdd(ScreenSeaPos,dirVec); //ベクトルの加算
VECTOR screen_pos = ConvWorldPosToScreenPos( ScreenSeaPos ) ;
// 値の表示
DrawFormatString( 0, 16, GetColor( 255,0,0 ), "camera (x,y,z)=(%7.1f,%7.1f,%7.1f)", CameraPos.x, CameraPos.y ,CameraPos.z ) ;
DrawFormatString( 0, 32, GetColor( 255,0,0 ), "target sea (x,y,z)=(%7.1f,%7.1f,%7.1f)", TargetSeaPos.x, TargetSeaPos.y ,TargetSeaPos.z ) ;
DrawFormatString( 0, 48, GetColor( 255,0,0 ), "screen_pos (x,y)=(%7.1f,%7.1f)", screen_pos.x, screen_pos.y ) ;
// カメラの近くの仮想水面の座標が画面内なら、海面下の描画を行う。
BOOL bDrawUnderSea = false;
if( CheckCameraViewClip( TargetSeaPos ) == FALSE ) {
// 画面内
DrawString( 0, 0, "Screen in", GetColor( 255,255,255 ) ) ;
bDrawUnderSea = true;
} else {
// 画面外
DrawString( 0, 0, "Screen out", GetColor( 255,255,255 ) ) ;
}
// 画面外でも座標がマイナスなら海面下の描画をを行う。
if( screen_pos.y < 0 ) {
bDrawUnderSea = true;
}
// screen_pos.y を元に海面下の描画
if( bDrawUnderSea ) {
// 海面下を半透明のBOXで塗りつぶす。分かりやすいように黄色
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 64 ) ;
DrawBox( 0, screen_pos.y, DEFAULT_SCREEN_SIZE_X, DEFAULT_SCREEN_SIZE_Y, GetColor( 0,0,255 ), TRUE ) ;
// DrawBox( 0, screen_pos.y, DEFAULT_SCREEN_SIZE_X, DEFAULT_SCREEN_SIZE_Y, GetColor( 255,255,0 ), TRUE ) ;
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ;
}
// 取得したスクリーン座標に四角形を描画
// DrawBox( ScreenPos.x - 2, ScreenPos.y - 2, ScreenPos.x + 2, ScreenPos.y + 2, GetColor( 255,0,0 ), TRUE ) ;
ScreenFlip() ;
}
DxLib_End() ;
return 0 ;
}
とりあえず、やってみたのは余り褒められた方法ではありません。あかり さんが書きました:ソースやいろいろな案を出して頂き、ありがとうございます!
出して頂いた案を作れるかわかりませんが、作ってみようと思います。