📄 lodterrain.cpp
字号:
#include "..\..\GameEngine\GameEngine_Common.h"
#include "LODTerrain.h"
#include "Frustum.h"
#include "Camera.h"
CLODTerrain::CLODTerrain(LPDIRECT3DDEVICE9 pd3dDevice,bool bUseHeightFile){
m_pd3dDevice=pd3dDevice;
m_pFrustum=new CFrustum();
m_iTerrainSize=1024;
m_pbQuadMat=new bool[(m_iTerrainSize+1)*(m_iTerrainSize+1)];
m_fHeightScale=1.0f;
m_pucHeightData=new unsigned char[(m_iTerrainSize+1)*(m_iTerrainSize+1)];
m_fResolution=5.0f;
m_fHeightDetail=8.0f;
m_iTexMapRepeatNum=10;
m_bUseHeightFile=bUseHeightFile;
}
CLODTerrain::~CLODTerrain(){
delete[] m_pbQuadMat;
delete[] m_pucHeightData;
if(m_pVertexBuffer!=NULL){
m_pVertexBuffer->Release();
m_pVertexBuffer=NULL;
}
if(m_pTexture!=NULL){
m_pTexture->Release();
m_pTexture=NULL;
}
}
bool CLODTerrain::InitTerrain(TCHAR* szHeightFile,TCHAR* szTextureFile){
if(m_bUseHeightFile){
if(!InitTerrainByFile(szHeightFile,szTextureFile)){
return false;
}
}
else{
if(!InitTerrainByFun(szTextureFile)){
return false;
}
}
return true;
}
bool CLODTerrain::InitTerrainByFun(char* szTextureFile){
if(!InitQuadMat())
return false;
if(!InitVertexBuf())
return false;
if(FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,szTextureFile,&m_pTexture)))
return false;
return true;
}
bool CLODTerrain::InitTerrainByFile(TCHAR* szHeightFile,TCHAR* szTextureFile){
m_bUseHeightFile=true;
if(!InitQuadMat())
return false;
if(!InitVertexBuf())
return false;
if(!LoadHeightData(szHeightFile))
return false;
if(FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,szTextureFile,&m_pTexture)))
return false;
return true;
}
bool CLODTerrain::InitQuadMat(){
if(!m_pbQuadMat){
MessageBox(NULL,"创建地形标志数组内存不足","提示",0);
return false;
}
for(int x=0;x<=m_iTerrainSize;x++){
for(int z=0;z<=m_iTerrainSize;z++){
SetQuadMatData(x,z,false);
}
}
return true;
}
bool CLODTerrain::InitVertexBuf(){
if(FAILED(m_pd3dDevice->CreateVertexBuffer(10*sizeof(CUSTOMVERTEX),0,CUSTOMVERTEX_FVF,
D3DPOOL_MANAGED,&m_pVertexBuffer,NULL))){
MessageBox(NULL,"创建顶点缓冲区失败","提示",0);
return false;
}
return true;
}
bool CLODTerrain::LoadHeightData(TCHAR* szFileName){
FILE* pFile;
pFile=fopen(szFileName,"rb");
if(!pFile){
return false;
}
if(!m_pucHeightData){
MessageBox(NULL,"创建地形数据内存不足","提示",0);
}
fread(m_pucHeightData,1,(m_iTerrainSize+1)*(m_iTerrainSize+1),pFile);
fclose(pFile);
return true;
}
float CLODTerrain::GenerateHeightData(float x,float z){
return 8*sinf(x)*cosf(z/10)+1.0f;
}
bool CLODTerrain::GetQuadMatData(int x,int z){
return m_pbQuadMat[m_iTerrainSize*z+x];
}
void CLODTerrain::SetQuadMatData(int x,int z,bool b){
if(x>=0 && x<=m_iTerrainSize && z>=0 && z<=m_iTerrainSize){
m_pbQuadMat[m_iTerrainSize*z+x]=b;
}
}
void CLODTerrain::TrimNodeSplit(int iX,int iZ,int iNodeLength){ //去除不合法的分割
int iChildNodeOffset=iNodeLength/4;
int iChildNodeLength=iNodeLength/2;
if(iNodeLength>=4 && GetQuadMatData(iX,iZ)==true){
if((iX+iNodeLength)<=m_iTerrainSize && GetQuadMatData(iX+iNodeLength,iZ)==false){
SetChildNodeFalse(iX+iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
SetChildNodeFalse(iX+iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
}
if((iZ-iNodeLength)>=0 && GetQuadMatData(iX,iZ-iNodeLength)==false){
SetChildNodeFalse(iX-iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
SetChildNodeFalse(iX+iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
}
if((iX-iNodeLength)>=0 && GetQuadMatData(iX-iNodeLength,iZ)==false){
SetChildNodeFalse(iX-iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
SetChildNodeFalse(iX-iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
}
if((iZ+iNodeLength)<=m_iTerrainSize && GetQuadMatData(iX,iZ+iNodeLength)==false){
SetChildNodeFalse(iX-iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
SetChildNodeFalse(iX+iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
}
TrimNodeSplit(iX+iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
TrimNodeSplit(iX+iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
TrimNodeSplit(iX-iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
TrimNodeSplit(iX-iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
}
else if(GetQuadMatData(iX,iZ)==false){
SetChildNodeFalse(iX,iZ,iNodeLength);
}
}
void CLODTerrain::SetChildNodeFalse(int iX,int iZ,int iNodeLength){
int iChildNodeOffset=iNodeLength/4;
int iChildNodeLength=iNodeLength/2;
SetQuadMatData(iX,iZ,false);
if(iNodeLength>=4){
SetChildNodeFalse(iX+iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
SetChildNodeFalse(iX+iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
SetChildNodeFalse(iX-iChildNodeOffset,iZ-iChildNodeOffset,iChildNodeLength);
SetChildNodeFalse(iX-iChildNodeOffset,iZ+iChildNodeOffset,iChildNodeLength);
}
}
void CLODTerrain::UpdateTerrain(CCamera* pCamera){
SplitNode(m_iTerrainSize/2.0f,m_iTerrainSize/2.0f,m_iTerrainSize,pCamera);
TrimNodeSplit(m_iTerrainSize/2,m_iTerrainSize/2,m_iTerrainSize);
}
void CLODTerrain::Render(){
m_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
m_pd3dDevice->SetRenderState(D3DRS_LIGHTING,false);
m_pd3dDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
m_pd3dDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
m_pd3dDevice->SetFVF(CUSTOMVERTEX_FVF);
m_pd3dDevice->SetTexture(0,m_pTexture);
m_pd3dDevice->BeginScene();
RenderNode(m_iTerrainSize/2.0f,m_iTerrainSize/2.0f,m_iTerrainSize);
m_pd3dDevice->EndScene();
m_pd3dDevice->Present(NULL,NULL,NULL,NULL);
}
void CLODTerrain::SplitNode(float x,float z,int iNodeLength,CCamera* pCamera){
int iX=(int)x;
int iZ=(int)z;
float y;
if(!m_bUseHeightFile)
y=m_pucHeightData[iZ*m_iTerrainSize+iX]*m_fHeightScale; //该点的高度
else
y=GenerateHeightData(x,z)*m_fHeightScale;
float fCameraDistance;
float fRule;
bool bSplit;
int iChildNodeLength;
float fChildNodeOffset;
//节点不在视截体内,设置标志后返回
m_pFrustum->GetFrustum(m_pd3dDevice,0.0f);
if(m_pFrustum->CheckCube(x,y,z,(float)iNodeLength))
m_pbQuadMat[m_iTerrainSize*iZ+iX]=true;
else{
m_pbQuadMat[m_iTerrainSize*iZ+iX]=false;
return;
}
//距离检测
D3DXVECTOR3* pCameraPos=NULL;
pCameraPos=pCamera->GetCameraPos();
fCameraDistance=(float)(fabs(pCameraPos->x-x)+
fabs(pCameraPos->y-y)+
fabs(pCameraPos->z-z));
//变形幅度估值
if(m_bUseHeightFile==true){
int iVertexOffset=iNodeLength>>1;
int iChildNodeLength=iVertexOffset>>1;
float fArrayHeightEva[9];
fArrayHeightEva[0]=m_pucHeightData[m_iTerrainSize*iZ+iX]*m_fHeightScale;
fArrayHeightEva[1]=m_pucHeightData[m_iTerrainSize*iZ+(iX+iVertexOffset)]*m_fHeightScale;
fArrayHeightEva[2]=m_pucHeightData[m_iTerrainSize*(iZ-iVertexOffset)+iX]*m_fHeightScale;
fArrayHeightEva[3]=m_pucHeightData[m_iTerrainSize*iZ+(iX-iVertexOffset)]*m_fHeightScale;
fArrayHeightEva[4]=m_pucHeightData[m_iTerrainSize*(iZ+iVertexOffset)+iX]*m_fHeightScale;
fArrayHeightEva[5]=m_pucHeightData[m_iTerrainSize*(iZ+iChildNodeLength)+(iX+iChildNodeLength)]*m_fHeightScale;
fArrayHeightEva[6]=m_pucHeightData[m_iTerrainSize*(iZ-iChildNodeLength)+(iX+iChildNodeLength)]*m_fHeightScale;
fArrayHeightEva[7]=m_pucHeightData[m_iTerrainSize*(iZ-iChildNodeLength)+(iX-iChildNodeLength)]*m_fHeightScale;
fArrayHeightEva[8]=m_pucHeightData[m_iTerrainSize*(iZ+iChildNodeLength)+(iX-iChildNodeLength)]*m_fHeightScale;
float fMaxHeight=fArrayHeightEva[0];
float fMinHeight=fArrayHeightEva[0];
for(int i=1;i<9;i++){
if(fArrayHeightEva[i]>fMaxHeight)
fMaxHeight=fArrayHeightEva[i];
if(fArrayHeightEva[i]<fMinHeight)
fMinHeight=fArrayHeightEva[i];
}
float fHeightDiff=fMaxHeight-fMinHeight;
if(fHeightDiff<=0.0f){
return;
}
float r=iNodeLength/fHeightDiff;
fRule=fCameraDistance/(iNodeLength*m_fResolution*r*m_fHeightDetail);
}
if(m_bUseHeightFile==false){
fRule=fCameraDistance/(iNodeLength*m_fResolution);
}
//设置节点分割标志
if(fRule<1.0f){
bSplit=true; //需要继续分割
}
else{
bSplit=false;
}
m_pbQuadMat[m_iTerrainSize*iZ+iX]=bSplit;
//需要分割的情形
if(bSplit){
if(iNodeLength>=4){ //节点未足够小
iChildNodeLength=iNodeLength/2; //一半长
fChildNodeOffset=iNodeLength/4.0f; //子节点中心的偏移量
//分割出上方的左节点
SplitNode(x-fChildNodeOffset,z+fChildNodeOffset,iChildNodeLength,pCamera);
//分割出上方的右节点
SplitNode(x+fChildNodeOffset,z+fChildNodeOffset,iChildNodeLength,pCamera);
//分割出下方的左节点
SplitNode(x-fChildNodeOffset,z-fChildNodeOffset,iChildNodeLength,pCamera);
//分割出下方的右节点
SplitNode(x+fChildNodeOffset,z-fChildNodeOffset,iChildNodeLength,pCamera);
}
}
}
void CLODTerrain::RenderNode(float x,float z,int iNodeLength){
int iX=(int)x;
int iZ=(int)z;
bool bSplit;
CUSTOMVERTEX vertices[10];
//顶点
float fVertexOffset=(iNodeLength)/2.0f;
float fRightX=x+fVertexOffset;
float fLeftX=x-fVertexOffset;
float fTopZ=z+fVertexOffset;
float fBottomZ=z-fVertexOffset;
//
int i;
int iChildNodeOffset;
int iChildNodeLength;
int iOutChildNodeOffset;
bool bTopRight,bTopLeft,bBottomRight,bBottomLeft;
int iChangeOffset1,iChangeOffset2;
//
bSplit=GetQuadMatData(iX,iZ);
if(bSplit==true){
if(iNodeLength<=2){ //节点已足够小,直接渲染该节点
i=0;
GenerateVertex(x,z,vertices[i]);
i++;
//右上角的顶点
GenerateVertex(fRightX,fTopZ,vertices[i]);
i++;
//右边上的中点
GenerateVertex(fRightX,z,vertices[i]);
i++;
//右下角的顶点
GenerateVertex(fRightX,fBottomZ,vertices[i]);
i++;
GenerateVertex(x,fBottomZ,vertices[i]);
i++;
//左下角的顶点
GenerateVertex(fLeftX,fBottomZ,vertices[i]);
i++;
//左边上的中点
GenerateVertex(fLeftX,z,vertices[i]);
i++;
//左上角的顶点
GenerateVertex(fLeftX,fTopZ,vertices[i]);
i++;
//上边的中点
GenerateVertex(x,fTopZ,vertices[i]);
i++;
//右上角的顶点(重复一次)
GenerateVertex(fRightX,fTopZ,vertices[i]);
i++;
//渲染三角扇形
RenderTriFan(vertices,i);
return;
}
//节点不渲染,继续分割
iChildNodeOffset=iNodeLength>>2;
iChildNodeLength=iNodeLength>>1;
iOutChildNodeOffset=iChildNodeOffset+iChildNodeLength;
iChangeOffset1=iChildNodeOffset>>1;
iChangeOffset2=iChildNodeOffset+iChangeOffset1;
//
bTopRight=GetQuadMatData(iX+iChildNodeOffset,iZ+iChildNodeOffset);
bTopLeft=GetQuadMatData(iX-iChildNodeOffset,iZ+iChildNodeOffset);
bBottomRight=GetQuadMatData(iX+iChildNodeOffset,iZ-iChildNodeOffset);
bBottomLeft=GetQuadMatData(iX-iChildNodeOffset,iZ-iChildNodeOffset);
//4个子节点均分割的情形
if(bTopRight && bTopLeft && bBottomRight && bBottomLeft){
RenderNode(x+iChildNodeOffset,z+iChildNodeOffset,iChildNodeLength);
RenderNode(x+iChildNodeOffset,z-iChildNodeOffset,iChildNodeLength);
RenderNode(x-iChildNodeOffset,z-iChildNodeOffset,iChildNodeLength);
RenderNode(x-iChildNodeOffset,z+iChildNodeOffset,iChildNodeLength);
return;
}
//3个子节点分割的情形
if(bTopRight==false && bTopLeft==true && bBottomRight==true && bBottomLeft==true){
i=0;
GenerateVertex(x+iChildNodeOffset,z+iChildNodeOffset,vertices[i]);
i++;
GenerateVertex(fRightX,fTopZ,vertices[i]);
i++;
if((iX+iOutChildNodeOffset)<=m_iTerrainSize && GetQuadMatData(iX+iOutChildNodeOffset,iZ+iChildNodeOffset)==true){
GenerateVertex(fRightX,z+iChildNodeOffset,vertices[i]);
i++;
}
GenerateVertex(fRightX,z,vertices[i]);
i++;
//下边的中点
GenerateVertex(x+iChildNodeOffset,z,vertices[i]);
i++;
GenerateVertex(x,z,vertices[i]);
i++;
//左边的中点
GenerateVertex(x,z+iChildNodeOffset,vertices[i]);
i++;
GenerateVertex(x,fTopZ,vertices[i]);
i++;
if((z+iOutChildNodeOffset)<=m_iTerrainSize && GetQuadMatData(iX+iChildNodeOffset,iZ+iOutChildNodeOffset)==true){
GenerateVertex(x+iChildNodeOffset,fTopZ,vertices[i]);
i++;
}
GenerateVertex(fRightX,fTopZ,vertices[i]);
i++;
//渲染三角扇形
RenderTriFan(vertices,i);
//继续分割其余3个子节点
RenderNode(x+iChildNodeOffset,z-iChildNodeOffset,iChildNodeLength);
RenderNode(x-iChildNodeOffset,z-iChildNodeOffset,iChildNodeLength);
RenderNode(x-iChildNodeOffset,z+iChildNodeOffset,iChildNodeLength);
}
if(bTopRight==true && bTopLeft==false && bBottomRight==true && bBottomLeft==true){
i=0;
GenerateVertex(x-iChildNodeOffset,z+iChildNodeOffset,vertices[i]);
i++;
GenerateVertex(x,fTopZ,vertices[i]);
i++;
GenerateVertex(x,z+iChildNodeOffset,vertices[i]);
i++;
GenerateVertex(x,z,vertices[i]);
i++;
GenerateVertex(x-iChildNodeOffset,z,vertices[i]);
i++;
GenerateVertex(fLeftX,z,vertices[i]);
i++;
if((x-iOutChildNodeOffset)>=0 && GetQuadMatData(iX-iOutChildNodeOffset,iZ+iChildNodeOffset)==true){
GenerateVertex(fLeftX,z+iChildNodeOffset,vertices[i]);
i++;
}
GenerateVertex(fLeftX,fTopZ,vertices[i]);
i++;
if((z+iOutChildNodeOffset)<=m_iTerrainSize && GetQuadMatData(iX-iChildNodeOffset,iZ+iOutChildNodeOffset)==true){
GenerateVertex(x-iChildNodeOffset,fTopZ,vertices[i]);
i++;
}
GenerateVertex(x,fTopZ,vertices[i]);
i++;
//渲染三角扇形
RenderTriFan(vertices,i);
//继续分割其余3个节点
RenderNode(x+iChildNodeOffset,z+iChildNodeOffset,iChildNodeLength);
RenderNode(x+iChildNodeOffset,z-iChildNodeOffset,iChildNodeLength);
RenderNode(x-iChildNodeOffset,z-iChildNodeOffset,iChildNodeLength);
}
if(bTopRight==true && bTopLeft==true && bBottomRight==false && bBottomLeft==true){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -