[Solved]Height Map Vertex Rotation Rule isses. (Its hard to sum up)

o/ I have been following this forum already quite a while and there has been already quite a bit of useful information out of that.

I am building myself right now an engine which is a 3D Game with a 2D Tile System (with height included)
So the Tiles are just auto translated based on terrain height, but are not aware of the height itself.

Ok here is my problem where i am still trying to find solutions for but i am in a feedback loop.

So as you can see the Vertexes at the bottom & top left (& right) are not rotated right, and i have already a system in place that can rotate them by just injecting a flag into the terrain texture. So thats not an issue.

My issue is to define the rules to automatically fix them. Yes the bottom part is fairly easy to fix, i found already a consitent rule that would fix it.
The issue is the top part because all rules i have tried so far to fix them would either not work at all, or invert the issue, or just work in 50% the cases.

Some details that i have found out: the issue only appears on the x + 1 & z + 1.

Do you guys have any ideas or sources that could help.
(Yes I know i provided barely any info i am just not sure what info is needed so please tell if you want to know regarding that issue)

Thanks for reading Speiger

If:

  • the “mountains” are always square shaped
  • the rotation (compared to the ground) is always the same

Inject the flag whenever they face SE or NW (in this case)… or?

i take the height difference between opposite corners, and if one is bigger than the other then flip it.


	float length1 = Math.abs(cornerHeight1 - cornerHeight3);
	float length2 = Math.abs(cornerHeight2 - cornerHeight4); 

	if (length1 > length2) flip = true;

…although that looks like it wont work on the peaks there.

Em yeah a friend of mine and me have solved that problem.
A 2x2 grid check of the vertex was not enough to get the amount of detail so we decided to switch to a 3x3 grid check.

That alone did not give enough good results so we came up with a solution to fix this problem at least a lot better.
This solution only handles like 99.5% of the cases (only extreme edge cases are left that you can not directly detect in this system)

The solution was to generate all possible cases automatically and evaluate them manually.
Since we had a 3x3 grid that was 8 bits of data around that point of interest. Well technically 16 bit since we have to see the difference between is higher & is lower.

That was not really hard. Setting up a UI that asks you is this ok or does it need to be rotated was pretty simple. After that it was around 1 hour sitting there pressing 2-3 buttons constantly to say: Yay/Nay (I felt like monkey push button to get reward xD)

That resulted out of the 65k cases that there were like 2.6k broken cases that needed to be rotated.
It was a long list.

I leave the code here if other people have close issues with that kind of system.


//Calculates if the Vertex needs to be rotated to look nice in the map.
public int calculateVertexState(int x, int y)
{
	int index = createIndex(x, y);
	if(index == 109) //Edge Case where i needed to check what vertex rotation comes directly after that.
	{
		return createIndex(x + 1, y + 1) == 110 ? 1 : 0;
	}
	else if(index == 115)//Edge Case where i needed to check what vertex rotation comes directly after that.
	{
		return createIndex(x + 1, y + 1) == 118 ? 1 : 0;
	}
	//ROTATION_CACHE is just a IntSet(FastUtil)/Set<Integer> with all the possiblities that i had manually selected
	return ROTATOR_CACHE.contains(index) ? 1 : 0;
}

//Creates a Bit Based index around the vertex that needs to be checked. (Right=>Left)First 8 Bits are if the terrain is higher then the vertex to check. Second 8 bits are if they are lower then the vertex to check.
public int createIndex(int x, int z)
{
	int height = getHeight(x, z);
	return getMultiFlag(x, z, height, 0, true) | getMultiFlag(x, z, height, 8, false);
}

//Helper function to reduce code size. It Just creates a 8 Bit Number the represents the HeightDiffereces
private int getMultiFlag(int x, int z, int height, int bitOffset, boolean up)
{	
	return getFlag(x - 1, z - 1, height, bitOffset, up) | getFlag(x, z - 1, height, bitOffset+1, up) | getFlag(x - 1, z, height, bitOffset+2, up) | getFlag(x + 1, z - 1, height, bitOffset+3, up) | getFlag(x - 1, z + 1, height, bitOffset+4, up) | getFlag(x + 1, z, height, bitOffset+5, up) | getFlag(x, z + 1, height, bitOffset+6, up) | getFlag(x + 1, z + 1, height, bitOffset+7, up);
}

//Helper function to reduce code size. Checks if the terrain is higher or lower and returns 1 bit based on that.
private int getFlag(int x, int z, int height, int bitOffset, boolean up)
{
	if(up)
	{
		return (getHeight(x, z) > height ? 1 : 0) << bitOffset;	
	}
	return (getHeight(x, z) < height ? 1 : 0) << bitOffset;
}

Thanks to fast util its only like 10-20kb of data that i actually store in ram.
Also this code is enough that you can easily generate yourself the “Automated Display Evaluation System” out of that.

That should at least cover enough cases that i can easly generate terrain without problems. And even if there is some left there is a manual fixing system for that. Once the map is generated the vertex data is anyway stored in the save file so players themselves don’t get any issues afterwards.

If you have any improvement ideas go ahead i will follow this thread at least a bit.

Thanks for reading/time. Speiger

Edit 1: Oh yeah i just forgot, why i return 0-1 in the function instead of the true/false is because this function actually parses directly into a Texture (which is the terraincolor, heightmap, colorOverlayForTerrain, VertexRotation, not in that order), because i use a Instanced Mesh renderer for a giant map and only have like 1 mesh for the entirety of it (mesh is 16x16 tiles). (Largest right now is 4096x4096 tiles)

If you have time and inclination, it would be neat to see a picture of the corrected version.

I used a different terrain for that but this seems to look correct.