📄 game_skybox.cpp
字号:
#include "..\Include\Game_SkyBox.h"
Game_SkyBox::Game_SkyBox(FLOAT width,char * strSkyName){
m_cStrSkyName=strSkyName;
m_vPos=D3DXVECTOR3(0,0,0);
m_fWidth=width;
m_pVB=NULL;
m_uSpeed=0.02f;
m_vSpeed=0.03f;
m_nSegment=16;
m_nSkyTile=10;
m_nAngle=D3DX_PI/4;
}
Game_SkyBox::~Game_SkyBox(){
SAFE_RELEASE(m_pVB);
for(UINT i=0; i<7; i++){
SAFE_RELEASE(m_pTexture[i]);
}
SAFE_RELEASE(m_pVBSky);
SAFE_RELEASE(m_pIBSky);
}
WCHAR* Game_SkyBox::CreateWideStringFromCharString(const char *c_str){
if (!c_str)
return NULL;
size_t len=strlen(c_str)+1;
WCHAR *wideString=new WCHAR[len];
if( MultiByteToWideChar( CP_ACP, 0, c_str, -1, wideString, (int)len ) == 0 )
return NULL;
return wideString;
}
void Game_SkyBox::InitObject(char * strName){
CreateSkyBox();
LoadSkyBox(strName);
InitialiseVertexBuffer();
}
HRESULT Game_SkyBox::CreateSkyBox(char *strTextureA6[]){
if(strTextureA6){
for(int i=0;i<7;i++){
D3DXCreateTextureFromFile(g_sGlobal.g_pDevice,CreateWideStringFromCharString(strTextureA6[i]),&m_pTexture[i]);
}
}
else{
for(int i=0;i<7;i++)
m_pTexture[i]=NULL;
}
return S_OK;
}
HRESULT Game_SkyBox::LoadSkyBox(char * strName){
//_ASSERT(!m_pTexture[0]);
char strFileName[256];
char *strKeyName[]={
"East",
"South",
"West",
"North",
"Earth",
"Sky",
"Cloud"
};
if(!m_pTexture[0]){
for(int i=0;i<7;i++){
if (FAILED(GetPrivateProfileStringA(m_cStrSkyName,strKeyName[i],"\0",strFileName,sizeof(strFileName),strName))){
MessageBox(NULL,L"A",L"",0);
return E_FAIL;
}
if (FAILED(D3DXCreateTextureFromFileA(g_sGlobal.g_pDevice,strFileName, &m_pTexture[i]))){
return E_FAIL;
}
}
}
return S_OK;
}
HRESULT Game_SkyBox::InitialiseVertexBuffer(){
VERTEX_BOX VB[]={
{ 0.5f,-0.5f, 0.5f,-1.0f,0,0, 0.0f,1.0f,}, //East
{ 0.5f, 0.5f, 0.5f,-1.0f,0,0, 0.0f,0.0f,},
{ 0.5f,-0.5f, -0.5f,-1.0f,0,0, 1.0f,1.0f,},
{ 0.5f, 0.5f, -0.5f,-1.0f,0,0, 1.0f,0.0f,},
{ 0.5f,-0.5f, -0.5f,0,0,1.0f, 0.0f,1.0f,}, //North
{ 0.5f, 0.5f, -0.5f,0,0,1.0f, 0.0f,0.0f,},
{ -0.5f,-0.5f, -0.5f,0,0,1.0f, 1.0f,1.0f,},
{ -0.5f, 0.5f, -0.5f,0,0,1.0f, 1.0f,0.0f,},
{ -0.5f,-0.5f, -0.5f,1.0f,0,0, 0.0f,1.0f,}, //West
{ -0.5f, 0.5f, -0.5f,1.0f,0,0, 0.0f,0.0f,},
{ -0.5f,-0.5f, 0.5f,1.0f,0,0, 1.0f,1.0f,},
{ -0.5f, 0.5f, 0.5f,1.0f,0,0, 1.0f,0.0f,},
{-0.5f,-0.5f, 0.5f,0,0,-1.0f,0.0f,1.0f,}, //South
{-0.5f, 0.5f, 0.5f,0,0,-1.0f,0.0f,0.0f,},
{ 0.5f,-0.5f, 0.5f,0,0,-1.0f,1.0f,1.0f,},
{ 0.5f, 0.5f, 0.5f,0,0,-1.0f,1.0f,0.0f,},
{ -0.5f,-0.5f, 0.5f,0,1.0f,0, 0.0f,0.0f,}, //Earth
{ 0.5f,-0.5f, 0.5f,0,1.0f,0, 0.0f,1.0f,},
{ -0.5f,-0.5f, -0.5f,0,1.0f,0, 1.0f,0.0f,},
{ 0.5f,-0.5f, -0.5f,0,1.0f,0, 1.0f,1.0f,},
{ 0.5f, 0.5f, 0.5f,0,-1.0f,0, 0.0f,0.0f,}, //Sky
{-0.5f, 0.5f, 0.5f,0,-1.0f,0, 1.0f,0.0f,},
{ 0.5f, 0.5f, -0.5f,0,-1.0f,0, 0.0f,1.0f,},
{-0.5f, 0.5f, -0.5f,0,-1.0f,0, 1.0f,1.0f,},
};
//---------------------------------------------------------------------------------------------
//创建SkyDome,方形圆顶
//---------------------------------------------------------------------------------------------
int nVertex=(m_nSegment+1)*(m_nSegment+1);
int nIndex=m_nSegment*m_nSegment*6;
float R=0.5f/sinf(m_nAngle/2); //半径满足弧形宽度为1,和天空盒相等大小
VERTEX_BOX *VBSKY=new VERTEX_BOX[nVertex]; //顶点缓冲区
DWORD *IBSKY=new DWORD[nIndex]; //索引数据
float angleCol,angleRow;
float anglePerSeg=m_nAngle/m_nSegment;
float angleStart=D3DX_PI/2-m_nAngle/2;
float dYDown=R*sinf(angleStart); //云层向下的偏移量,边缘位于地平线上
for (int i=0;i<nVertex;i++){ //顶点数据
angleCol=angleStart+(i%(m_nSegment+1))*anglePerSeg;
angleRow=angleStart+(i/(m_nSegment+1))*anglePerSeg;
VBSKY[i].nx=-cosf(angleCol); //法线指向圆心
VBSKY[i].ny=-sinf(angleCol)*sinf(angleRow);
VBSKY[i].nz=-sinf(angleCol)*cosf(angleRow);
VBSKY[i].x=-R*VBSKY[i].nx;
VBSKY[i].y=-R*VBSKY[i].ny-dYDown; //偏移,边缘和地平线(y=0)平齐
VBSKY[i].z=-R*VBSKY[i].nz;
VBSKY[i].tu=m_nSkyTile*angleCol/m_nAngle;
VBSKY[i].tv=m_nSkyTile*angleRow/m_nAngle;
if(VBSKY[i].y<0.0f)
VBSKY[i].y=0.0f;
}
DWORD *lpIB=IBSKY; //索引数据
long iMax=(m_nSegment+1)*m_nSegment; //最后一个对应到矩形的左下角的顶点的索引号
for (int i=0;i<iMax;i++ ){
if(i%(m_nSegment+1)!=m_nSegment){ //每行的最后一个点不对应一个矩形
*(lpIB++)=i;
*(lpIB++)=i+m_nSegment+2; //每行顶点数量m_nSegment+1;
*(lpIB++)=i+m_nSegment+1;
*(lpIB++)=i;
*(lpIB++)=i+1;
*(lpIB++)=i+m_nSegment+2;
}
}
g_sGlobal.g_pDevice->CreateVertexBuffer(sizeof(VB),0,D3DFVF_SKYBOX,
D3DPOOL_DEFAULT, &m_pVB,NULL);
void* pVertices;
m_pVB->Lock(0,0,&pVertices,D3DLOCK_DISCARD);
memcpy(pVertices,(void*)VB,sizeof(VB));
m_pVB->Unlock();
//云的顶点数据
g_sGlobal.g_pDevice->CreateVertexBuffer(sizeof(VERTEX_BOX)*nVertex,0, D3DFVF_SKYBOX,
D3DPOOL_DEFAULT, &m_pVBSky,NULL);
m_pVBSky->Lock(0,0,&pVertices,D3DLOCK_DISCARD);
memcpy(pVertices,(void*)VBSKY,sizeof(VERTEX_BOX)*nVertex);
m_pVBSky->Unlock();
//天空的索引数据
g_sGlobal.g_pDevice->CreateIndexBuffer(sizeof(DWORD)*nIndex,0,D3DFMT_INDEX32,
D3DPOOL_DEFAULT, &m_pIBSky,NULL);
m_pIBSky->Lock(0,0,&pVertices,D3DLOCK_DISCARD);
memcpy(pVertices,(void*)IBSKY,sizeof(DWORD)*nIndex);
m_pIBSky->Unlock();
delete []IBSKY;
delete []VBSKY;
return S_OK;
}
VOID Game_SkyBox::Render(){
SetPosition(*(g_sGlobal.g_pGameApp->m_pGame_Camera->GetCameraPos()));
VERTEX_BOX *pV;
static float timeLastFrame=timeGetTime()/1000.0f;
float timeNow=timeGetTime()/1000.0f;
float timeFrameTime=timeNow-timeLastFrame;
timeLastFrame=timeNow;
m_pVBSky->Lock(0,0,(void**)&pV,0);
//Refresh UV coordinate
if(pV[m_nSegment/2].tu<2.0f){
for(UINT i=0;i<(m_nSegment+1)*(m_nSegment+1) ;i++) pV[i].tu+=m_uSpeed*timeFrameTime;
}
else{
float tu=pV[m_nSegment/2].tu;
for(int i=(m_nSegment+1)*(m_nSegment+1)-1;i>=0;i--) pV[i].tu-=tu;
}
if(pV[m_nSegment/2].tv<2.0f){
for(UINT i=0;i<(m_nSegment+1)*(m_nSegment+1) ;i++) pV[i].tv+=m_vSpeed*timeFrameTime;
}
else{
float tv=pV[m_nSegment/2].tv;
for(int i=(m_nSegment+1)*(m_nSegment+1)-1;i>=0;i--) pV[i].tv-=tv;
}
m_pVBSky->Unlock();
g_sGlobal.g_pDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_BLENDTEXTUREALPHA); //使用透明贴图
g_sGlobal.g_pDevice->SetRenderState( D3DRS_ZWRITEENABLE,FALSE); //关闭深度写入
g_sGlobal.g_pDevice->SetRenderState(D3DRS_ZENABLE,TRUE);
g_sGlobal.g_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
g_sGlobal.g_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_sGlobal.g_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_sGlobal.g_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_MIRROR);
g_sGlobal.g_pDevice->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_MIRROR);
//g_sGlobal.g_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
FrameMove();
g_sGlobal.g_pDevice->SetFVF(D3DFVF_SKYBOX);
g_sGlobal.g_pDevice->SetStreamSource(0,m_pVB,0,sizeof(VERTEX_BOX));
g_sGlobal.g_pDevice->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_DISABLE);
for(int i=0;i<6;i++){
g_sGlobal.g_pDevice->SetTexture(0,m_pTexture[i]);
g_sGlobal.g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,i*4,2);
}
g_sGlobal.g_pDevice->SetTexture(0,m_pTexture[6]); //云的纹理
g_sGlobal.g_pDevice->SetStreamSource(0,m_pVBSky,0,sizeof(VERTEX_BOX));
g_sGlobal.g_pDevice->SetIndices(m_pIBSky);
g_sGlobal.g_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,
(m_nSegment+1)*(m_nSegment+1),0,m_nSegment*m_nSegment*2);
g_sGlobal.g_pDevice->SetRenderState( D3DRS_CLIPPLANEENABLE ,TRUE);
g_sGlobal.g_pDevice->SetRenderState( D3DRS_ZWRITEENABLE,TRUE);
}
VOID Game_SkyBox::FrameMove(){
D3DXMATRIX matWorld;
matWorld._11=m_fWidth; matWorld._12=0; matWorld._13=0; matWorld._14=0;
matWorld._21=0; matWorld._22=m_fWidth; matWorld._23=0; matWorld._24=0;
matWorld._31=0; matWorld._32=0; matWorld._33=m_fWidth; matWorld._34=0;
matWorld._41=m_vPos.x; matWorld._42=m_vPos.y; matWorld._43=m_vPos.z; matWorld._44=1;
g_sGlobal.g_pDevice->SetTransform(D3DTS_WORLD,&matWorld);
}
VOID Game_SkyBox::SetPosition(D3DXVECTOR3 pos){
m_vPos=pos;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -