第11讲 天空.docx
- 文档编号:5256941
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:18
- 大小:944.95KB
第11讲 天空.docx
《第11讲 天空.docx》由会员分享,可在线阅读,更多相关《第11讲 天空.docx(18页珍藏版)》请在冰豆网上搜索。
第11讲天空
天空构造
在上一章,我们采用一个平面网格表示地面,这样的场景不够真实。
本章我们学习构造出一个更加真实的场景,给它加上天空和地面,地面有一定的坡度,使之可以在高地起伏的3D游戏场景中漫步。
1、天空的构造方法与原理
构造天空的方法:
(1)用一种接近天空的淡蓝色清除背景颜色,然后在上面用白色绘制出白云,这种方法简单,但不够逼真。
(2)绘制一个长方体盒子,然后将天空纹理贴图到各个多边形上,此方法只要纹理贴图使用的足够好,就可以达到很好的视觉效果。
但长方体到底其边框边时,会发现其各个多边形的衔接缝。
(3)绘制一个半球体,使之笼罩在地面上,贴上天空纹理图,给人一个真实的天似穹庐视觉效果,但半球体的顶部点附近纹理贴图会有一定的皱褶。
这里我们以长方体盒子贴图来构造天空。
构造天空的原理:
前后左右4幅贴图
顶部纹理图
5个多边形纹理贴图相连
使用的纹理贴图合适,可以使之在视觉上看不到衔接缝隙,使视觉效果更加逼真。
天上
地下
封装CCubeSky类
#pragmaonce
#include
#include
#include"Camera.h"
structCUSTOMVERTEX2
{
FLOATx,y,z;
FLOATtu,tv;
};
#defineD3DFVF_CUSTOMVETEX2(D3DFVF_XYZ|D3DFVF_TEX1)
classCCubeSky
{
private:
LPDIRECT3DDEVICE9m_pd3dDevice;
LPDIRECT3DVERTEXBUFFER9m_pVB;
LPDIRECT3DINDEXBUFFER9m_pIB;
LPDIRECT3DTEXTURE9m_pTexScene[6];
floatlen;
public:
CCubeSky(LPDIRECT3DDEVICE9pd3dDevice);
~CCubeSky(void);
HRESULTVBInit();
voidRender();
boolSetTexture(constWCHAR*FileTexture,intflag);
};
CCubeSky.cpp
#include"CubeSky.h"
CCubeSky:
:
CCubeSky(LPDIRECT3DDEVICE9pd3dDevice)
{
m_pd3dDevice=pd3dDevice;
this->m_pIB=NULL;
this->m_pVB=NULL;
len=100.0f;
}
CCubeSky:
:
~CCubeSky(void)
{}
HRESULTCCubeSky:
:
VBInit()
{
//创建天空盒需要的8个顶点
CUSTOMVERTEX2gCubeVerts[]=
{
//z方向点和纹理坐标
{-len,0.0f,-len,1.0f,1.0f},//0
{-len,len,-len,1.0f,0.0f},//1
{len,0.0f,-len,0.0f,1.0f},//2
{len,len,-len,0.0f,0.0f},//3
{len,0.0f,len,1.0f,1.0f},//4
{len,len,len,1.0f,0.0f},//5
{-len,0.0f,len,0.0f,1.0f},//6
{-len,len,len,0.0f,0.0f},//7
//x方向点和纹理坐标
{len,0.0f,-len,1.0f,1.0f},//2-8
{len,len,-len,1.0f,0.0f},//3-9
{len,0.0f,len,0.0f,1.0f},//4-10
{len,len,len,0.0f,0.0f},//5-11
{-len,0.0f,-len,0.0f,1.0f},//0-12
{-len,len,-len,0.0f,0.0f},//1-13
{-len,0.0f,len,1.0f,1.0f},//6-14
{-len,len,len,1.0f,0.0f},//7-15
//y方向点和纹理坐标
{-len,0.0f,-len,1.0f,0.0f},//0-16
{len,0.0f,-len,0.0f,0.0f},//2-17
{-len,0.0f,len,1.0f,1.0f},//6-18
{len,0.0f,len,0.0f,1.0f},//4-19
{-len,len,-len,1.0f,1.0f},//1-20
{len,len,-len,0.0f,1.0f},//3-21
{len,len,len,0.0f,0.0f},//5-22
{-len,len,len,1.0f,0.0f},//7-23
};
//创建天空盒需要的顶点的索引
WORDgCubeIndices[]=
{2,3,1,//z方向
2,1,0,//
6,7,5,//
6,5,4,//
10,11,9,//x方向
10,9,8,//
12,13,15,//
12,15,14,//
16,18,19,//y方向
16,19,17,//
20,21,22,//
20,22,23
};
//创建顶点缓冲区
if(FAILED(m_pd3dDevice->CreateVertexBuffer(sizeof(gCubeVerts),
0,
D3DFVF_CUSTOMVETEX2,
D3DPOOL_DEFAULT,
&m_pVB,
NULL
)))
{
returnE_FAIL;
}
VOID*pVertices;
//锁定顶点缓冲区
if(FAILED(m_pVB->Lock(0,sizeof(gCubeVerts),
(void**)&pVertices,0)))
{
returnE_FAIL;
}
//把顶点数组的数据拷贝到顶点缓冲区中
memcpy(pVertices,gCubeVerts,sizeof(gCubeVerts));
m_pVB->Unlock();//解锁顶点缓冲区
//创建索引缓冲区
if(FAILED(m_pd3dDevice->CreateIndexBuffer(sizeof(gCubeIndices),
0,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&m_pIB,
NULL
)))
{
returnE_FAIL;
}
VOID*pIndices;
//锁定索引缓冲区
if(FAILED(m_pIB->Lock(0,sizeof(gCubeIndices),
(void**)&pIndices,0)))
returnE_FAIL;
//把索引数组的值拷贝索引缓冲区中
memcpy(pIndices,gCubeIndices,sizeof(gCubeIndices));
m_pIB->Unlock();//解锁索引缓冲区
returnS_OK;
}
boolCCubeSky:
:
SetTexture(constWCHAR*FileTexture,intflag)
{
if(FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,FileTexture,
&m_pTexScene[flag])))
{
returnfalse;
}
returntrue;
}
voidCCubeSky:
:
Render()
{
D3DXMATRIXmatrix,smatrix,tmatrix,rmatrix;
//m_Camera.ProcInput();
//设置数据源
m_pd3dDevice->SetStreamSource(0,m_pVB,0,sizeof(CUSTOMVERTEX2));
m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVETEX2);
m_pd3dDevice->SetIndices(m_pIB);
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);//背面消隐
m_pd3dDevice->SetRenderState(D3DRS_LIGHTING,false);//光照关闭
m_pd3dDevice->SetRenderState(D3DRS_ZENABLE,false);//关闭Zbuffer
//SetProjection();//投影
//画天空盒设置纹理
m_pd3dDevice->SetTexture(0,m_pTexScene[0]);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,4,0,2);
m_pd3dDevice->SetTexture(0,m_pTexScene[1]);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,4,4,6,2);
m_pd3dDevice->SetTexture(0,m_pTexScene[2]);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,8,4,12,2);
m_pd3dDevice->SetTexture(0,m_pTexScene[3]);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,12,4,18,2);
m_pd3dDevice->SetTexture(0,m_pTexScene[4]);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,16,4,24,2);
m_pd3dDevice->SetTexture(0,m_pTexScene[5]);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,20,4,30,2);
}
球形天空构造
球面天空是通过在半球面上进行纹理贴图实现的,因此,需要分割一个半球面获得各个顶点,然后定义顶点的灵活顶点格式,设置和计算每个顶点的xyz坐标和纹理uv坐标,最后将顶点数据送入渲染管道流水线进行处理,如图所示
假设半球面上的任意点p=(px,py,pz)半球体的半径为r,α和β为相应的经度角和纬度角,如图下所示。
从图中可以看出,经度角α的取值范围在区间[0,2π]内,而纬度角β的取值范围在区间[0,π/2]内。
所以顶点p的坐标计算公式如下:
接下来考虑纹理坐标的计算。
若将2π除以经度角就可以得到维度线的条数,而若将π/2除以维度角就可以得到经度线的条数。
因此,根据p点的经度角α和维度角β就可以计算出p点的纹理坐标。
可以按照下面代码计算出p点的坐标和纹理坐标。
m_fSkyboxRadius=fRadius;//半球体的半径
m_nNumLatitudes=360/nAlpha;//维度线的条数
m_nNumLongitudes=90/nBeta;//经度线的条数
m_nVertsPerLongi=m_nNumLatitudes+1;//每条经度线上的顶点数
m_nVertsPerLati=m_nNumLongitudes+1;//每条维度线上的顶点数
m_nNumVertices=m_nVertsPerLati*m_nVertsPerLongi;
//灵活顶点格式
structSkyBoxVERTEX
{
FLOAT_x,_y,_z;
FLOAT_u,_v;
SkyBoxVERTEX(FLOATx,FLOATy,FLOATz,FLOATu,FLOATv)
:
_x(x),_y(y),_z(z),_u(u),_v(v){}
staticconstDWORDFVF=D3DFVF_XYZ|D3DFVF_TEX1;
};
//计算地形的灵活顶点
if(FAILED(m_pd3dDevice->CreateVertexBuffer(m_nNumVertices*sizeof(SKYBOXVERTEX),
D3DUSAGE_WRITEONLY,SKYBOXVERTEX:
:
FVF,D3DPOOL_MANAGED,&m_pVertexBuf,0)))
returnFALSE;
SKYBOXVERTEX*pVertices=NULL;
m_pVertexBuf->Lock(0,0,(void**)&pVertices,0);
intnIndex=0;
FLOATfAlpha=2.0f*D3DX_PI*nAlpha/360.0f;//经度角转换为弧度表示
FLOATfBeta=2.0f*D3DX_PI*nBeta/360.0f;//维度角转换为弧度表示
for(introw=0;row { for(intcol=0;col { //计算顶点的坐标 pVertices[nIndex]._x=fRadius*cosf(row*fBeta)*cosf(col*fAlpha); pVertices[nIndex]._y=fRadius*sinf(row*fBeta); pVertices[nIndex]._z=fRadius*cosf(row*fBeta)*sinf(col*fAlpha); //计算顶点的纹理坐标 pVertices[nIndex]._u=col*fAlpha/(2.0f*D3DX_PI); pVertices[nIndex]._v=row*fBeta/(D3DX_PI/2.0f); nIndex++; } } m_pVertexBuf->Unlock(); 对于半球面上的任意点A,并以该点为起始顶点的两个相邻三角形的顶点B、C、D点,它们的位置关系将如图所示。 pIndices[nIndex+0]=row*m_nVertsPerLongi+col; pIndices[nIndex+1]=(row+1)*m_nVertsPerLongi+col; pIndices[nIndex+2]=(row+1)*m_nVertsPerLongi+col+1; pIndices[nIndex+3]=row*m_nVertsPerLongi+col; pIndices[nIndex+4]=(row+1)*m_nVertsPerLongi+col+1; pIndices[nIndex+5]=row*m_nVertsPerLongi+col+1; nIndex+=6; 球形天空类定义: CSkyBox.h classCSkybox { private: LPDIRECT3DDEVICE9m_pd3dDevice; LPDIRECT3DTEXTURE9m_pTexture; LPDIRECT3DINDEXBUFFER9m_pIndexBuf; LPDIRECT3DVERTEXBUFFER9m_pVertexBuf; INTm_nNumLatitudes;//维度的数目 INTm_nNumLongitudes;//经度的数目 INTm_nVertsPerLati;//每条维度上包含的顶点数 INTm_nVertsPerLongi;//每条经度上包含的顶点数 INTm_nNumVertices;//顶点总数 FLOATm_fSkyboxRadius;//球形天空的半径 structSKYBOXVERTEX//球形天空的顶点结构 { FLOAT_x,_y,_z; FLOAT_u,_v; SKYBOXVERTEX(FLOATx,FLOATy,FLOATz,FLOATu,FLOATv) : _x(x),_y(y),_z(z),_u(u),_v(v){} staticconstDWORDFVF=D3DFVF_XYZ|D3DFVF_TEX1; }; public: CSkybox(IDirect3DDevice9*pd3dDevice); virtual~CSkybox(void); public: BOOLLoadSkybox(wchar_t*pTextureFile);//加载纹理 BOOLInitSkybox(INTnAlpha,INTnBeta,FLOATnRadius);//初始化球形天空 BOOLDrawSkybox(D3DXMATRIX*pMatWorld,BOOLbDrawFrame=FALSE);//绘制天空 }; 球形天空类的实现SkyBox.cpp #include"SkyBox.h" CSkyBox: : CSkyBox(IDirect3DDevice9*pd3dDevice) { m_pd3dDevice=pd3dDevice; m_pTexture=NULL; m_pIndexBuf=NULL; m_pVertexBuf=NULL; m_nNumVertices=0; m_nNumLatitudes=0; m_nNumLongitudes=0; m_nVertsPerLongi=0; m_nVertsPerLati=0; m_fSkyBoxRadius=0; } CSkyBox: : ~CSkyBox(void) { if(m_pIndexBuf! =NULL) m_pIndexBuf->Release(); if(m_pTexture! =NULL) m_pTexture->Release(); if(m_pVertexBuf! =NULL) m_pVertexBuf->Release(); } BOOLCSkyBox: : LoadSkyBox(wchar_t*pTextureFile) { //加载天空纹理 if(FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,pTextureFile,&m_pTexture))) returnFALSE; returnTRUE; } BOOLCSkyBox: : InitSkyBox(INTnAlpha,INTnBeta,FLOATfRadius) { m_fSkyBoxRadius=fRadius;//半球体的半径 m_nNumLatitudes=360/nAlpha;//维度线的条数 m_nNumLongitudes=90/nBeta;//经度线的条数 m_nVertsPerLongi=m_nNumLatitudes+1;//每条经度线上的顶点数 m_nVertsPerLati=m_nNumLongitudes+1;//每条维度线上的顶点数 m_nNumVertices=m_nVertsPerLati*m_nVertsPerLongi; //计算天空的灵活顶点 if(FAILED(m_pd3dDevice->CreateVertexBuffer(m_nNumVertices*sizeof(SkyBoxVERTEX), D3DUSAGE_WRITEONLY,SkyBoxVERTEX: : FVF,D3DPOOL_MANAGED,&m_pVertexBuf,0))) returnFALSE; SkyBoxVERTEX*pVertices=NULL; m_pVertexBuf->Lock(0,0,(void**)&pVertices,0); intnIndex=0; FLOATfAlpha=2.0f*D3DX_PI*nAlpha/360.0f;//经度角转换为弧度表示 FLOATfBeta=2.0f*D3DX_PI*nBeta/360.0f;//维度角转换为弧度表示 for(introw=0;row { for(intcol=0;col { //计算顶点的坐标 pVertices[nIndex]._x=fRadius*cosf(row*fBeta)*cosf(col*fAlpha); pVertices[nIndex]._y=fRadius*sinf(row*fBeta); pVertices[nIndex]._z=fRadius*cosf(row*fBeta)*sinf(col*fAlpha); //计算顶点的纹理坐标 pVertices[nIndex]._u=col*fAlpha/(2.0f*D3DX_PI); pVertices[nIndex]._v=row*fBeta/(D3DX_PI/2.0f); nIndex++; } } m_pVertexBuf->Unlock(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第11讲 天空 11