how use 3d hw for iso tile rendering?

Started by
12 comments, last by Simagery 18 years, 6 months ago
hi, i'm looking for an efficient way to render my isometric tile based game in direct3d. right now (with absolutely no optimization) i'm calling drawprimitiveup for each and every quad on the screen, which might be a little slow sometimes (especially when there are thousands or billions of quads being rendered). of course, culling has to be implemented. but more interesting is: should i group the quads by texture, pack them into one vertex buffer and then render them using the z-buffer (so no depth-ordering has to be done) ? how do i handle the different layers then? 'z-buffer-zones', like 0 .. 0.25 for tiles, 0.25 .. 0.5 for sprites etc.? what about transparent objects/sprites/tiles? or maybe it's ok to lock/unlock the vb for each quad? is that faster than drawprimitiveup? how do you guys do it? thanks, flix
ALL YOUR BASE ARE BELONG TO US
Advertisement
hi,

- you can't group by texture, because you must draw isometric map from top to down (no Z-buffering), and this is the way you got to do it, because Z-buffering slows down a whole rendering a lot. Maybe I'm wrong but this is the way I do.
- layering... programs render each layer in one call. f.e: first you draw background, second call: rendering objects, sprites on map..third call: render layer that is over that two... clouds, birds, and similar...I'm using just 1.0 for z...
transparent objects are loaded as textures with D3DXCreateTextureFromFile. you have one parameter wich defines transparent color in texture.
texture MUST be size of 2^n (32,64,128...) and rendered in quad with exactly texture width and height size (if texture is 32x32 then quad is also 32x32), because if you don't use that size, texture/object isn't going to be clear.
- and locking/unlocking is slower than drawprimitiveup, so stick yourself to drawprimitiveup command [smile].

I'm using a method above and it is fast as hell [smile]. Lot od layers, lot of objects, lot of enemies,and still have decent FPS.

alright, thank you very much.

your approach looks pretty much like my current implementation looks like. yesterday i had some minor speed problems mainly due to my unoptimized 'rendering pipeline', but it's pretty fast now.

flix
ALL YOUR BASE ARE BELONG TO US
To clear up some misconceptions

Quote:Original post by streamer
hi,

- you can't group by texture, because you must draw isometric map from top to down (no Z-buffering), and this is the way you got to do it, because Z-buffering slows down a whole rendering a lot. Maybe I'm wrong but this is the way I do.


I would wager that using z-buffering to mimic draw order and sorting by texture is far better, we use this method, and it was only by this method that our very image-heavy game did not slow to a crawl.

Quote:
- layering... programs render each layer in one call. f.e: first you draw background, second call: rendering objects, sprites on map..third call: render


You should implement a buffering scheme, wherin as you draw quads it bufferes them (and sorts them by texture and other propertie) and then renders them in batches on a single vertex buffer. Also keep in mind that images with true alpha translucency (not alpha test) must be rendered last and sorted properly back to front(no z-buffer)

Quote:
- and locking/unlocking is slower than drawprimitiveup, so stick yourself to drawprimitiveup command [smile].


While you should definetly keep locking and unlocking to a minimum, you should NEVER use drawprimitiveup unless it is absolutely neccisary, since you lose all the benefit of vertex buffers.

As mentioned above, for a 2D application a single vertex buffer that contains a couple thousand (see documentation for optimal buffer size) can be:

Locked
Filled with all of the quads you have buffered (which are sorted by texture)
Filled with all of the alpha-blend neccisary quads (which are sorted by texture, and then back to front)
Unlocked

then for each texture
setTexture
draw from one index in the buffer to the next (hopefully nice large batches)

this will reduce calls to DrawPrimitive and Texture switches, which are pretty expensive calls

during the buffering process if you run out of buffer space you can either grow the buffer to your known size, or you can fill the buffer, render out and then Lock it again (using the writeonly flag) and continue to fill it with data, as many times as needed.

be sure that the vertex buffer is Dynamic, so that lock and unlock calls incur as little overhead as possible.

also be sure to use the proper flags whenever you lock, they help to optimize it.

Raymond Jacobs, Owner - Ethereal Darkness Interactive
www.EDIGames.com - EDIGamesCompany - @EDIGames

Hm Edi may I argue with you a little bit? [smile]

In isometric style game with z-buffer turned off,there is no sorting to mimic z-buffer. you simply draw an array (or anything similar) that is in row.
And for vertex buffers... your method works only with indexed vertex buffers, but drawprimitive call works with vertex buffers that are not indexed
fe:
//your approach:m_pd3dDevice->SetTexture( 0, m_myTexture );m_pd3dDevice->SetFVF( MY_FVF );m_pd3dDevice->SetStreamSource( 0, m_myVB, 0, sizeof(VERTEX) );m_pd3dDevice->SetIndices( m_myIB );m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, numofvettices, 0, numofindices/3 );//my approach:m_pd3dDevice->SetStreamSource(0, m_myVB, sizeof(VERTEX));m_pd3dDevice->SetVertexShader(FVF_VERTEX);m_pd3dDevice->SetTexture(0, m_myTexture);m_pdDdevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
well, actually i don't see any hint to use an indexed vb in edi's post. currently, i have some buffering mechanism in my engine, sorting quads by depth.

alright then, background layers should be rendered with lowest z-values, let's say, 0..2. then, sprites are going to be rendered with far more depth precision (like 3..n+3, with n being the screen's vertical resolution, so one depth value for each row on the screen), and finally the 'sky'-elements are drawn, again depth-ordered in a higher range (n+4..infinity?).

the renderjobs are going to be packed in one single vertex buffer, grouped by texture, and rendered using one drawprimitive call per texture.

this approach means that the vertex buffer is going to be filled up *after* all renderjobs have been collected, to maintain the texture drawing order.

one question still remains, though: i have no control about what images my gfx artist procudes use alpha translucency. is there any way to find out?

flix
ALL YOUR BASE ARE BELONG TO US
What you mean that you have no control?
You can't determine which texture has alpha translucency?
or you don't know how to create textures with alpha chanel?
we have a custom loader, so all pixels must pass through our loader, we examine these pixels and the moment we see an intermediate alpha value (not 0 or 255) we mark the texture storage object as having intermediate alpha.

I am not sure what you are using, but perhaps a texture loader will return a proper texture based on the alpha format?

R8G8B8A8 R8G8B8X8 ?

Raymond Jacobs, Owner - Ethereal Darkness Interactive
www.EDIGames.com - EDIGamesCompany - @EDIGames

currently i'm using the d3dx library (d3dxloadtexturefromfile etc.), but i surely can switch to a custom loader, i just need to implement it. any idea where to find some code for that?

another idea is indeed to check the buffer format of the loaded texture, maybe d3dx detects alpha translucency, but i wouldn't rely on that...

well, i'll be seaching... see you later =)

flix
ALL YOUR BASE ARE BELONG TO US
Hello! I don't mean to be bumping an inactive thread but I've been grappling with a problem similar to the OP and I was hoping some of you more knowledgable guys might be able to help me out.

I currently have a buffering system set up similar to what EDI described to display all my 2D gui, text, etc items:

Solid items are sorted by texture and rendered through a dynamic vertex buffer. Depth sorting is handled by the Z-Buffer. Translucent items are stored in the order they're requested to be drawn in and not drawn until after the solid items have been handled. The Z-Buffer is turned off for this portion.

My problem arises when I need to have a solid item drawn on top of a translucent one. Because the translucent items are drawn last they are always on top, any solid items that need to be drawn on top of them appear below.

I'm hoping that it's something simple that I'm missing that will allow me to do this while still being able to maintain my batching by texture. Any thoughts?

This topic is closed to new replies.

Advertisement