Skip to main content
gamedev.net
🔒 Locked

Help figure out the algorithm

Started by itz_faraz 9 replies 1.6k views
Original Post
itz_faraz
itz_faraz
Hello I have been having this problem for quite some time now, I had given up some time back but now I've picked up the problem again, and again I'm scratching my head, so hear me out. I'll try to state the problem as simple as possible: First of all, I'm not experienced when it comes to game development. I haven't been able to create a decent 3D engine without running into performance problems and scraping the whole project in the end. I'm working on: VB6 DirectX 8.1 Pentium III 700 MHz, 128 MB RAM GeForce4 64 MB What I'm creating: I'm trying to create a city building game. The game will consist of a terrain capable of having mountains/valleys, etc. The terrain is built completely in 3D with an orthographic camera view. Its supposed to be somewhat similar to SimCity. I create the terrain from a BMP height map file, which (in this prototype version) creates 84x68 tiles. I'm using only one terrain texture, i.e. I haven't coded for multiple terrain levels yet. A small screenshot of the current development: Terrain is built on XZ plane with Y for height. Ignore the grid lines and lighting for now. It is an orthographic view with camera set at (16, 34, -40) which creates the isometric 'diamond' tile look-alike view. Zooming and scrolling is done by moving the camera, no changes done to the vertices/terrain when zoomed in/out or scrolled. Problem #1: In short, poor performance! And poorly coded as well with severe limitations. What's wrong: I read the map BMP file and create untransformed but lit vertices and combine all of them into one big vertex buffer and index buffer. So in order to draw the terrain, the whole VB is punched through causing to render even the areas not visible. I read about Quadtrees, BSP, ROAM, etc. I could understand what they are trying to tell but cant figure out how to implement it here in my project. The New Version: I adapted the quadtree approach just a bit. Now I create four vertex buffers instead of one. (its all hard-coded right now). And then using ray-picking technique, I check if any of the corners of the VB is currently visible, and if it is so I render it. I 'think' this is what quadtree approach is. But that is a very big problem. You see if the terrain is zoomed in on, for eg, the north-east vertex buffer, none of the corners will be visible but still it has to be drawn but with my approach it wont be drawn. Next problem is that even if I make it draw, what if in the south-east VB portion there is a big mountain that should be visible even if the north-east part is zoomed in. Same thing, none of the corners of the SE portion are visible but the mountain within it is supposed to be visible. So how do I code? Should I go for quadtrees or is there a different approach to solve this matter. Is one vertex buffer enough or ... how should it all be coded? Problem #2: The goal is not only to build a terrain that is rendered efficiently, but also to be able to detect which tile (set of 2 triangles) is the mouse currently over. I do this by enumerating each tile from north-west to south-east through ray-picking technique until I determine within which tile the mouse is currently over: This poor method of mine works on a very small terrain as above, but on a normal size terrain, one can imagine that if a tile is near to north-west, it will be determined (calculated) very quickly. But if the mouse is on the lower areas of the terrain, it takes awful lot of time to calculate, because enumerating in each frame till mouse is detected and mouse is on the last tiles in the enumeration list, so takes a while. I particularly have no idea how to solve this matter. Another problem in this coding of mine is that if enumerating from north-west to south-east, if a mouse is over a high mountain, my code wont detect the mouse being on the mountain but will detect the tile which falls behind the mountain. And the way I show the 'white selection' on the terrain is that I create another tile with a texture having white border and transparent within and place that tile on the tile clicked/hovered. Future Expected Problems: 1. I will be adding buildings, roads, etc stuff. In my current project, the game runs at steady 55 FPS but by adding each house (which is a very primitive house, very few polygons and 2 small textures) the frame rate drops sharply. When it comes to add the 5th house, the FPS is somewhere around 25. So creating a metropolis seems impossible at the moment. 2. When adding roads, I create another tile over the tile which is clicked. This new tile holds the road texture. I think a better approach would be to not to create the a new tile but to replace the texture of the tile clicked by the road's texture. Now, since the terrain is in a vertex buffer, how do I create the terrain with the grass texture and set the road texture for a particular tile? I tried creating the whole terrain once, then redrawing the tile on which road is created, with the road texture. But thats overdrawing! Conclusion: I need guidelines! How to overcome this poor coding?! [headshake] [help] [Edited by - itz_faraz on October 18, 2005 10:49:24 AM]
Faraz Azhar-Intel 700mhz128 MB RAMnVidia GeForce4 MX440Using DirectX 8.1 SDK, VB6
dbzprogrammer
dbzprogrammer
Well, problem number 1 is that your coding it in VB6 IMO. But you can if you want to. It is quite limited in this field of technology, due to the fact that algorithims have a wider range of possible ways of implementations.
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"
itz_faraz
itz_faraz
I dont supose that VB6 could cause a huge downfall in performance. Can it? It is not a VB6 problem.. my basic problem is that how do I implement quadtree technique in a 3D environment with the camera rotated to cause the terrain look like isometric diamonds? Can quadtree be implemented here?
Faraz Azhar-Intel 700mhz128 MB RAMnVidia GeForce4 MX440Using DirectX 8.1 SDK, VB6
Wyrframe
Wyrframe
Well, I see those "rotate" buttons and my usual first optimization goes right out the window. That is (and this fixes your mountain too) quadtree-ify the entire map in screenspace, instead of world space. Then, even that tall mountain still qualifies as being in your "NE", because it visually obscures the NE area.

Disregarding the above change, for the size of the map you're hinting at I'd advise three to five levels of quadtree instead of just one. This also means making a more abstract and more powerful quadtree system, but that's a good thing. Gets your feet wet.

For finding the tile your cursor is over; that quadtree will help massively. Start by testing hits with the outermost quadtree. If there's a hit, test hits for the part of the child quadtree that was hit. If there's a hit, test hits for the part of the child quadtree that was hit... until you get to a leaf node (where the terrain vertex buffers are), and then iterate over the terrain doing your picking. Scan from the edge nearest the camera, going away, so that you always get the nearest terrain slice.

Buildings; each building design (not each individual building) ought to be a vertex buffer of its own. I recommend you switch to a single texture per building, and just get clever with your texture UVs. I assume you've got a ZBuffer going; draw the terrain, then draw all the buildings that are in the visible areas (remember that quadtree? damned useful thing, that) sorted by same-kinds; that'll minimize texture switches and reduce pipeline usage (you don't change textures after every building, and you don't send one building's data, send another building's data, and then send the first one again).

That ought to hold you off for a while. Good luck!
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
itz_faraz
itz_faraz
OK Im relieved that you have understood the problem. But I have not clearly understood the solution you provided. What do you mean by:

"That is (and this fixes your mountain too) quadtree-ify the entire map in screenspace, instead of world space."

Can you elaborate on that please? I have no idea what you are talking about.
Faraz Azhar-Intel 700mhz128 MB RAMnVidia GeForce4 MX440Using DirectX 8.1 SDK, VB6
Wyrframe
Wyrframe
Well, on the assumption you have a fixed viewing angle, all your vertices are pre-transformed, pre-lit. So you know where they will end up on-screen, right?

So instead of dropping them into vertex buffers sorted their world position, drop them into the buffers sorted by their final on-screen position, after transformation from world coordinates (XYZ) to screen coordinates (XY).

That help?
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
itz_faraz
itz_faraz
Pre-transformed? I use my custom 'D3DVERTEX2LIT' data structure for storing vertices of the terrain. Thats untransformed but lit vertices.

(Did I mention TL vertices earlier? [embarrass] Im sorry I dont know why I said that.. [rolleyes])

So I dont think that technique would work. I have to use ray-pick technique just because that I am not using pre-transformed. Pre-transformed would have made things quite lot easier.
Faraz Azhar-Intel 700mhz128 MB RAMnVidia GeForce4 MX440Using DirectX 8.1 SDK, VB6
fearyourself
fearyourself
Can't you just combine the drawing of the tiles with the raytrace?

Go through your array and for each tile:

Draw it and check for mouse positionning...

itz_faraz
itz_faraz
I didnt completely understand what you suggested.. here's my reply anyway..

The thing is that currently Im drawing the whole terrain through one big vertex buffer i.e. the whole terrain is drawn at once, whether or not any portion of it is visible on the screen. So I cant test each tile 'while drawing' for mouse position.

So currently my code does is that it draws the whole terrain, and then it tests each tile for mouse position.. which is a VERY SLOW PROCESS! It brings the FPS from 40-50 to 3-5.

Therefore I think the method you suggested would cause the same effect, if I were to break the vertex buffer and draw each tile separately and raytrace it at the same time.
Faraz Azhar-Intel 700mhz128 MB RAMnVidia GeForce4 MX440Using DirectX 8.1 SDK, VB6
dimebolt
dimebolt
IMO, problem #1 and #2 are the same. You need a proper quad-tree representation. Your mistake was to go for 2 dimensional planes to represent the quads, whereas your terrain obviously is 3D. A solution to this is this:
- calculate the (3D) bounding box of the scene
- recursively cut this bbx into a 2x2 grid of smaller bbxes until you reach the point that each tile has its own box (or until a certain threshold is reached if you think that a full subdivision is overkill, but I would rather build the full tree and threshold the algorithms using it).

Use this data-structure to:
- perform recursive frustum culling, by first checking if the highest level boxes are contained in the frustm and then descending down until you reach a certain level. If a bbx at that level is in, draw the vertex array for that bbx. Note that you don't want to descend all the way down for this, as that will make your vertex arrays too small, which eliminates the benefit of frustum culling.
- perform recursive ray-picking, by first checking which of the highest level boxes intersect with the ray, and then recursively descending into those bbxes that intersect. If you do this to the deepest level (of individual tiles) you will end up with a list of candidate tiles. For these candidates, you can check if the ray intersects with their actual vertex data.

Tom

[Edited by - dimebolt on October 21, 2005 6:56:49 AM]
itz_faraz
itz_faraz
hmm.. seems a lot complex.. ill try to figure out a basic algorithm...
Faraz Azhar-Intel 700mhz128 MB RAMnVidia GeForce4 MX440Using DirectX 8.1 SDK, VB6

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.