Java-Gaming.org Java4K winners: [ by our judges | by the community ]         
Featured games (67)
games approved by the League of Dukes
Games in Showcase (∞)
games submitted by our members



News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  Print  
  Rendering tiles fast (isometric too)  (Read 2524 times)
0 Members and 1 Guest are viewing this topic.
Offline theagentd

JGO Wizard
****

Posts: 1392
Medals: 88



« on: 2011-12-14 07:12:53 »

In a recent thread I mentioned/came up with a method of drawing tiles without needing a quad for each tile to avoid a vertex bottleneck by using a fragment shader. I've implemented it.


The whole map in this test program is 2048x2048 tiles, and they are all drawn as a single quad (no culling on the CPU). Zooming out so that all tiles are visible, FPS drops to around 450-500 as the texture cache won't be able to do its magic. However, in that case tiles are smaller than screen pixels, and the whole map just looks like randomly colored pixels.

The renderer is not limited to pure 2D rendering in any way. It's possible to just rotate and scale the rendered quad to achieve lots of effects. For example, isometric tiles:


It uses an RGB texture to keep tile indices per tile and a 2D texture array for tiles to prevent bleeding between tiles when linear filtering is used. The most important part is the fragment shader:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
#extension GL_EXT_texture_array : enable

uniform vec2 mapSize;

uniform sampler2D tileTexture;
uniform sampler2DArray tilesetTexture;

void main()
{
   vec2 texCoords = gl_TexCoord[0].st;
   vec2 tileResult = texture2D(tileTexture, texCoords / mapSize).rg;
   float tile = dot(tileResult, vec2(65535, 256.0));
   gl_FragColor = texture2DArray(tilesetTexture, vec3(fract(texCoords), tile));
}

which calculates the tile from 2 color channels and then looks up the tile in the texture array. This could be implemented in OpenGL 2 too by using a pure tile set, but it would have severe bleeding between bordering tiles when using filtering. However, mipmaps do not work as they produce weird 2 pixel seams between tiles for me.

Here is the Java and GLSL shader source, plus a test tileset: http://www.mediafire.com/?flc36t8uq6floaw You need the LWJGL jars in the classpath and the natives directory in the VM commands. It also needs OpenGL 3 to run, but it is possible to work around this.

I hope someone finds it useful!

There is no god.
Offline sproingie

JGO Strike Force
***

Posts: 899
Medals: 55



« Reply #1 on: 2011-12-14 13:04:32 »

VERY nice  Cool

libtcod's shader renderer uses this trick too, though your code is a lot easier to follow.  The libtcod code uses some nasty tricks to deal with correcting for NPOT map dimensions, whereas I think just starting with a POT texture in the first place is a better idea (I guess it might get a bit more expensive if you had a 257x257 map, but eh, edge case).

For a true isometric view you really need a custom tileset designed for it, but it's still nice to be able to pull off arbitrary scaling.
Offline BoBear2681

Full Member
**

Posts: 238
Medals: 8



« Reply #2 on: 2011-12-14 14:09:07 »

<OT>
That tileset looks familiar, but I can't place what game it's from.  Care to enlighten me?
</OT>
Games published by our own members! Go get 'em!
Offline h3ckboy

JGO Kernel
*****

Posts: 1645
Medals: 4



« Reply #3 on: 2011-12-14 14:14:07 »

haha, to me it seems like Heroes of might and magic, but I strongly doubt that is it
Offline aazimon

Full Member
**

Posts: 208
Medals: 5



« Reply #4 on: 2011-12-14 14:24:59 »

Cool.
The tile set might be Final Fantasy. I see a little tent icon from the game.
Offline theagentd

JGO Wizard
****

Posts: 1392
Medals: 88



« Reply #5 on: 2011-12-14 14:36:43 »

Hahaha, the tileset is from Chrono Trigger. You can see parts of a few houses from the starting town.

VERY nice  Cool

libtcod's shader renderer uses this trick too, though your code is a lot easier to follow.  The libtcod code uses some nasty tricks to deal with correcting for NPOT map dimensions, whereas I think just starting with a POT texture in the first place is a better idea (I guess it might get a bit more expensive if you had a 257x257 map, but eh, edge case).

For a true isometric view you really need a custom tileset designed for it, but it's still nice to be able to pull off arbitrary scaling.

I'm sure you can modify the texture loader and fragment shader to sample from a special isometric tile texture. =D

EDIT: Why would NPOT map dimensions be a problem? Textures have supported non-power of 2 textures since a long time ago.

There is no god.
Offline R.D.

Full Member
**

Posts: 122
Medals: 2


"For the last time, Hats ARE Awesome"


« Reply #6 on: 2011-12-14 16:43:08 »

Nice! Will implement it as option in my next game for sure if I can use it as expected Cheesy For my current project I just don't have the time Shocked

I would like to see a test where I have a map and walk trough it with a camera or something!

Edit:
Argh, forget it, just saw that I can move around and such xD

Offline sproingie

JGO Strike Force
***

Posts: 899
Medals: 55



« Reply #7 on: 2011-12-14 20:36:32 »

NPOT textures are indeed supported, but operations on them can be considerably slower.  Maybe the libtcod guys were coding for nvidia 5xxx cards which claimed to implement GL2.0 but didn't support NPOT textures, I dunno.  At any rate, nothing that anyone need concern oneself over when already requiring GL 3.0.


Offline theagentd

JGO Wizard
****

Posts: 1392
Medals: 88



« Reply #8 on: 2011-12-15 04:38:53 »

NPOT textures are indeed supported, but operations on them can be considerably slower.  Maybe the libtcod guys were coding for nvidia 5xxx cards which claimed to implement GL2.0 but didn't support NPOT textures, I dunno.  At any rate, nothing that anyone need concern oneself over when already requiring GL 3.0.
The only thing that actually requires GL3.0 is texture arrays. I was thinking of using them to prevent bleeding between tiles, especially when using mipmaps, but for some reason I get weird seams between tiles that seem to have a random color from the tile I'm drawing without any good reason, and it only happens when I enable mipmaps, regardless of if I use GL_LINEAR or GL_NEAREST. That means that you could get the exact same result by using a single huge 2D texture with the tileset instead of a 2D texture array as long as you eliminate bleeding by enabling GL_NEAREST or adding a border around each tile. The real problem is generating texture coordinates from the tile index in the fragment shader, and I suspect that performance could suffer a little because of this. Using a texture array, I can just pass in the tile index as an integer to the sampler and get the correct layer, which allows me determine the tile index and get the tile texture in only 3 lines.

Anyway, it's nice to see people interested in this. =D

EDIT: Facepalm! There's a small "bug" in the shader. It's supposed to be float tile = dot(tileResult, vec2(65536, 256.0)), not 65535!!! It'll probably round to the right number as lang as the index is under 32 000 though... xd

There is no god.
Offline h3ckboy

JGO Kernel
*****

Posts: 1645
Medals: 4



« Reply #9 on: 2011-12-15 12:07:07 »

yeah, now that u said that I realize its true. wow I wasted soooo many hours on chrono trigger... haha.
Pages: [1]
  Print  
 
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.16 | SMF © 2011, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.156 seconds with 20 queries.