Inspired by the “Terraria-ish” thread somewhere here in the forum I was thinking about the best approach to first to setup the tileworld.
How would you guys do to to setup the visual world tiles?
My thoughts has been:
Tilemaps
Well, they are a really good option using a small number of them and just changing the tiles in them. Problem is light. As I would create a simple approach of light and let all tiles have their separate light, its not really possible to do in a tilemap component (one shader to rule them all)
Gameobjects with 8x8 sprites components inside.
This is my way of doing it right now. Unfortunately having a shader with a light property will not work as soon as it goes beyond 1024 objects as changing anything colorwise in the fragment shader breaks the batchs and results in 1024 drawcalls…
Yes, that works if all objects having the same tint. I’m thinking about them all individually having their own tint? Or am I missing something here? If I’m passing in the same tint using normal go.set I will get the same result as well (1 drawcall) but as soon as they are individually getting different tints it all breaks.
I think what you want to do is to have light positions and colors set in your sprite material (maybe have scale too). Then you set those values all at once, and you shade based on those values. Then it’s a single draw call. You can reference the builtin model material and related shader programs for the necessary components I think. Otherwise maybe one of the old materials I put together would work as a basis.
So your render script imports a module with all of the lights in your world with the important ones given priority such as ones around the character. Then passes that info as constant buffer to your lit tile predicate. All of the light positions etc. sent are the same, but the vp generates different relative positions for each lit tile so they are lit differently.
Not sure that this is the correct way to go. The solution should be considering having a light in every single tile! Thinking in the terms of the voxelengines I have been working on before. Every single tile has it’s own light and possibility to bring further light and impact the tiles next to it.
As the whole sky will be just tiles of brightest light the tiles next to it. If there is no “visible” tile, the light of that tile has less falloff and the light can then “travel” further on.
See how the tile themselves are spreading the light to their surrounding and as soon as you remove/add a tile you will impact the surrounding tiles until there is no more changes. The light is not calculated every frame but only once when changing the environment somehow or adding “lightsources” to a tile (still impacting that tile and then to the flooding calculation again from that point).
Using light sources and their positions would not be the same I believe. Its more like creating your lowres realtime lightmap.
You can render the “shading sprites” to their own render target so that you can then blur that and unify their feel a bit more probably. Overall Terraria like lighting effects should be possible without a ton of extra drawcalls.
I remember one thing about that style is that meshes are generated on the fly too for lighting info. Once we can generate meshes maybe we can get those similar effects like
which are not so easily to do dynamically currently I think.
Yes maybe tilemaps is the way to go in the end anyway. Just couldnt get the shader route out of my head.
Tilemaps though cannot in anyway be optimized (disabling tiles that should not be visible) they are just… like that.
Still the best would be if sprite tint was baked in the vertex color of the sprite as it is in the gui system. Then you could tint each individual sprite without breaking batching. I know I have discussed this elsewhere on this forum, but don’t know if it’s in any plans.
For me the obvious route would be storing the light map as a texture and supply it into each sprite. Use drawpixel extension to update the lighting map when needed.
In the sprite shader retrieve the lighting info based on world coordinates.
Yes, I was thinking of this one as well. But as I want to make an infinite world (chunks being created on the fly) and visual “chunks” are being reused and moved around, how would I approach this? I guess if recreating the texture and somehow bit-shifting it to be able to write new shadow pixels on the texture. On the other hand, this is a thing I could rewrite later on as it is very detached to the world data. Starting on the tilemap right now with shadows in a layer and then we’ll see.
Just refill the texture data based on world position. Then if you fear about performance, make a native extension that will cleverly move data buffers.