Thread: Terrain generation (DX9)

  1. #1
    Registered User
    Join Date
    Aug 2003
    Posts
    288

    Terrain generation (DX9)

    heres the code i use to generate/draw terrain:

    Code:
    void Create_cVertex(cVertex *p_Vertex, float fX, float fY, float fZ, float fTU, float fTV)
    {
    	p_Vertex->x = fX;
    	p_Vertex->y = fY;
    	p_Vertex->z = fZ;
    	p_Vertex->tu = fTU;
    	p_Vertex->tv = fTV;
    	p_Vertex->color = D3DCOLOR_XRGB(255, 255, 255);
    }
    
    #define TILES_X 64
    #define TILES_Y 64
    
    // Globals:
    
    cVertex terrain[TILES_X * TILES_Y][4];
    IDirect3DTexture9 *texture; //already loaded elsewhere
    
    void GenerateTerrain()
    {
    	memset(&terrain, 0, sizeof(terrain));
    
    	unsigned int x, y;
    	float SIZEX = 0.5f, SIZEY = 0.5f;
    
    	srand(timeGetTime());
    
    	for (x = 0; x < TILES_X; ++x)
    	{
    		for (y = 0; y < TILES_Y; ++y)
    		{
    			Create_cVertex(&terrain[y + (x * TILES_Y)][0], SIZEX * y, rand() % 2, SIZEY - SIZEX, 0, 0);
    			Create_cVertex(&terrain[y + (x * TILES_Y)][1], SIZEX * y, rand() % 2, SIZEY, 1, 0);
    			Create_cVertex(&terrain[y + (x * TILES_Y)][2], SIZEX * (y + 1), rand() % 2, SIZEY - SIZEX, 0, 1);
    			Create_cVertex(&terrain[y + (x * TILES_Y)][3], SIZEX * (y + 1), rand() % 2, SIZEY, 1, 1);
    		}
    
    		SIZEY += 0.5f;
    	}
    }
    
    void DrawTerrain()
    {
    	unsigned int x, y;
    
    	for (x = 0; x < TILES_ROW; ++x)
    	{
    		for (y = 0; y < TILES_COLUMN; ++y)
    		{
    			g_Device->SetTexture(0, texture);
    			g_Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, terrain[y + (x * TILES_Y)], sizeof(cVertex));
    		}
    	}
    }
    That works fine for flat terrains, but when i added (rand() % 2) to the y value of each vertex, i get really messed up tiles (image attached).

    Also, ive been looking through a few sites, and ive noticed that this person did it differently, using only 3 vertices for each tile and his results seem fine, but its in OpenGL and he uses X and Z instead of X and Y.. Is his method better? and if so, how can i convert his code to work with DirectX.

    Thanks in advance.

  2. #2
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    I may be wrong , but say in a Tile 1, you set the vertices on the left side to a Y of 0, and on the right side (both top and bottom, they end up with Y = 1.

    So you're left with an inclined tile going up, to the right.

    Then, in the tile beside it (to the right), you set both Y values (on the left side of the tile) to 0 (Well, Rand() decided it so)...then, wouldn't you be left with a gap between the right side of Tile 1 and left side of Tile 2?

    Perhaps I missed something, but that seems like a potential problem. I think you'd have to (once all tiles have Y values) compare adjacent tiles and average out the Y-Values of overlapping vertices to get a smoother terrain. I don't know why this would be producing triangles though...What are your Location/LookAt vectors for your camera?
    Last edited by Epo; 04-13-2005 at 06:18 AM. Reason: I have my reasons
    Pentium 4 - 2.0GHz, 512MB RAM
    NVIDIA GeForce4 MX 440
    WinXP
    Visual Studio .Net 2003
    DX9 October 2004 Update (R.I.P. VC++ 6.0 Compatability)

  3. #3
    Registered User
    Join Date
    Aug 2003
    Posts
    288
    Code:
    void UpdateView()
    {
      D3DXMATRIX matIdentity, matView, matProjection;
    
      D3DXVECTOR3 vLookatPt(User.x, User.y, User.z);
      D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
      D3DXVECTOR3 vEyePt(User.x, Camera.y, User.z + Camera.z);
      
      D3DXMatrixIdentity(&matIdentity);
      D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
      D3DXMatrixPerspectiveFovLH(&matProjection, D3DXToRadian(60), (float)g_DisplayMode.Width / (float)g_DisplayMode.Height, 1.0f, 50000.0f);
    
      g_Device->SetTransform(D3DTS_PROJECTION, &matProjection);
      g_Device->SetTransform(D3DTS_WORLD, &matIdentity);
      g_Device->SetTransform(D3DTS_VIEW, &matView);
    }
    user.* is just a struct i use to move around the terrain
    camera.y = 5.0f; (so its looking down on the terrain)
    camera.z = -3.0f; (so its a 3rd person camera, ie. its 3 units behind user.z)

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You are creating several disjoint triangles. Remember that in a grid, any one triangle will have a certain number of neighbors. So if you don't use an index buffer you will be re-creating several vertices twice.

    Render that scene in wireframe mode and you will see that you don't have a grid at all. Practice creating a grid from -x,-z to +x,+z and set y to 0.0f. You should have a perfect grid squares and 2 tri's within each square or quad. Now displace the y value a bit and don't touch the x and z values. This should produce what you want. Render the scene as a triangle list first and then try to produce as many strips as possible. Notice that at max x,z you could move to max x,z+cellsize and only set two vertices to create your quad as a triangle strip.

    It is better, however, to load the height values from a map. Notice that x and z do not change in the grid and they increment by constants. The only thing that really changes with simple terrains is the height or y value. So it makes sense that you could create a greyscale image and load the data into memory. To displace the y component of the vertex, check the map at (x/cellsize),(z/cellsize), scale the value to fit your needs and set that vertices y component and/or set it's texture ID and texture coords. Now render and extract the texture ID from each vertex. If the texture ID does not match the current one, switch to the vertex texture ID, set current texture ID to it's ID and render - you should have some very good looking tiled and textured terrain. If you would like to smooth it notice that any smoothing function that can be done on an array can be done on your terrain since it is really just an array of Y values. The possibilities are endless. Another thing to do is add light. Here are the computations for simple pre-computed per-vertex dot3 lighting in Direct3D for any one triangle. The normal for a vertex here is assumed to be the normal of the plane created by the vertices. You could do normal averaging and get much better results. Notice in a triangle list every 6 vertices is 1 quad or 2 triangles.

    Code:
    for (int i=0;i<m_iNumVertices;i++)
    {
    
      //Vector to light source
      D3DXVECTOR3 ToLight=Vertices[i].Pos-Light.Pos;
      
      //Find normal of plane formed by this triangle
      D3DXVECTOR3 V1=Vertices[i].Pos-Vertices[i+1].Pos;
      D3DXVECTOR3 V2=Vertices[i].Pos-Vertices[i+2].Pos;
      D3DXVec3Normalize(&V1,&V1);
      D3DXVec3Normalize(&V2,&V2);
      D3DXVec3Cross(&Vertices[i].Normal,&V1,&V2);
        
      //Normalize vector to light source
      D3DXVec3Normalize(&ToLight,&ToLight);
    
      //Set dot3 value of this vertex
      //Always satisfies 0<dot3<1.0f
      Vertices[i].PreComputedDot=MAX(D3DXVec3Dot(&ToLight,&Vertices[i].Normal),0.0f);
    }
    Not every vertex needs a normal - just every 7th one because when we compute the normal we are using 3 vertices that make up the tri and setting the first vertex normal to that value. So if we always look at the ith vertex normal - the next 5 will be the same value.
    Last edited by VirtualAce; 04-13-2005 at 07:21 AM.

  5. #5
    Registered User
    Join Date
    Aug 2003
    Posts
    288
    what do you mean by not having a grid? heres a screenshot in wireframe mode, it seems to have a grid..

  6. #6
    Registered User
    Join Date
    Aug 2003
    Posts
    288
    btw, about the lightmap, i was going to add that once i figured out how i could fix this problem, because the only way i know atm, is to edit 4 different vertices for 1 point on the terrain to .. elevate, im guessing this is because i use 4 vertices per square, and no index buffer. Is there a better way? like maybe sharing the vertices from the previous tile, and so on, that might work out better

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I would share the vertices. It is more efficient not to, but it adds flexibility to the system if you do - at the small cost of memory which by today's standards isn't even a consideration.

    There is no way that is the same image as the top one, just in wireframe mode. The first one is a huge mess of oddly placed triangles. If you perturb the y values of the vertices in the second picture - you should get a terrain.

  8. #8
    Registered User
    Join Date
    Aug 2003
    Posts
    288
    but thats exactly, what i do, i just edit the y values of the tiles in the picture. but since the vertices arent shared, only 1 vertex from the tile changes, and it 'seperates' from the other tiles around it. how would i actually go about sharing the vertices? ive never done it before, except for 2 triangles (quad).

    image of triangles with modified y values
    Last edited by X PaYnE X; 04-13-2005 at 07:36 AM.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Iterate through the array and change the y values. If you are using an array, they should all be shared.

    Triangle 1 - 0,1,2
    Triangle 2 - 1,3,2

    01
    23

    1 Quad.

    So your grid will look like this:
    0145
    2367

    or something close to it.

  10. #10
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    If you have all your vertices in an array indexed 0 to n-1, then create an array of render indices that specify the drawing order for your mesh. for example
    Code:
    say your 2D array is represented as a 1D array like the element indices below:
    1 2 3 
    4 5 6
    7 8 9
    
    ex. array vaules (heights):
    heights = {
    23 45 60
    32 35 63
    63 53 55
    }
    
    now create an array which specifies the rendering order.. for triangle strips it could be as follows.
    renderIndices = { 1 4 2 5 3 6 9 5 8 4 7 }

  11. #11
    Registered User
    Join Date
    Aug 2003
    Posts
    288
    image #1 has vertices going from v1 to v4 on the first line
    image #2 has vertices going from v1 to v14 on the first line

    i just googled a bit more and found an article with image #1, as you can see, he defined the first row up to v9. in image #2 (my method), i defined the first row up to v15, because i use 2 vertices for 1 point most of the time.

    my question is, if i defined it like in image #1, up to v9, how would i render it? the creation is easy, the rendering part i dont understand, since the first triangle is v0 - v1 - v5 instead of v0 - v1 - v2.

  12. #12
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    >>my question is, if i defined it like in image #1, up to v9, how would i render it?

    just like i explained above if you want one continuous triangle strip. Maybe it would be easier for you to start with rendering individual rows of triangle strips.

    looky...
    Code:
    for (int i = 0; i < height - 1; i++) {
      beginTriangleStrip
      for (int j = 0; j < width; j++) {
        render vertex i * width + j
        render vertex (i + 1) * width + j
      }
      endTriangleStrip
    }
    so, from your image above... it would render v0, v5, v1, v6, v2, v7 etc....
    what Bubba and i are suggesting is to pre-calculate these render indices and store them in an array. This makes using vertex arrays (or whatever DX calls it) easy and rendering faster.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. My terrain Generation function's fubar.
    By indigo0086 in forum Game Programming
    Replies: 12
    Last Post: 06-22-2007, 09:57 AM
  2. Continous LOD Terrain Source... Released!
    By Perspective in forum Game Programming
    Replies: 13
    Last Post: 04-17-2006, 11:21 PM
  3. New terrain engine
    By VirtualAce in forum Game Programming
    Replies: 16
    Last Post: 03-16-2006, 02:47 AM
  4. Replies: 5
    Last Post: 02-25-2005, 04:48 PM
  5. Terrain algos
    By VirtualAce in forum Game Programming
    Replies: 1
    Last Post: 04-10-2004, 02:50 PM