⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lodterrain.cpp

📁 里内面有两个关于地形的模拟的范例,仔细看一下会收获不小啊
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#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 + -