- Home /
terrainData.SetHeightsDelayLOD seem to have no effect and i dont know why.
I have multiple unity terrains next to each other that i want to seamlessly erode. my current problem is how to set heights across terrain borders. The current approach is to set single heightsamples when the SetHeightsDelayLOD array would go out of bounds. Basically i provide SetHeightsDelayLOD with a [1,1] array with a single heightsample. This is expensive so I'm having it set larger arrays at a time when not crossing borders. Sadly these larger arrays seem to do nothing, event though they use the same exact function only with a larger array. Any other suggestions to improve this code are welcome, I'm still learning.
Here is the function that sets the heights. pos is the coordinates for the middle of the array. yMod and xMod is used to offset this to either access neighbouring samples or find the base coords of the array.
public void setHeight(Vector2 pos, float[,] heights, int yMod = 0, int xMod = 0)
{
pos = new Vector2(pos.x + xMod, pos.y + yMod);
Vector2 chunkPos = TerrainSettings.worldToChunk(pos);
Vector2 heightPos = TerrainSettings.worldToHeightMap(pos);
chunks[(int)chunkPos.x, (int)chunkPos.y].terrain.terrainData.SetHeightsDelayLOD((int)heightPos.x,
(int)heightPos.y, heights);
if(!chunksToUpdate.Contains(chunks[(int)chunkPos.x, (int)chunkPos.y]))
chunksToUpdate.Enqueue(chunks[(int)chunkPos.x, (int)chunkPos.y]);
}
Here is the function calculating mass to erode which then calls setHeights. It works fine when sending single samples, but when i try the larger array no changes are visible.
public static Drop takeSediment(Map map, Drop drop, float heightDif)
//calculates the amount of mass to take from the surrounding area
{
float[,] array = new float[radius * 2 + 1, radius * 2 +1];
float[,] heights = new float [2,2];
bool multiChunk = false;
//Debug.Log("takes " + Mathf.Min((drop.capacity - drop.sediment) *
erosion, heightDif * -1));
float takeAmount = Mathf.Min((drop.capacity - drop.sediment) *
erosion, (heightDif * -1)*radius);
drop.sediment += takeAmount;
float totalWeight = 0;
for (int x = -radius; x <= radius; x++)
{
for (int y = -radius; y <= radius; y++)
{
array[x + radius, y + radius] = Mathf.Max(0, radius -
(Vector2.Distance(drop.posOld, new
Vector2(drop.posOld.x + x, drop.posOld.y + y))));
totalWeight += Mathf.Max(0, radius -
(Vector2.Distance(drop.posOld, new
Vector2(drop.posOld.x + x, drop.posOld.y + y))));
}
}
for (int x = -radius; x <= radius; x++)
{
for (int y = -radius; y <= radius; y++)
{
if(TerrainSettings.worldToHeightMap(drop.posOld).x
+ radius > TerrainSettings.HeightmapResolution
|| TerrainSettings.worldToHeightMap(drop.posOld).y
+ radius >
TerrainSettings.HeightmapResolution
|| TerrainSettings.worldToHeightMap(drop.posOld).x
- radius < 0
|| TerrainSettings.worldToHeightMap(drop.posOld).y
- radius < 0)
{
//if it intersects the border use single samples
float test = map.getHeight(drop.posOld, y, x);
multiChunk = true;
float[,] tempArray = new float[1, 1] { {
map.getHeight(drop.posOld, y, x) - ((array[x + radius,
y + radius] / totalWeight) * takeAmount) } };
map.setHeight(drop.posOld, tempArray, y, x);
}
else
{
//does not intersect border, send whole array at once
multiChunk = false;
heights = map.getHeights(drop.posOld, radius);
float test = heights[x + radius, y + radius];
heights[x + radius, y + radius] =
heights[x + radius, y + radius] -
((array[x + radius, y + radius] / totalWeight) * takeAmount);
}
}
}
if (!multiChunk)
{
//this is the call that doesn't do anything
map.setHeight(drop.posOld, heights, -radius, -radius);
}
return drop;
}
Answer by Bjosor · Apr 25, 2017 at 05:04 AM
So this turned out to be an easy fix. I looked at it for so long and couldn't see what was wrong. Then i came back after a week and solved it in 15 seconds...
apparently its a bad idea to call getheights within a loop as i only want to get the heights once.
for (int x = -radius; x <= radius; x++)
{
for (int y = -radius; y <= radius; y++)
{
if(TerrainSettings.worldToHeightMap(drop.posOld).x
+ radius > TerrainSettings.HeightmapResolution
|| TerrainSettings.worldToHeightMap(drop.posOld).y
+ radius >
TerrainSettings.HeightmapResolution
|| TerrainSettings.worldToHeightMap(drop.posOld).x
- radius < 0
|| TerrainSettings.worldToHeightMap(drop.posOld).y
- radius < 0)
{
float test = map.getHeight(drop.posOld, y, x);
multiChunk = true;
float[,] tempArray = new float[1, 1] { {
map.getHeight(drop.posOld, y, x) - ((array[x + radius,
y + radius] / totalWeight) * takeAmount) } };
map.setHeight(drop.posOld, tempArray, y, x);
}
else
{
multiChunk = false;
//Moved this one out of the loop. Fixed it
heights = map.getHeights(drop.posOld, radius);
float test = heights[x + radius, y + radius];
heights[x + radius, y + radius] =
heights[x + radius, y + radius] -
((array[x + radius, y + radius] / totalWeight) * takeAmount);
}
}
Your answer
Follow this Question
Related Questions
Why do smaller terrains have higher triangle count? 0 Answers
terrain の detail について (About Terrain Detail),terrain の detail について (About Terrain Detail) 0 Answers
terrainData.heightmapTexture float value range 2 Answers
Convert terrain map coordinates (GetDetailLayer) into world position 0 Answers
Edit Terrain at runtime 1 Answer