Archived

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

steg

terrain looks terrible

Recommended Posts

Hi all, I am rendering some terrain using quads, the height map I have generated with PSP and loaded in as a raw file, set the y-vertices to the data in from the height map for each quad. After inspecting what I get from the height map it looks as followsnote this was for debug info) (x,y,z,diffuse color) {0,151.000000,0,D3DCOLOR_XRGB(0,255,0)}, {1,154.000000,0,D3DCOLOR_XRGB(0,255,0)}, {2,150.000000,0,D3DCOLOR_XRGB(0,255,0)}, {3,148.000000,0,D3DCOLOR_XRGB(0,255,0)}, {4,148.000000,0,D3DCOLOR_XRGB(0,255,0)}, {5,143.000000,0,D3DCOLOR_XRGB(0,255,0)}, {6,134.000000,0,D3DCOLOR_XRGB(0,255,0)}, {7,129.000000,0,D3DCOLOR_XRGB(0,255,0)}, {8,124.000000,0,D3DCOLOR_XRGB(0,255,0)}, {9,116.000000,0,D3DCOLOR_XRGB(0,255,0)}, etc.... The method I use for creating quads (storing in my vertex table): void CreateQuads() { for(int z=0; z<32; z++) // 32 is height size { for (int x=0; x<32; x++) // 32 is width { quadVertices[z][x].x = (float)x; quadVertices[z][x].z = (float)z; quadVertices[z][x].y = GetHeight(z,x); quadVertices[z][x].DiffuseColor = D3DCOLOR_XRGB (0,255,0); } } } Get height method: float GetHeight(int z, int x) { int pos = (32 * z) + x; float height = pData[pos]; return height; } pData contains the height map, now when I brute force render this it looks terrible (I am using Triangle strips). Anyone any ideas ? Kind regards, Steve

Share this post


Link to post
Share on other sites
Your z values are all zero, you should increase your z values linearly, as you have with your x values otherwise your quads will all be rendered with the same z coordinate. This though seems a little unlikely, perhaps I''m misunderstanding the data you show that you get from the heightmap?

Share this post


Link to post
Share on other sites
Normally, you would have some sort of x,z scale, where you would do:

quadVertices[z][x].x = (float)x*ScaleX;
quadVertices[z][x].z = (float)z*ScaleZ;

Just to make the quads larger than 1 unit (unless that was the scale you were going for to begin with, which is unlikely). Also, using a single color isn''t going to look the greatest, because you can''t really tell the difference of depths very well. I think it''ll look a LOT better once you get that color thing figured out, any shading at all will help tremendously.

if (z<31 && x<31) //Can''t +1 to these, otherwise it goes beyond the bounds of our map!
{
float tmp1, tmp2;
tmp1 = quadVertices[z+1][x+1].x-quadVertices[z][x].x;
tmp2 = quadVertices[z+1][x+1].z-quadVertices[z][x].z;
tmp1*=tmp1;
tmp2*=tmp2;
tmp1 = sqrtf(tmp1+tmp2)/2.0f; //Return a number between 0 - 255 depending on the angle of incline/decline.
quadVertices[z][x].DiffuseColor = D3DCOLOR_XRGB (tmp,tmp,tmp);
}

Share this post


Link to post
Share on other sites
Thanks guys,

Mephs, the Z-values aren''t all zero (just the example data I shown is misleading), they go up linearly like you mentioned, Example :

{0,116.000000,3,D3DCOLOR_XRGB(0,255,0)}
{1,117.000000,3,D3DCOLOR_XRGB(0,255,0)}
{2,119.000000,3,D3DCOLOR_XRGB(0,255,0)}
{etc...},
{etc...},
{31,107.000000,3,D3DCOLOR_XRGB(0,255,0)}
{0,114.000000,4,D3DCOLOR_XRGB(0,255,0)}
{1,114.000000,4,D3DCOLOR_XRGB(0,255,0)}
{2,116.000000,4,D3DCOLOR_XRGB(0,255,0)}
{3,118.000000,4,D3DCOLOR_XRGB(0,255,0)}

We see here that the x-values go up linearly by one, they y-values are from the height map and z is set to 3, this will increase to 4 the next time as shown.

Thanks Ready4Dis for the colour info and scale info.

Maybe I''m rendering the data wrong ?

I create the vertex buffer as shown (1024 is 32x32):
r = g_pDevice->CreateVertexBuffer(sizeof(MYVERTEX)*1024,0,CUSTOM_MYVERTEX,D3DPOOL_DEFAULT,&g_pVB,NULL);

Then I lock the buffer:
r = g_pVB->Lock(0,1024*16,(void**)&pVertices,0);

Then copy:
CopyMemory(pVertices,&quadVertices,1024*16);

and render with DrawPrimitive:
g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1020)

I''m not so sure about the 1020 I''ve put into the DrawPrimitive primitivecount parameter ?

Any more clues ?

Kindest regards,
Steve

Share this post


Link to post
Share on other sites
It would help if you would explain ''looks terrible'' a little better. My best guess is that it is just ups and downs all over way too close to each other. Take a look at your y values. They are going up and down large amounts each vertex, with only 1 x/z space between each one. My suggestion is to divide the values you get from the height map to make the values not change so much. Try something between 8-16 to start with. See what happens.

Share this post


Link to post
Share on other sites
Thanks AikonIV,

I''ll elaborate, some of the terrain looks correct while other parts of it has lines stretching across the screen, some not even connected ?

Having divided the height value it does look a little better but still some lines are stretching across the screen ?

Kind regards,
Steve

Share this post


Link to post
Share on other sites
Hmm, you said you are using triangle strips. Are you doing using just one strip or are you using more than one? More specifically, are your strips spanning more than one Z value? If they are, make sure that they alternate the direction they go in every time Z increases. Otherwise you''ll have polygons going from the right side of the map over to the left side.

I would suggest trying it using triangle lists. If it works, what I described above may be the culprit. You could try using a seperate list for each Z value.

Share this post


Link to post
Share on other sites
Thanks again AikonIV,

I''ll try it with Triangle lists, I''m thinking that it is the strips.
I''m also using untransformed vertices as I''m planning on later having the terrain move (I know I''ve a long way to go....quad trees etc...), guess this is correct ?

Kind regards,
Steve

Share this post


Link to post
Share on other sites
In case you hadn''t guessed it, I recently finished implementing a basic terrain engine. My FVF is XYZ|NORMAL|TEX1. I should try using transformed vertices tho. Could potentially give a (desperatly needed ) speed increase.

If it turns out your triangle strips aren''t the problem tho, I don''t think I''ll be able to help much more. I''m just about out of ideas.

Also, are you using index buffers or just straight vertex buffers? If you aren''t using index buffers, seriously consider using them.

Share this post


Link to post
Share on other sites
Thanks AikonIV,

Not using index buffers, does this give a big speed increase over using just triangle strips ?

I think it is the strips, I just drawing one big one which is wrong, I guess you draw one strip the width of your screen and then draw another etc ?

Steve

Share this post


Link to post
Share on other sites
Yeah, index buffers will probably give you a decent speed increase. In my case I'm using triangle lists to build my terrain engine. A leaf node has 4 triangles which come together to form each square (12 vertexes). Using an index buffer, this reduced down to 5 vertexes (center, NW, NE, SW, SE). I went from about 80FPS to around 110 on a GeForce2 (it's a small 129x129 heightmap) and they took less than 30 minutes to implement.

[edited by - bpopp on March 18, 2003 10:39:10 AM]

Share this post


Link to post
Share on other sites
I am not sure (cuz i didnt spend much time looking at your code) but drawing all your terrain with one trianglestrip call is the problem
a trianglestrip should end after 32 points if you dont use fake triangles

what i mean is you have to use 32 trianglestrip calls one for each row (if u dont use fake triangles to continue one line to other)

like:

drawprimitive for first row
drawprimitive for second row
....
etc...

if you dont do that the triangle at the end of each row will be messed up

the solution either use fake triangles at the end of each row to make a new start from the second row or USE TRIANGLELISTS...

i hope that helps


When left alone, things tend to get bad to worse. Finally, it will get f**cked up way before than you expect...

Share this post


Link to post
Share on other sites
Hi all,

I''m now trying to draw 32 triangle strips as shown :

g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 29); // 31 - 2
g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 30, 59);
etc...
I know this should be in a looop but just showing this for simplicity.
Now first strip renders correctly, second does not, lines stretch across the screen ? I guess my vertices are not joining up after the first strip ?

Any ideas ?

Sorry for keep asking!

Thanks,
Steve

Share this post


Link to post
Share on other sites
Ooops,

Just noticed that my primitive count is wrong! Show always be 29, don''t know what I was thinking.

g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 29); // 31 - 2
g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 31, 29);

Share this post


Link to post
Share on other sites
Hi all,

Ok, no long lines going all the way across the screen now by using 32 strips :

for(int i=0; i<31; i++)
{
g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i*32, 29);
}

But....still doesn''t look too nice, when I turn culling mode on I have big gaps with triangles not connected, I don''t think this is correct ? Could be wrong ?

Any ideas ?

Thanks,
Steve

Share this post


Link to post
Share on other sites

If you are getting gaps like that with culling on, then the winding order on the co-ords of the vertices is wrong.

Go check the docs about the correct way to do the winding!

Share this post


Link to post
Share on other sites
Hi AikonIV,

Vertices are filled as shown below :

struct MYVERTEX
{
float x,y,z;
DWORD DiffuseColor;
};
MYVERTEX quadVertices[32][32];

for(int z=0; z<31; z++) // 1024 is height size
{
for (int x=0; x<31; x++)
{
quadVertices[z][x].x = (float)x; //* ScaleX;
quadVertices[z][x].z = (float)z; //* ScaleZ;
quadVertices[z][x].y = GetHeight(z,x) / 8;
}
}

float GetHeight(int z, int x)
{
int pos = (z*32) + x;
return pData[pos]; // pData is height map data
}

Function to load height map from raw file:

BOOL ReadHeightMap(LPSTR szFilename)
{
BOOL bRead = FALSE;
DWORD dwSize = 0;
DWORD dwBytesRead = 0;
HANDLE handle = ::CreateFile (szFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);
if(handle!=INVALID_HANDLE_VALUE)
{
dwSize = ::GetFileSize(handle,NULL);
pData = new unsigned char[dwSize];
memset(pData,''\0'',dwSize);
if(::ReadFile(handle, pData, dwSize, &dwBytesRead, NULL)!=0)
bRead = TRUE;
::CloseHandle(handle);
}
return bRead;
}

g_pDevice->SetFVF(CUSTOM_ZENVERTEX);
g_pDevice->SetRenderState(D3DRS_LIGHTING,FALSE);
g_pDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
g_pDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
---
for(int i=0; i<31; i++)
{
g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, i*32, 28);
}

Maybe it is when I''m drawing the next strip ?

I would post a screen shot but how do you do that ?

Regards,
Steve

Share this post


Link to post
Share on other sites
Yep, looks like it''s probably your tri strips that are the problem. You can''t just fill in your vertices as a 2D array and expect them to draw directly whether you use triangle strips/lists/whatever. However if you use index buffers you can do something like that.

Here is how you should fill in your vertex buffer if you were using triangle lists.

MYVERTEX quadVertices[32*32*6]; //Note that we are using one-dimensional array. We are also using six vertices per quad

for(int i=0;i<31;i++) //Note that our loops are going to one less than the size of the vertex array
{
for(int j=0;j<31;j++)
{
DWORD tmp = (i+(j*32))*6; //This is the ID of the first vertex used in this quad

//We have to split the quad into two triangles

//The first triangle
quadVertices[tmp+0].x = (i+0)*1.0;
quadVertices[tmp+0].z = (j+0)*1.0;
quadVertices[tmp+0].y = GetHeight(i+0,j+0);

quadVertices[tmp+1].x = (i+1)*1.0;
quadVertices[tmp+1].z = (j+0)*1.0;
quadVertices[tmp+1].y = GetHeight(i+1,j+0);

quadVertices[tmp+2].x = (i+0)*1.0;
quadVertices[tmp+2].z = (j+1)*1.0;
quadVertices[tmp+2].y = GetHeight(i+0,j+1);

//The second tri
quadVertices[tmp+3].x = (i+1)*1.0;
quadVertices[tmp+3].z = (j+0)*1.0;
quadVertices[tmp+3].y = GetHeight(i+1,j+0);

quadVertices[tmp+4].x = (i+1)*1.0;
quadVertices[tmp+4].z = (j+1)*1.0;
quadVertices[tmp+4].y = GetHeight(i+1,j+1);

quadVertices[tmp+5].x = (i+0)*1.0;
quadVertices[tmp+5].z = (j+1)*1.0;
quadVertices[tmp+5].y = GetHeight(i+0,j+1);
}
}

You should be able to render that as one big triangle list. Note that I didn''t check winding order, so if culling is on, some might not be drawn.

If I didn''t explain myself well enough, just say so, and I''ll try to do better.

About posting a screenshot, I am assuming that you know how to get a screenshot but not how to post it? If you know how to get a screenshot, and using a triangle list doesn''t work for whatever reason, just email a screenshot (or more than one!) to me at aikoniv@yahoo.com

Share this post


Link to post
Share on other sites
Many thanks AikonIV,

I''ve been drawing this on a white board to try to better understand it, it seems so easy to do in OpenGL (this is an example I have) but Direct3D sets vertices up differently.
I guess I''m just thinking that by just putting the vertices into the vertex buffer they should be drawn correctly, guess this is completely wrong.

I will email you a screen shot.

Many thanks again.
Steve

Share this post


Link to post
Share on other sites
In case there was any question, it definitely is your triangle strips. If you want, you can try doing it the way I showed you using triangle lists.

If you''re tired of trying to get this working, I could email you a small demo of how I do it (that is, using an index buffer containing triangle list information.)

Just tell me if you want me to.

Share this post


Link to post
Share on other sites
Hiyas,
Just a gut reaction, and if I had more time I''d look into this more thoroughly, but if you say vertices are stretching across the screen, chances are the variables are initialised incorrectly or at some point set to an incorrect value. I remember having the same thing when coding a worldcraft *.map viewer, and the cause was, if I recall correctly, that some vertices were being calculated incorrectly, prolly a division by zero or something daft which of course made them stretch out to what looked like infinity or near as dammit

Share this post


Link to post
Share on other sites
Thanks guys,

It''s defo the triangle strips. I wasn''t even making the buffer size big enough to hold them! i.e.for 32x32 should be 32x32x4, 4 being number of vertices for a quad using lists method.
One question though, if I was drawing the quads row by row I''m thinking that the next quad has to have the same y,x value of the previous one ? Two quads below (1 and 2!) I''m taking it that quad 2 has to have same x,y veritces as quad vertices labelled 1 ? Does this make sense ?

| /|| /|
|/ ||/ |
12

AikonIV, your demo code would be much appreciated, I think I do know how to do this now, took me long time for it to sink in!

Kind regards,
Steve

Share this post


Link to post
Share on other sites
OK, I threw together a little demo using the D3D Matrices tutorial as the base code. I am doing it with multiple triangle strips, which I believe is how you are currently doing it. This code should compile and run with no problem, though it looks kinda stupid b/c I'm just generating random values for my height map rather than reading them in from a file. Will be no problem for you to change. If there are any parts you don't understand/would like explained in greater detail, just say so.


  
#include <d3dx8.h>
#include <mmsystem.h>

LPDIRECT3D8 g_pD3D = NULL; // Used to create the D3DDevice

LPDIRECT3DDEVICE8 g_pd3dDevice = NULL; // Our rendering device

LPDIRECT3DVERTEXBUFFER8 g_pVB = NULL; // Buffer to hold vertices


struct CUSTOMVERTEX
{
FLOAT x, y, z; // The untransformed, 3D position for the vertex

DWORD color; // The vertex color

};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)

FLOAT fHeightMap[33*33];

HRESULT InitD3D( HWND hWnd )
{
// Create the D3D object.

if( NULL == ( g_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) )
return E_FAIL;

// Get the current desktop display mode, so we can set up a back

// buffer of the same format

D3DDISPLAYMODE d3ddm;
if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
return E_FAIL;

// Set up the structure used to create the D3DDevice

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;

// Create the D3DDevice

if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}

// Turn off culling, so we see the front and back of the triangle

g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

// Turn off D3D lighting, since we are providing our own vertex colors

g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

g_pd3dDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);

return S_OK;
}




//-----------------------------------------------------------------------------

// Name: InitGeometry()

// Desc: Creates the scene geometry

//-----------------------------------------------------------------------------

HRESULT InitGeometry()
{
for(int i=0;i<33;i++)
for(int j=0;j<33;j++)
fHeightMap[i+(j*33)] = rand()/25000;

if(FAILED(g_pd3dDevice->CreateVertexBuffer(2178*sizeof(CUSTOMVERTEX),D3DUSAGE_WRITEONLY,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&g_pVB))) return E_FAIL;

CUSTOMVERTEX* pVertices;
if(FAILED(g_pVB->Lock(0,0,(BYTE**)&pVertices,0))) return E_FAIL;

DWORD dwBaseVertex = 0;
for(int z=0;z<32;z++)
{
for(int x=0;x<33;x++)
{
pVertices[dwBaseVertex+(x*2)+0].x = x*1.0;
pVertices[dwBaseVertex+(x*2)+0].z = (z+0)*1.0;
pVertices[dwBaseVertex+(x*2)+0].y = fHeightMap[x+((z+0)*33)];
pVertices[dwBaseVertex+(x*2)+0].color = 0xFFFFFFFF;

pVertices[dwBaseVertex+(x*2)+1].x = x*1.0;
pVertices[dwBaseVertex+(x*2)+1].z = (z+1)*1.0;
pVertices[dwBaseVertex+(x*2)+1].y = fHeightMap[z+((z+1)*33)];
pVertices[dwBaseVertex+(x*2)+1].color = 0xFFFFFFFF;
}
dwBaseVertex += 66; //Using 66 vertices per strip

}

/*for(int x=0;x<33;x++)
{
for(int y=0;y<33;y++)
{
pVertices[x+(y*33)].x = x*1.0;
pVertices[x+(y*33)].y = rand()/25000.0f;//RAND_MAX;
pVertices[x+(y*33)].z = y*1.0;
pVertices[x+(y*33)].color = 0xFFFFFFFF;
}
}*/

g_pVB->Unlock();

return S_OK;
}

VOID Cleanup()
{
if( g_pVB != NULL ) g_pVB->Release();
if( g_pd3dDevice != NULL ) g_pd3dDevice->Release();
if( g_pD3D != NULL ) g_pD3D->Release();
}

VOID SetupMatrices()
{
// For our world matrix, we will just rotate the object about the y-axis.

D3DXMATRIX matWorld;
//D3DXMATRIX matWorld_Trans;

//D3DXMATRIX matWorld_Rot;

D3DXMatrixTranslation(&matWorld,-16.0,0.0,-16.0);
//D3DXMatrixRotationY(&matWorld_Rot,timeGetTime()/500.0f);

//D3DXMatrixMultiply(&matWorld,&matWorld_Trans,&matWorld_Rot);


g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3((-sin(timeGetTime()/1000.0f))*30, 20.0f,(-cos(timeGetTime()/1000.0f))*30),
&D3DXVECTOR3(0.0f,0.0f,0.0f),
&D3DXVECTOR3(0.0f, 1.0f,0.0f));
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}

VOID Render()
{
// Clear the backbuffer to a black color

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

// Begin the scene

g_pd3dDevice->BeginScene();

// Setup the world, view, and projection matrices

SetupMatrices();

// Render the vertex buffer contents

g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
for(int i=0;i<32;i++) g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,i*66,64);//g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );


// End the scene

g_pd3dDevice->EndScene();

// Present the backbuffer contents to the display

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}

return DefWindowProc( hWnd, msg, wParam, lParam );
}

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
// Register the window class

WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"D3D Tutorial", NULL };
RegisterClassEx( &wc );

// Create the application's window

HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 03: Matrices",
WS_OVERLAPPEDWINDOW, 100, 100, 256, 256,
GetDesktopWindow(), NULL, (HINSTANCE)wc.hInstance, NULL );

// Initialize Direct3D

if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Create the scene geometry

if( SUCCEEDED( InitGeometry() ) )
{
// Show the window

ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );

// Enter the message loop

MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render();
}
}
}

// Clean up everything and exit the app

Cleanup();
UnregisterClass( "D3D Tutorial", (HINSTANCE)wc.hInstance );
return 0;
}


[edited by - AikonIV on March 22, 2003 6:26:17 PM]

Share this post


Link to post
Share on other sites