Okay so I have this terrain stamper I have made, that takes a height map, made up in an array float[ , ] that smaller then the terrain heights array… I have it able to apply the heights onto what area I select on the terrain,one of 4 ways… normal, upside-down, rotated 90 left, and 90 right. My problem is now I need to apply them at a certain angle, other then “Squared/Rectangular” . Trying to figure out the best way to do so that, since my arrays are no longer squared up…I was thinking about ,shooting Raycasts down at certain points that make up the height map. then rounding to the nearest resolution point in the terrain array to adjust with += there… or maybe shooting rays from the terrain up and at gameobject I applied the height map to but I don’t want it to grow to that height if that height was supposed to be 0 addition. Maybe I’m over thinking this (more then likely) just cant decide on the best way. And I have a feeling there’s a better way then shooting raycasts… any input would be appreciated.
I would just iterate the terrain and see if any of it intercepts the stamper outline.
This script basically does that: lets you make a bunch of colliders of arbitrary shape, position them, then with one click it blends the terrain up to their height. Orientation, tilt, rotation, etc. doesn’t matter since it raycasts at the colliders.
Full source code linked in the video comments. It can match to upper or lower edge of colliders.
Nice but it would cause problems since there are heights in the heightmap that are zero and if i put it on the gameobject above the terrain and cast to it it would way it up to that point when it really should be at zero…I worked on it all day and after hours of tinkering I came up with an array only version…
public static float[,] Loader(float[,] heights, HeightMap sectionObj, Vector3 loadPoint)
{
//used for turning the hieght map
int degree = Random.Range(0, 360);
Vector3 angle = new Vector3(0, degree, 0);
//this is cordinate where i clicked with my mouse on the terrain
Vector2 loadPointV2 = Utility.ConvertWorldCords2TeraCords(loadPoint);
//coverts my heightmap list into a multidimensional height map array
float[,] section = sectionObj.heightArray.ToArray().TwoDimensional((int)sectionObj.arraySize.x, (int)sectionObj.arraySize.y);
//round - no float numbers in an array
int xMid = Mathf.RoundToInt((section.GetLength(1) - 1) / 2);
int yMid = Mathf.RoundToInt((section.GetLength(0) - 1) / 2);
// offset my heightmap so that it starts array in the middle from where i clicked
Vector2 start = new Vector2(loadPointV2.y - (xMid + 1), loadPointV2.x - (yMid + 1));
Vector2 end = new Vector2(start.x + (section.GetLength(1) - 1), start.y + (section.GetLength(0) - 1));
// matching array for world cords from resolution points
Vector3[,] worldPoints = new Vector3[section.GetLength(0), section.GetLength(1)];
// step threw the array easyer
int xStep = -1;
int yStep = -1;
// used/changed resolution points
List<Vector2> usedLocs = new List<Vector2>();
// go through heights in terrain data
for (int y = 0; y < heights.GetLength(0); y++)
{
if (y >= start.y && y <= end.y) yStep++;
else yStep = -1;
for (int x = 0; x < heights.GetLength(1); x++)
{
if (x >= start.x && x <= end.x) xStep++;
else xStep = -1;
// heights that match the area selected
if (xStep >= 0 && yStep >= 0)
{
worldPoints[yStep, xStep] += Utility.ConvertTeraCords2WorldCords(new Vector2(y, x));
}
}
}
// point where all others point rotate around in the array
Vector3 pivot = worldPoints[yMid, xMid];
// goes thru stored vectors
for (int y = 0; y < worldPoints.GetLength(0); y++)
{
for (int x = 0; x < worldPoints.GetLength(1); x++)
{
Vector3 point = worldPoints[y, x];
// rotate each points on a pivot except the pivot;
if (point != pivot)
{
point = Utility.RotatePointAroundPivot(point, pivot, angle);
Vector2 loc = Utility.ConvertWorldCords2TeraCords(point);
if (section[y,x]>0 && heights[(int)loc.y, (int)loc.x] <= section[y, x])
{
heights[(int)loc.y, (int)loc.x] += section[y, x];
// save all heightmap location that we change
if (!usedLocs.Contains(loc))usedLocs.Add(loc);
}
}
}
}
//go thru used points and make sure all points that wasnt used next to the points are avg to the points
//around it, else you get holes in the terrain;
for (int i = 0; i < usedLocs.Count; i++)
{
Vector2 left = new Vector2(usedLocs[i].x -1, usedLocs[i].y);
Vector2 upLeft = new Vector2(usedLocs[i].x - 1, usedLocs[i].y+1);
Vector2 up = new Vector2(usedLocs[i].x, usedLocs[i].y+1);
Vector2 upRight = new Vector2(usedLocs[i].x + 1, usedLocs[i].y+1);
Vector2 right = new Vector2(usedLocs[i].x + 1, usedLocs[i].y);
Vector2 downRight = new Vector2(usedLocs[i].x - 1, usedLocs[i].y-1);
Vector2 down = new Vector2(usedLocs[i].x, usedLocs[i].y-1);
Vector2 downLeft = new Vector2(usedLocs[i].x - 1, usedLocs[i].y-1);
if (!usedLocs.Contains(left))
heights[(int)left.y, (int)left.x] = Utility.MultiDArrayAVGAround(heights, left);
if (!usedLocs.Contains(upLeft))
heights[(int)upLeft.y, (int)upLeft.x] = Utility.MultiDArrayAVGAround(heights, upLeft);
if (!usedLocs.Contains(up))
heights[(int)up.y, (int)up.x] = Utility.MultiDArrayAVGAround(heights, up);
if (!usedLocs.Contains(upRight))
heights[(int)upRight.y, (int)upRight.x] = Utility.MultiDArrayAVGAround(heights, upRight);
if (!usedLocs.Contains(downRight))
heights[(int)downRight.y, (int)downRight.x] = Utility.MultiDArrayAVGAround(heights, downRight);
if (!usedLocs.Contains(down))
heights[(int)down.y, (int)down.x] = Utility.MultiDArrayAVGAround(heights, down);
if (!usedLocs.Contains(right))
heights[(int)right.y, (int)right.x] = Utility.MultiDArrayAVGAround(heights, right);
if (!usedLocs.Contains(downLeft))
heights[(int)downLeft.y, (int)downLeft.x] = Utility.MultiDArrayAVGAround(heights, downLeft);
}
return heights;
}
the Utility functions are pretty simple the MultiDArrayAVGAround adds up all heights around a point and finds the average… the converters used to go between world to terrain cordinates
and for Roation its simple:
public static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
{
Vector3 dir = point - pivot; // get point direction relative to pivot
dir = Quaternion.Euler(angles) * dir; // rotate it
point = dir + pivot; // calculate rotated point
return point; // return it
}