Archived

This topic is now archived and is closed to further replies.

emmai

Geomipmapping & triangle fan

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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;
}

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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)

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites