Drawing Big Tiled Map with Textured Quads

Hello Everybody,

I am Working on a 2D Game wich is using a Tile Based Map, The Ground is static, so it only needs to be set once.
My tiles are 32x32 Textures wich are stored in a TextureAtlas.
Until now i have been Rendering the Ground into an array of RenderTargets (64x64 Tile Chunks) at the beginning of the Game and then just rendering those chunks affected by the view Matrix.
This works fine, but put results in enormus amounts of RAM being used while running the Game, wich doesn’t look like a long Term solution for me.
After some reading i found that Textured Quads might be the solution to speeding up and streamlining the Process of Rendering the Ground. As I am still very new to using Quads (and basically anything concerning Shaders and Graphics) I have some Questions on how to Implement them:

  • would i be fine setting up an array of Quads for each Tile at the Start of the Game and then just Drawing those affected by the View Matrix (onto a RenderTarget for the Final Render) ?
  • or could I just Render the 64x64 Tile Chunks i had before onto Quads and discard of the RenderTargets afterwards?
  • Is there a Good source of Information on how to use Quads instead of static Sprites?
  • if i am using Quads, do i need to seperate my TextureAtlas into single Textures?

Sorry if this seems uninformed, i am just starting out with this Stuff.

Id do a search on the forums there are many posts about tilemaps and monogame extended has some built in stuff for it as well which is pretty popular.

SpriteBatch.Draw is itself drawing quads. A quad is only 2 triangles consisting of 4 points 2 of these points could considered to be shared between the two triangles.
If you consider each triangle to be its own set of 3 individual points instead. Then there are 6 total points 3 per triangle when triangles don’t consider themselves to be sharing vertices.

drawing a tile map … nkast has a well laid out solution link here as also lithium does, as well i have a basic example in the post.

drawing a quad, a pair of small examples that mimics what spritebatch does with a shader and manually created quads.

forum search.
http://community.monogame.net/search?q=tile%20map

.
.
.

Is there a Good source of Information on how to use Quads instead of static Sprites?

Yes.

There are many tutorials posts here examples and even what amounts to librarys which include things to make or just render tilemaps using monogame.

Sprites are image data drawn onto quads, which are then drawn to a backbuffer or onto a rendertarget, which will eventually be drawn to the back buffer anyways.

if i am using Quads, do i need to seperate my TextureAtlas into single Textures?

No …

In almost every scenario a tile or sprite sheet is better for performance and is preferable, if it is purely a choice.

You can assign a source rectangle to sprite batch draw call, or to the texture coordinates of a quad you create yourself which is a manual duplication of what spritebatch draw does. The source rectangle denotes the area on the image you get pixels from. The destination denotes were on screen these pixels are placed at.

would i be fine setting up an array of Quads for each Tile at the Start of the Game and then just Drawing those affected by the View Matrix (onto a RenderTarget for the Final Render) ?

provided i understand you to mean can you swap out sprites to a pre made map of quads.

Yes… But

That is probably less efficient and more complicated then most other things people would normally do who have some experience. See the links to the posts you should look at examples there are many fully made ones.

or could I just Render the 64x64 Tile Chunks i had before onto Quads and discard of the RenderTargets afterwards?

There are many possible ways to render a tile map look to the examples and forum posts.

Hi, may i ask why you don’t just draw with spritebatch directly on the screen buffer using your tile texture (in Atlas texture coordinates) as a source rectangle, and your screen tile position and size as rectangle destination?

Fast and simple. You can also bypass drawing empty tiles with simple checks.

Or do i miss something? :slight_smile:

Hi, may i ask why you don’t just draw with spritebatch directly on
the screen buffer using your tile texture (in Atlas texture coordinates)
as a source rectangle, and your screen tile position and size as
rectangle destination?

Fast and simple. You can also bypass drawing empty tiles with simple checks.

Or do i miss something?

If you are asking about the one i posted there… Answer is flexibility extensibility speed.

Spritebatch is normally great but in this specific case because of the way it works it’s actually going to be less efficient. You are basically recalculating everything visible each frame at the least when you really don’t need too.
In the version i posted the map is pooled with 9 dynamic alpha blended layers row batch drawn per frame.
I did that on purpose and most people won’t even need to do that much.
The only thing i want to calculate is what tiles not to draw. Each row is drawn out in a single draw call not each tile so it is like drawing a full row of tiles for the cost of 1 draw and simply not doing all the positional calculations.

Nkasts actually draws his entire map in one draw call and is a very good way to do it in most cases because it will be very fast.

So my example is a middle ground choice, for what i imagine is one of the most demanding tilemap scenarios a user could attempt. It’s maybe more flexable then other options to address even more demanding requirements were other faster methods can actually end up have more cons then pros.

Basically i picked a general middle ground algorithm that can be altered to do things no one asked how to do yet and is still fairly fast.

I questionably could have instanced it but i didn’t in that post.

No, that question was for the original poster Superschnizel, as he was creating an RT for each tiles, rather than just drawing them directly, just to “convert” textures from atlas to tile texture alone.

Now for your technique, it can be “ok” to “great” imo, depending on the project, but here you don’t resolve the RTs RAM problem at all, i think moving from chunks RTs to row RTs will lower it a bit but not remove it all together… or?

I see it like pre-optimizing, and it will add a layer of complexity to the engine that is not needed

Drawing directly tiles with a few visibility checks will not kill any perfs on modern hardwares, plus it will still allow you to animate tiles, thing you cannot do if you pre-allocate tiles on RTs before runtime (gameplay)… i used this simple method in my MG engine: Youtube video

Now once again, i’m not an expert at all, giving my 2 cents on the subject. :wink:

Good points. Cool game btw. I always use TextureAtlus(sprite-sheet) + source-rects & spritebatch.

Side-note: If you need to do 3D with spritebatch - you actually can if you know what you’re doing (can make some neat camera fx and mess with FOV) and even play with colored light & shadow across the surfaces.
I have had up to 32 layers of graphics with fx and thus reserve RT’s for specific post-shader trix, because I have an insane amount of animations (64M * 15 sheets) which need a lot of VRAM.

It’s possible to tag tiles too for span-jumping(using n+=jump;continue;) to reduce the number of loops and tests but I’d only worry about that if you have tons of tiles like I did. Takes a long time to edit levels when you’re assembling tiles on 14 of those layers. XD … In the future I’m gonna try to keep things simpler… I’d say the same tho - best to just draw with source-rects and do simple empty-tests until you encounter slow-down which doesn’t happen easily on most hardware.

As far as determining what’s in view - you’d just draw the span of tiles by index relative to map location. ie: top_left: tile[xmap-20, ymap-15] to tile[xmap+20, ymap+15] or something like that and then update the map location based on where the player’s center is (divide by the tile sizes to get the x&y index)

but here you don’t resolve the RTs RAM problem at all, i think moving
from chunks RTs to row RTs will lower it a bit but not remove it all
together… or?

Not sure what you mean by RTs and Ram problem, there were a couple parts to his question.

If by Ram you mean cpu side bottlenecking… That is heavily GPU side in that example there is no more then 150 draws for (15 rows and 9 layers which is like drawing the whole map 9x over). so im not sure what is meant by RAM problem. The entire map is static so cpu isn’t really used much here. Unless you want to change tiles in update like animate them ect which i didn’t do in that example but you could.

RenderTargets i don’t remember that being one of his problems but regardless you can set a render target before drawing that.

That version is also good for adapting parallax layers which he said he was doing, as well as alpha blending between them which he also said he was doing.
While i didn’t write a parallax layer into that example, he said he is doing it already. I figure he could fit it in from that on his own especially since each layer is drawn in separate.

The example i showed may not be the fastest for specific situations but it is probably the most flexible maybe it takes a closer look to appreciate just how flexible it is.
Anyways.
That example is runnable all the code is right there in game1, it’s general, it’s simple to understand…

From that point i would say if you needed to you could instance it. I mean i could have but um that is starting to get pretty specific.

Anyways like i said nkast’s solution is very good and you could just use that if you are most worried about optimal performance.

Oh i think i totally missunderstood Superschnizel main problem then.

Until now i have been Rendering the Ground into an array of RenderTargets (64x64 Tile Chunks) at the beginning of the Game and then just rendering those chunks affected by the view Matrix.
This works fine, but put results in enormus amounts of RAM being used while running the Game, wich doesn’t look like a long Term solution for me.

There i understood he just asked for a solution without RTs (RenderTargets) altogether, to remove the RTs allocated memory into the RAM. My bad then.