Geomipmapping & triangle fan

Started by
8 comments, last by emmai 19 years, 11 months ago
my geomipmapping is too slow...11fps with triangle fan but using triangle list,even bruteforce can got 100fps how can I solve this...any idea is appreciated.
Advertisement
Have you thought about using ROAM instead?

Chris
Chris ByersMicrosoft DirectX MVP - 2005
quote:Original post by Supernat02
Have you thought about using ROAM instead?

Chris



For even slower results?

With the current 3D hardware there is no need for ROAM or CPU based calculations. Of course it is a great thing to learn to understand, but hardware solutions are a much better alternative.

[edited by - Imperil on April 22, 2004 12:58:15 PM]
it''s only 257*257 terrain
GeomipmappingTerrain.cpp
// GeomipmappingTerrain.cpp: implementation of the CGeomipmappingTerrain class.////////////////////////////////////////////////////////////////////////#include "GeomipmappingTerrain.h"typedef struct GEOMIPMAPPING_VERTEX{	D3DXVECTOR3		v;	DWORD			dwColor;	float fu,fv;	float fu1,fv1;	static DWORD	FVF;}GEOMIPMAPPING_VERTEX;DWORD GEOMIPMAPPING_VERTEX::FVF = D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX2;CGeomipmappingTerrain::CGeomipmappingTerrain(){	m_dwPatchSize = 17;	m_pPatchInfo = 0;	m_dwMaxLod = 0;	m_pVB = 0;}HRESULT CGeomipmappingTerrain::CreateVertexBuffer(){	SAFE_RELEASE(m_pVB);	HRESULT hr = m_pDevice->CreateVertexBuffer(10 * sizeof(GEOMIPMAPPING_VERTEX),D3DUSAGE_WRITEONLY,GEOMIPMAPPING_VERTEX::FVF,D3DPOOL_MANAGED,&m_pVB,0);	if(FAILED(hr))	{		return E_FAIL;	}	return S_OK;}CGeomipmappingTerrain::~CGeomipmappingTerrain(){	SAFE_DELETE(m_pPatchInfo);}HRESULT CGeomipmappingTerrain::InitDeviceObjects(LPDIRECT3DDEVICE9 pDevice,D3DXVECTOR3 vScale){	m_pDevice = pDevice;	m_vScale = vScale;	CreateVertexBuffer();	m_pDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);	m_pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );    m_pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );	m_pDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU,  D3DTADDRESS_MIRROR);	m_pDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV,  D3DTADDRESS_MIRROR);	m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);	m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );  	m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); 	m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE );	m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT );  	m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_LERP);	m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG0, D3DTA_CURRENT);	return S_OK;}HRESULT CGeomipmappingTerrain::DeleteDeviceObjects(){	SAFE_RELEASE(m_pVB);	return S_OK;}void CGeomipmappingTerrain::SetPatchSize(DWORD dwSize){	m_dwPatchSize = dwSize;	SAFE_DELETE(m_pPatchInfo);	m_dwPatchPerSide = (m_dwSize - 1) / (m_dwPatchSize - 1);	m_dwMaxLod = 0;	DWORD dwPatchSize = m_dwPatchSize - 1;	while(dwPatchSize > 2)	{		dwPatchSize>>=1;		m_dwMaxLod++;	}	m_pPatchInfo = new GeoPatch[m_dwPatchPerSide * m_dwPatchPerSide];}HRESULT CGeomipmappingTerrain::FrameMove(float fTime,CCamera camera){	D3DXVECTOR3 vEye = camera.m_vPos;	for(DWORD dwZ = 0;dwZ < m_dwPatchPerSide;dwZ++)		for(DWORD dwX = 0;dwX < m_dwPatchPerSide;dwX++)		{			D3DXVECTOR3 vCenter;			vCenter.x = (dwX + 0.5f) * (m_dwPatchSize - 1) * m_vScale.x;			vCenter.z = (dwZ + 0.5f) * (m_dwPatchSize - 1) * m_vScale.z;			vCenter.y = GetScaledHeight(dwX * (m_dwPatchSize - 1) + (m_dwPatchSize - 1) / 2,dwZ * (m_dwPatchSize - 1) + (m_dwPatchSize - 1) / 2);			m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_fDistance = sqrtf((vEye.x - vCenter.x) * (vEye.x - vCenter.x) + (vEye.y - vCenter.y) * (vEye.y - vCenter.y) + (vEye.z - vCenter.z) * (vEye.z - vCenter.z));			m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_dwLOD = ((DWORD)m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_fDistance) / 64;			if(m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_dwLOD > m_dwMaxLod)				m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_dwLOD = m_dwMaxLod;			if(camera.CubeFrustumTest(vCenter.x,vCenter.y,vCenter.z,m_dwPatchSize * m_vScale.x))				m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_bVisible = TRUE;			else				m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_bVisible = FALSE;		}	return S_OK;}HRESULT CGeomipmappingTerrain::RenderPatch(DWORD dwX,DWORD dwZ){	DWORD dwLod = m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_dwLOD;	DWORD dwFanSize = (m_dwPatchSize - 1) / (1 << (m_dwMaxLod - dwLod)) + 1;	DWORD dwFanHalfSize = dwFanSize / 2;	for(DWORD Z = dwFanHalfSize;Z < m_dwPatchSize - 1;Z += (dwFanSize - 1))		for(DWORD X = dwFanHalfSize;X < m_dwPatchSize - 1;X += (dwFanSize - 1))		{			BOOL bLeft = TRUE,bUp = TRUE,bRight = TRUE,bDown = TRUE;			if(X == dwFanHalfSize)			{				if(dwX == 0 || (m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX - 1].m_dwLOD <= dwLod))				{				}				else				{					bLeft = FALSE;				}			}			if(Z == dwFanHalfSize)			{				if(dwZ == 0 || (m_pPatchInfo[(dwZ - 1) * m_dwPatchPerSide + dwX].m_dwLOD <= dwLod))				{				}				else				{					bDown = FALSE;				}			}			if(X + (dwFanSize - 1) > (m_dwPatchSize - 1))			{				if(dwX == m_dwPatchPerSide - 1 || (m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX + 1].m_dwLOD <= dwLod))				{				}				else				{					bRight = FALSE;				}			}			if(Z + (dwFanSize - 1) > (m_dwPatchSize - 1))			{				if(dwZ == m_dwPatchPerSide - 1 || (m_pPatchInfo[(dwZ + 1) * m_dwPatchPerSide + dwX].m_dwLOD <= dwLod))				{				}				else				{					bUp = FALSE;				}			}			RenderFan(dwX,dwZ,X,Z,dwFanHalfSize,bLeft,bUp,bRight,bDown);		}	return S_OK;}inline void CGeomipmappingTerrain::SetVertex(GEOMIPMAPPING_VERTEX * pV,DWORD dwXX,DWORD dwZZ){	pV->v = D3DXVECTOR3(m_vScale.x * dwXX,GetScaledHeight(dwXX,dwZZ),m_vScale.z * dwZZ);	BYTE c = GetBrightness(dwXX,dwZZ);	pV->dwColor = D3DXCOLOR(c / 255.0f,c / 255.0f,c / 255.0f,1.0f);	pV->fu = (float)dwXX / (float)(m_dwSize - 1);	pV->fv = 1 - (float)dwZZ / (float)(m_dwSize - 1);	pV->fu1 = pV->fu * m_dwRepeat;	pV->fv1 = pV->fv * m_dwRepeat;}HRESULT CGeomipmappingTerrain::RenderFan(DWORD dwX,DWORD dwZ,DWORD X,DWORD Z,DWORD dwFanHalfSize,BOOL bLeft,BOOL bUp,BOOL bRight,BOOL bDown){	GEOMIPMAPPING_VERTEX *v = 0;	m_pVB->Lock(0,0,(void**)&v,0);	DWORD dwCount = 0;	if(v)	{		//center (X,Z)		DWORD dwCenterX = dwX * (m_dwPatchSize - 1) + X;		DWORD dwCenterZ = dwZ * (m_dwPatchSize - 1) + Z;		//center		SetVertex(&v[dwCount++],dwCenterX,dwCenterZ);		//lower left		SetVertex(&v[dwCount++],dwCenterX - dwFanHalfSize,dwCenterZ - dwFanHalfSize);		//left		if(bLeft)			SetVertex(&v[dwCount++],dwCenterX - dwFanHalfSize,dwCenterZ);		//upper left		SetVertex(&v[dwCount++],dwCenterX - dwFanHalfSize,dwCenterZ + dwFanHalfSize);		//up		if(bUp)			SetVertex(&v[dwCount++],dwCenterX,dwCenterZ + dwFanHalfSize);		//upper right		SetVertex(&v[dwCount++],dwCenterX + dwFanHalfSize,dwCenterZ + dwFanHalfSize);		//right		if(bRight)			SetVertex(&v[dwCount++],dwCenterX + dwFanHalfSize,dwCenterZ);		//lower right		SetVertex(&v[dwCount++],dwCenterX + dwFanHalfSize,dwCenterZ - dwFanHalfSize);		//down		if(bDown)			SetVertex(&v[dwCount++],dwCenterX,dwCenterZ - dwFanHalfSize);		//low left		SetVertex(&v[dwCount++],dwCenterX - dwFanHalfSize,dwCenterZ - dwFanHalfSize);				m_pVB->Unlock();					m_pDevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,dwCount - 2);	}	return S_OK;}HRESULT CGeomipmappingTerrain::Render(){	m_pDevice->SetTexture(0,m_pTexture);	m_pDevice->SetTexture(1,m_pDetailTexture);	m_pDevice->SetFVF(GEOMIPMAPPING_VERTEX::FVF);	m_pDevice->SetStreamSource(0,m_pVB,0,sizeof(GEOMIPMAPPING_VERTEX));	for(DWORD dwZ = 0;dwZ < m_dwPatchPerSide;dwZ++)		for(DWORD dwX = 0;dwX < m_dwPatchPerSide;dwX++)		{			if(m_pPatchInfo[dwZ * m_dwPatchPerSide + dwX].m_bVisible)				RenderPatch(dwX,dwZ);		}	return S_OK;}
GeomipmappingTerrain.h
#ifndef __GEOMIPMAPPING_TERRAIN_H__#define __GEOMIPMAPPING_TERRAIN_H__#include "terrain.h"#include "camera.h"struct GEOMIPMAPPING_VERTEX;class CGeomipmappingTerrain : public CTerrain  {public:typedef struct GeoPatch{	float	m_fDistance;	DWORD	m_dwLOD;	BOOL	m_bVisible;};private:	DWORD		m_dwPatchSize;	DWORD		m_dwPatchPerSide;	DWORD		m_dwMaxLod;	GeoPatch	*m_pPatchInfo;	LPDIRECT3DVERTEXBUFFER9	m_pVB;public:	CGeomipmappingTerrain();	virtual ~CGeomipmappingTerrain();private:	HRESULT CreateVertexBuffer();	void	SetVertex(GEOMIPMAPPING_VERTEX * pV,DWORD dwXX,DWORD dwZZ);public:	virtual HRESULT InitDeviceObjects(LPDIRECT3DDEVICE9 pDevice,D3DXVECTOR3 vScale = D3DXVECTOR3(1.0f,1.0f,1.0f));	virtual HRESULT DeleteDeviceObjects();	virtual HRESULT FrameMove(float fTime,CCamera camera);	virtual HRESULT Render();			void	SetPatchSize(DWORD dwSize);	HRESULT RenderPatch(DWORD dwX,DWORD dwZ);	HRESULT RenderFan(DWORD dwX,DWORD dwZ,DWORD X,DWORD Z,DWORD dwFanHalfSize,BOOL bLeft,BOOL bUp,BOOL bRight,BOOL bDown);};#endif
I am assuming you mean the algorithm by Willem H. de Boar. I have also implemented this and have not had the same problems so you should be able to get much better FPS.

I see you render using only triangle fans. What I did is render the entire patch with one triangle strip and between each patch I used fans to compensate for the different sampling level.

I would recommend that you strip every thing off and see what happens, try to locate the bottle neck. Try rendering with no textures, constant height and ext so you focus only on the algorithm.

By the way I’m not entirely convinced that this algorithm is really better than ROAM
Don't shoot! I'm with the science team.....
Well, I guess you read the book by Trent Polack.
I''m working on a terrain project at the moment as well, but in contrast to Trent, I use two important things: TrianglesStrips and Indexbuffers.
You can use fans (it''s easier) without any great performance losses.
But as countless vertices appear more than once, I would create one big vertex buffer with all vertices appearing in the terrain. Then, I would use an index buffer for every patch and fill it with the according values.
And last, I recommend you to use the L1-Norm for calculating distances, square-Roots are incredibly slow (in general, be careful that you use the most efficient algorithms to detect the LOD dynamically...)
Greetings,
Chris
since modern hardware does autostripping from independant triangles, and the lower state changes the better, you should try to cache your terrain into a unique/or some VertexBuffer/IndexBuffer couple(s), and draw it entirely throught few DrawIndexedPrimitve calls. (the index buffer make the GPU use its Post-T&L cache).

how much triangles have you per DrawPrimitve ? ( too few means you are cpu/DrawPrimitve bound, too few would be below 30-100 triangles, the higher triangle count between DrawPrimitve calls the better efficiency)

Of the two terrain books I''ve read so far, they start out with Geomipmapping and then discuss why ROAM is faster. The examples always run faster as well. They are fairly recent books, but I have no doubt they could be wrong. I should mention that they use the ROAM algorithm as a basis and then implement it much more efficiently. Anyway, I''m curious what book you guys are reading on Geomipmapping. I would like to check it out too. Also, what hardware solutions are you talking about Imperil? I''m still trying to learn the best way to approach terrain rendering, and any info would help.

Thanks!
Chris
Chris ByersMicrosoft DirectX MVP - 2005
to OrenGL:
I have thinked a lot,but I still can''t imagine how to render the entire patch with one triangle strip.the frustum culling may cull many patchs.

to Christoph Well:
sure,I''m now reading the book by Trent Polack
I found it''s hard to render geomipmapping using TriangleStrips & IndexBuffers,say,when I go forward or backward the terrain,large amount of vertices will be added or emitted to/from the terrain.how can u do this like that?

to bjone:
you mean buffer the vertices,and calculate the visible triangles every frame and render them once?

This topic is closed to new replies.

Advertisement