TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post here if you need help getting started with Daggerfall Unity or just want to clarify a potential bug. Questions about playing or modding classic Daggerfall should be posted to Community.
User avatar
Daniel87
Posts: 246
Joined: Thu Nov 28, 2019 6:25 pm

TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Daniel87 »

Hi everyone,

Currently, there is only a transition from water -> dirt -> grass -> stone in the ITerrainTexturing.cs

I was wondering if and when all transitions will be implemented.

To quote Interkarmas (I think?) comments:

Code: Select all

// Very basic marching squares for water > dirt > grass > stone transitions.
// Cannot handle water > grass or water > stone, etc.
// Will improve this at later date to use a wider range of transitions.
If somebody can help me wrap my mind around the LookupTable, maybe I can help with this? I would really need some nicer transitions between all the different terrain textures, as this is VERY restricting in how I texture the terrain right now.

Thanks for any hints and help!

User avatar
King of Worms
Posts: 3955
Joined: Mon Oct 17, 2016 11:18 pm
Location: Scourg Barrow (CZ)
Contact:

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by King of Worms »

Nice to see u pushing it forward.. bump 😉

User avatar
Interkarma
Posts: 6284
Joined: Sun Mar 22, 2015 1:51 am

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Interkarma »

This relates to default wilderness tiling algorithm, which I thought I'd do more with several years back. I doubt that I'll return to it again now.

But this doesn't hold you back at all. You can tile the terrain using whatever means you want by implementing your own ITerrainTexturing class.

Take a look at Hazelnut's Basic Roads as an example. This mod lays down road tiles, but you could layout terrain tiles using any system you want.

https://github.com/ajrb/dfunity-mods/bl ... xturing.cs

By the way, that comment just refers to tile selection using my basic marching squares algo. It's not referring to adding new tile adjacencies that don't already exist in game art.

User avatar
Daniel87
Posts: 246
Joined: Thu Nov 28, 2019 6:25 pm

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Daniel87 »

Interkarma wrote: Tue Apr 20, 2021 12:25 pm This relates to default wilderness tiling algorithm, which I thought I'd do more with several years back. I doubt that I'll return to it again now.

But this doesn't hold you back at all. You can tile the terrain using whatever means you want by implementing your own ITerrainTexturing class.

Take a look at Hazelnut's Basic Roads as an example. This mod lays down road tiles, but you could layout terrain tiles using any system you want.

https://github.com/ajrb/dfunity-mods/bl ... xturing.cs

By the way, that comment just refers to tile selection using my basic marching squares algo. It's not referring to adding new tile adjacencies that don't already exist in game art.
Hey Interkarma,

Thanks for getting back to me. From the texture files of the DFU Texture Tool, I saw that there were gradient tiles for sand-water, grass-water, stone-grass, etc. Since I never played the original game, I don't know if they ever got used or not.
Could you point me to the exact cs file where these textures are being defined for the borders between two tile types? So far I understood how to utilize plain dirt, water, grass and stone tiles but am not sure where they get defined exactly and where I would add additional gradients.
(I never really worked with byte arrays and such means before, so I am not sure if I am sitting right infront of it but am not seeing it or if I am looking in the wrong files).

EDIT: I just checked the github link u gave me that pointed to the basicRoads sollution of texturing tiles. As I based my mod on your original ITerrainTexutring.cs, where would I find the equivalent in the approach you have chosen back when you wrote it? I mean I saw where the byte are declared as grass, stone, etc. (not sure how to find out which byte in the game files stands for which texture) but where does your algorithm decide which gradient texture to use for a transition between grass and dirt by example?

In the basic road example, he used byte arrays, but from where does he know the byte number of each texture?

Code: Select all

new byte[] { 00, 00, 00, 00 },  // Cardinal - Inner
Did you solve it in the original DFU the same way?

I think those byte-wise operations are above my pay-grade and intellectual capacity as a hobby coder, so I guess I will need a volunteer helping me with this part of my script or simply give up on it for the sake of getting the mod finished. Anyone who wants to help me with this, please contact me via PN.

User avatar
Interkarma
Posts: 6284
Joined: Sun Mar 22, 2015 1:51 am

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Interkarma »

Hey Daniel87 :)

Using Daggerfall Imaging, the tilesets are TEXTURE.002-004 (desert), 102-104 (mountain), 302-304 (temperate), 402-404 (swamp). These tiles form everything you see on the ground in wilderness and towns. Each tile can be flipped, rotated or both.

tiles.JPG
tiles.JPG (184.98 KiB) Viewed 178 times

These tiles are designed to fit together using marching squares, an algorithm to follow contours using pre-made shapes. Compare the shapes below with the shapes above and you'll see the same patterns. This is what the lookup table is based on.

contours.JPG
contours.JPG (42.18 KiB) Viewed 178 times

RMB (city) blocks have a bespoke tile layout by a human creator. All roads, parks, town squares, etc. are defined in the block data. When painting tiles inside locations, the bespoke data will always be used.

Out in the wilderness, you can paint tiles however you want by registering a custom implementation of ITerrainTexturing. Inheriting from DefaultTerrainTexturing and overriding the virtual methods like in Basic Roads is the best starting point.

When DFU paints wilderness tiles, it will use the active ITerrainTexturing interface and ask it to supply a byte array for that block. This is done using the Unity job system, which complicates things a little, but the premise is fairly simple - populate an array with numbers matching the index and orientation of tiles you want to use.

The simplest implementation would paint the whole world using a single tile like dirt (index 1) or grass (index 2). This is the best place to start to make sure your ITerrainTexturing implementation is basically working. Then expand it to use another algorithm like a better version of marching squares.

Using my basic marching squares as an example, it creates a lookup table of tiles to suit the standard marching squares contours shown in image above. MakeLookup() is a helper method to set an index, rotation, and flip to a byte. Each tile byte uses the following bit setup.

Code: Select all

bits  0-5  tile index in TEXTURE.002, etc.
bit   6    set bit to rotate tile
bit   7    set bit to flip tile
The reason my algo is so basic is that it only supports contour adjacencies in a linear manner. For example, water>dirt>grass>stone. I'm not great with mathy concepts and I have to work hard just to create basic stuff like this, even with lots of examples out there to follow.

I don't recall classic using the full complement of tiles in wilderness either, it's a fairly simple implementation too. AFAIK the full tilesets are only used in locations. A better algorithm could support all the adjacencies in TEXTURE.002, etc, including those novel tri-part corner pieces.

The best advice I can offer is to start small and simple as possible. Paint the world completely in grass or dirt, or random tiles, then start working up from there. The standard marching square algorithm will yield results similar to classic and DFU, but I have no doubts someone brighter than myself could build a better algorithm to paint more interesting terrain tiles across the wilderness.

Alternatively, you could use some other solution to paint the world, like a splat map. There's some support for this in the game now, TheLacus has a Splat Terrain Texturing mod using splats instead of tiles. You could possibly even inject new materials onto terrain using a totally custom shader and solution, but you'd have to find a way to support towns as well.

User avatar
Daniel87
Posts: 246
Joined: Thu Nov 28, 2019 6:25 pm

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Daniel87 »

Interkarma wrote: Tue Apr 20, 2021 10:32 pm The reason my algo is so basic is that it only supports contour adjacencies in a linear manner. For example, water>dirt>grass>stone. I'm not great with mathy concepts and I have to work hard just to create basic stuff like this, even with lots of examples out there to follow.
First of all, thank you for the thorough explanation, that definitely is a great starting point for me.
I will try to wrap my head around working with bits and bytes in the coming weeks/months based on this.

Your stated reason speaks from my heart as well. Though I studied hydrogeology and engineering, the math and mainly physics I used is not at all related to IT, so I will have to invest quite some time to wrap my head around it starting with your approach and abondinning the nature flats for now to dedicate the time to terrain texturing and the marching square algorithm. I have watched tutorials on how it is applied on 3D maps so reducing this to 2D should simplify the matter a bit.

But I still keep my hopes up that someone smarter than us will join and help us :D

So if I understood it right, all I would need is to

A) Expand upon the LookUpTable and
B) Expand upon the Marching Square algo to cover all other terrain transitions?

I will definitely make some experiments with this now. Thanks again for the time and work you put in!!

Stay safe!

User avatar
Interkarma
Posts: 6284
Joined: Sun Mar 22, 2015 1:51 am

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Interkarma »

Yep, those two points sum it up. :) Start simple and build up in stages. I'm interested to see what you end up with.

User avatar
Daniel87
Posts: 246
Joined: Thu Nov 28, 2019 6:25 pm

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Daniel87 »

Interkarma wrote: Wed Apr 21, 2021 8:31 am Yep, those two points sum it up. :) Start simple and build up in stages. I'm interested to see what you end up with.
Can I ask you one quick question?

Code: Select all

void AddLookupRange(int baseStart, int baseEnd, int shapeStart, int saddleIndex, bool reverse, int offset)
Looking at the Lookup-Table contour lines right now: What is saddleIndex and shapeStart
(I know shape refers to

Code: Select all

int shape = (b0 & 1) | (b1 & 1) << 1 | (b2 & 1) << 2 | (b3 & 1) << 3;
, but I am not really understanding, what this int shape and int ring is doing exactly. Did you use a specific tutorial for this marching square, which I could also have a look into?
Last edited by Daniel87 on Wed Apr 21, 2021 10:42 am, edited 2 times in total.

User avatar
pango
Posts: 2917
Joined: Wed Jul 18, 2018 6:14 pm
Location: France
Contact:

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by pango »

If I understand correctly, those 4 bits match the 4 black-or-white dots at the corners of the schema above
Follow the "marching squares" Wikipedia link in Interkarma's post if you haven't already, hopefully it will be more clear
When a measure becomes a target, it ceases to be a good measure.
-- Charles Goodhart

User avatar
Daniel87
Posts: 246
Joined: Thu Nov 28, 2019 6:25 pm

Re: TerrainTexturing -> Incomplete LookupTable for tile texture transitions

Post by Daniel87 »

Had my "AHAAA!"-moment. I think I got it.
It took me a while to understand, that your lookup table looks like:
Case: 0,1,2,3, 8,9,10,11, 4,5,6,7, 12,13,14,15
Is there a reason it is built like this?

Image

EDIT:

I guess, this answers my question:

Code: Select all

int shape = (b0 & 1) | (b1 & 1) << 1 | (b2 & 1) << 2 | (b3 & 1) << 3;
int ring = (b0 + b1 + b2 + b3) >> 2;
int tileID = shape | ring << 4;

tilemapData[index] = lookupTable[tileID];

Post Reply