Lots of surfaces on a mesh..
Blitz3D Forums/Blitz3D Beginners Area/Lots of surfaces on a mesh..
| ||
I was studying the 3D makeup of Warcraft 3 maps, and it's fairly simple.. standard map size, is a 64x64 grid mesh, containing two polygons per grid square, or 8192 odd triangles. Now this hits me as strange first of all, as thats a lotta triangles to be drawing, but War3 DOES limit on-screen viewing (even in the map editor) up to a maximum of about a 30x30 viewing size (approx 1800 polys - still allowing plenty for character/scenery models, etc). However, every square of that can contain a separate texture. Questions: 1. How can this kind of density be achieved in Blitz? Is using 4096 surfaces (one per square) on a mesh realistic? It doesn't sound it. 2. How much will this affect performance considering that only 900 of these surfaces are on-screen at a time? 3. Would splitting up the terrain into say, 64 meshes of 8x8 grid squares each (128 polys, 64 surfaces) be a more likely way to achieve a similar result? Would it save on processing power? 4. Another alternative - creating a massive image in memory and assigning the single image as the texture and dynamically changing/reassigning the texture to "emulate" an effect of each square having a different texture - possibility or insanity? I'm still trying to get my head around some of this 3D stuff. I mean, playing with sprites having a few hundred on-screen seriously hampers performance, so surely having a few-hundred surfaces on-screen is gonna cause an even bigger performance hit. Any ideas/experience appreciated. :) +BlackD PS. Sorry for asking questions I know I could answer by playing around in Blitz for a while, but I'm not that good in 3D and it'd take me days of coding to find answers some folk here probably already know. :) |
| ||
Sprites can be slow when they use alpha transparency. When the card has to handle a lot alphaed sprites that are filling most of the screen, it can become real slow, esp. when the camera looks trough a lot of layers of sprites. It is true, a high number of seperate surfaces can also slow things down. If I was you, I would combine both: use a number of 1024*1024 texel textures and each of them contains eg: 4*4 textures. So you would have 16 times less surfaces in use. BTW on some cards 1024*1024 is the max anyway. so you couldn't use eg. a 10'000^2texels texture. |
| ||
Well, after much extended experimentation, I found option #3 works the best. Using option #1, 4096 separate surfaces on a single mesh, it ground the engine down to about 12fps, on an nVidia 5900 Ultra. Option 2 isn't really an option. Option #3 - Create 256 meshes, each with 16 surfaces. This worked very well, and would be how I imagine programs like ALE work to make up large landscapes. I could fit quite a large number of these meshes onto screen and still max out the FPS. Even 512 meshes (a 128X64 map) worked without speed impedence, with 8192 surfaces. An interesting thing I found though - while moving around this terrain while zoomed in, it would be very jaggy while moving over "new" areas, then once they were viewed, this movement would be smooth and fast. I attributed this to allocating chunks to video memory, and confirmed it by zooming my camera out to view the whole scene, doing an update and render without a flip, then zooming in to the correct level and re updating/rendering/flipping in the main loop - at which stage because it had all been "viewed" in the non-flipped render, it was now all fast and smooth. What is the cause of this? Does Blitz not load objects into video memory when they are created, only when they are first viewed on-screen? |
| ||
When I first started to code a 3d puzzle game I am working on I had a similar problem to yours, I needed a grid like playing area that could potentially contain hundreds of different textured tiles, the soloution I came up with was to use AddMesh to merge the play area into one mesh. This could be used to create warcraft 3 style tiling textures that you see on the ground. Using addmesh is pretty fast. Here is an example I knocked up at work, all from memory but it seems to work ok :) Graphics3D 800,600,0,2 ;################################################################## ; Change Test from 1 to 2 ;################################################################## ; 1 = Lots of individual entities making up the 'grid' (Slow) ; 2 = One big mesh created with addmesh (Fast) ;################################################################## Const Test = 1 ; Change Width and Height, the bigger the more 'grid' the play area has, you will really see a difference in speed when you try 50 or so with Test 1 (slow :) Const Width = 30 Const Height = 30 Dim GRID(WIDTH,HEIGHT) For Y = 0 To HEIGHT For X = 0 To WIDTH GRID(X,Y)= Rand(0,4) Next ; X Next ; Y ; CAMERA TYPE Global MVX#,MVY#,MVZ# Global OMX,OMY Global Mesh Global Cube0,Cube1,Cube2,Cube3,Cube4 Global Brush0,Brush1,Brush2,Brush3,Brush4 Type Camera_Type Field Mesh Field DummyMesh End Type ;------------------------- ; Set up the Camera ;------------------------- Global Camera.Camera_Type = New Camera_Type Camera\DummyMesh = CreatePivot() Camera\Mesh = CreateCamera(Camera\DummyMesh) CameraRange Camera\Mesh,0.1,1000 PositionEntity Camera\DummyMesh,Width ,Height,28 RotateEntity Camera\Mesh,0,180,0 Global TileTexture = CreateTexture(32,32,1,5) SetBuffer TextureBuffer(TileTexture,0) : Color 255,0,0 : Rect 0,0,32,32 SetBuffer TextureBuffer(TileTexture,1) : Color 0,255,0 : Rect 0,0,32,32 SetBuffer TextureBuffer(TileTexture,2) : Color 0,0,255 : Rect 0,0,32,32 SetBuffer TextureBuffer(TileTexture,3) : Color 255,255,0 : Rect 0,0,32,32 SetBuffer TextureBuffer(TileTexture,4) : Color 255,0,255 : Rect 0,0,32,32 SetBuffer BackBuffer() L=CreateLight(2) PositionEntity l,150,50,150 ; #################################################################### Cube0=CreateCube() Cube1=CreateCube() Cube2=CreateCube() Cube3=CreateCube() Cube4=CreateCube() BRUSH0 = CreateBrush() : BrushTexture BRUSH0,TileTexture,0 BRUSH1 = CreateBrush() : BrushTexture BRUSH1,TileTexture,1 BRUSH2 = CreateBrush() : BrushTexture BRUSH2,TileTexture,2 BRUSH3 = CreateBrush() : BrushTexture BRUSH3,TileTexture,3 BRUSH4 = CreateBrush() : BrushTexture BRUSH4,TileTexture,4 PaintMesh CUBE0,BRUSH0 PaintMesh CUBE1,BRUSH1 PaintMesh CUBE2,BRUSH2 PaintMesh CUBE3,BRUSH3 PaintMesh CUBE4,BRUSH4 ; ##################################################################################### ; Try Method 1 or Method 2 to Compare Speed ; ; If Test = 1 Method1() ; Each Cube is a completely seperate entity which is individually textured If Test = 2 Method2() ; Each Cube is merged into the overall mesh, so only 1 mesh is created ; ##################################################################################### Repeat If KeyDown(200) TranslateEntity Camera\DummyMesh,0,0,-0.3 If KeyDown(208) TranslateEntity Camera\DummyMesh,0,0,0.3 If KeyDown(203) TranslateEntity Camera\DummyMesh,0.3,0,0 If KeyDown(205) TranslateEntity Camera\DummyMesh,-0.3,0,0 UpdateWorld() RenderWorld() VWait Flip False Until KeyHit(1) Function Method2() Mesh = CreateMesh() For Y = 0 To HEIGHT For X = 0 To WIDTH CUBE = 0 Select GRID(X,Y) Case 0 cube = CopyMesh(CUBE0) PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 Case 1 cube = CopyMesh(CUBE1) PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 Case 2 cube = CopyMesh(CUBE2) PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 Case 3 cube = CopyMesh(CUBE3) PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 Case 4 cube = CopyMesh(CUBE4) PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 Case 99 Goto SKIP End Select AddMesh Cube,Mesh FreeEntity Cube .SKIP Next ; X Next ; Y End Function Function Method1() For Y = 0 To HEIGHT For X = 0 To WIDTH Select GRID(X,Y) Case 0 cube = CreateCube() PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 EntityTexture Cube,TileTexture,0 Case 1 cube = CreateCube() PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 EntityTexture Cube,TileTexture,1 Case 2 cube = CreateCube() PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 EntityTexture Cube,TileTexture,2 Case 3 cube = CreateCube() PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 EntityTexture Cube,TileTexture,3 Case 4 cube = CreateCube() PositionMesh cube,X*2,Y*2,0 ; * 2 because a cube = 2x2x2 EntityTexture Cube,TileTexture,4 End Select Next ; X Next ; Y End Function |
| ||
Thanks heaps for that, I really appreciate your time. :) I've been working on this a bit since I asked the question, and I've come up with this so far: (needs to be extracted) http://www.geocities.com/kinneargames/war3.zip Very early stages, completely unoptomized code. Arrow keys move around, ESC quits (takes a few secs to quit though as I have a very thoughrough "free"ing routine). On my machine at least, that runs very fast/smooth. 4096 individual surfaces, spread over 256 meshes, 16 per mesh, ie - a 64x64 map grid. Although increasing it to 128x64 and 128x128 results in no performance loss. I haven't included a toggle to do so - as i said, the code is unoptomized so at the moment changing the map size means a bunch of hard-coding. :) Feedback on its performance elsewhere is appreciated. +BlackD |
| ||
Cool At work the PC I am using is really bad, has a built in VIA / S3 oboard 3d card, your demo runs at 38fps, I will try when I get home soon and I guarentee it will run a lot faster :) The warcraft 3 map editor is really powerfull, I would love to create something that is as powerfull and intuative as that for creating terrain style maps. |
| ||
I don't think 8192 polys will kill many cards - my Gforce 2 could easily cope with that. Reckon a good bet is single surface full of squares and use texture coords to select the right part of the texture |
| ||
falken, its not the polys i'm concerned about, its the number of surfaces (individual textures in the mesh). |