# Issues wrapping my brain around this math

This is a problem for you math wizards that I have been stumped on for a while even though I feel like I should be able to solve it.

**What I am doing :** I am taking an image, or rather, float[,] values from an image and putting them into an array. From that array I am "upressing" the values so that the range of values turns into a larger pool. From there I am dividing it up into chunks. This is for terrain generation.

So for this example.

N = 512 (the original input dimensions. 512*512)

Up = 5 (the upres amount)

Cs = 512 (The chunk dimensions. 512*512)

Ms = N * Up (The total dimensions of the upresed array. 2560*2560)

Gs = Ms/Cs (The grid dimensions. 5*5 chunks)

Currently I am upresing the entire thing all at once. What I want to be able to do is upress only the necessary areas. As you can imagine, upressing a 512*512 image 50 times (25600*25600) would take a while to process a lot of unnecessary data...especially when its going to be representing terrain that the player wont be near.

**Where I fail:** I need to be able to access the specific values that are getting upresed into the chunk dimensions (512x512) from the original input (N) and upres only those. I cant have float values and I cant be rounding. The values exist and are being upressed, I just cant think of a way to reverse this process.

**Conclusion:** I want to collect only the necessary values from the original input and pass those to be upresed instead of unpresing the entire original input array.

Here is the code I am currently working with.

```
float[,] originalInput; // an array containing the original values, im using 512*512 (N)
int upres = 5; // how many times the original values are upres (Up)
originalInput = UpresHeights(originalInput, upres); //upres the input
int mapsize = originalInput.GetLength(0); // (Ms)
int chunkSize = 512; //(Cs)
int gridSize = (int)Mathf.Round((mapsize / (float)chunkSize)); //Grid size (Gs)
float[,] UpresHeights(float[,] oldHeights, int upres)
{
//Duplicate the array input array
int originalHeight = oldHeights.GetLength(0);
float[,] heights = new float[originalHeight, originalHeight];
for (int y = 0; y < originalHeight; y++)
{
for (int x = 0; x < originalHeight; x++)
{
float val = oldHeights[x, y];
heights[x, y] = val;
}
}
//Upres the new array
int heightsLength = originalHeight;
int resolution = (heightsLength * upres);
float[,] newHeights = new float[resolution, resolution];
for (int y = 0; y < originalHeight; y++)
{
for (int x = 0; x < originalHeight; x++)
{
//The original input is tileable, so the following
//just makes sure to sample from the opposite side
//of the array if at the border
float right = 0.0f;
if (x == originalHeight - 1)
{
right = heights[0, y];
}
else {
right = heights[x + 1, y];
}
float top = 0.0f;
if (y == originalHeight - 1)
{
top = heights[x, 0];
}
else {
top = heights[x, y + 1];
}
for (int xx = 0; xx < upres; xx++)
{
for (int yy = 0; yy < upres; yy++)
{
//smooth the values (could use vector2.distance,
//but this isnt important right now)
//not that important since blur is applied later
float a = Mathf.Lerp(heights[x, y], right, (xx / (float)upres));
float b = Mathf.Lerp(heights[x, y], top, (yy / (float)upres));
newHeights[x * upres + xx, y * upres + yy] = (a + b) / 2f;
}
}
}
}
return newHeights;
}
```

**Answer** by b1gry4n
·
Oct 02, 2016 at 07:34 AM

Heres the solution.

I needed to create two new variables

```
//The sample area "per chunk" of the lower resolution array
lowResWidth = (N) / (Gs);
//the value of a step. Since its being upresed and between each value in //the array many other values are being made, this would be a float
//example: between value 1 and value 2, theres 5 values with a pixel
//step of 0.2
pixelstep = lowResWidth / (CS);
```

My grid was already set up with x and y coordinates, so i needed to find the start value of the x and y in relation to the "downscaled" version

```
float startX = lowResWidth * gridpoint.x;
float startY = lowResWidth * gridpoint.y;
```

I created a new function to return an upresed array from that specific area of the downscaled array called with

```
float[,] segment = UpresSeg(originalValues(N), chunkDimensions(Cs), startX, startY, gridPoint.x, gridPoint.y);
```

and the meat:

```
float[,] UpresSeg(float[,] originalHeight, int resolution, float startX, float startY, int gridX, int gridY)
{
//create a new array to return
float[,] returnThis = new float[resolution, resolution];
//Since its possible to start on a float (example 1.2), we need to floor the original start values
int origStartX = Mathf.FloorToInt(startX);
int origStartY = Mathf.FloorToInt(startY);
//we also need to subtract the original start floored value from the given start so we can retieve our
//xstep and ystep starting points
float xStep = startX - origStartX;
float yStep = startY - origStartY;
int xCounter = 0;
int yCounter = 0;
for (int y = 0; y < resolution; y++)
{
//reset the x counter for the new row
xCounter = 0;
for (int x = 0; x < resolution; x++)
{
int origX = Mathf.FloorToInt(gridX * lowResWidth) + xCounter;
int origY = Mathf.FloorToInt(gridY * lowResWidth) + yCounter;
float right = 0.0f;
float top = 0.0f;
int xMod = 0;
int yMod = 0;
if (origX < originalHeight.GetLength(0) - 1)
{
xMod = origX + 1;
}
else {
xMod = originalHeight.GetLength(0) - 1;
}
right = originalHeight[xMod, origY];
if (origY < originalHeight.GetLength(1) - 1)
{
yMod = origY + 1;
}
else {
yMod = originalHeight.GetLength(1) - 1;
}
top = originalHeight[origX, yMod];
float a = Mathf.Lerp(originalHeight[origX, origY], right, xStep);
float b = Mathf.Lerp(originalHeight[origX, origY], top, yStep);
returnThis[x, y] = (a + b) / 2f;
xStep += pixelstep;
if (xStep >= pixelstep * tileSettings.upres)
{
xStep = 0.0f;
xCounter++;
}
}
yStep += pixelstep;
if (yStep >= pixelstep * tileSettings.upres)
{
yStep = 0.0f;
yCounter++;
}
}
return returnThis;
}
```

There are some new issues that arise for me, but those are related to my generation script and what it does after this step. This might not be the best way to do this or even the "smartest" way, but it works

**Answer** by Bunny83
·
Oct 02, 2016 at 01:42 AM

Well, it all boils down how you want to interpolate the values across your new resolution. What you do currently is kinda strange:

```
top----unused
| |
| |
x/y----right
```

Currently you ignore the height at "unused" and only interpolate in the lower left triangle.

Maybe you want a bilinear interpolation?

As for how to find the right values, first need some additional information: The chunk x and y position in "chunk coordinates". So the first chunk would have (0, 0) the second on the x axis would have (1, 0). The last chunk would be (4,4)

Now you could split the problem into smaller pieces but the easiest way is to simply iterate through your target array and work out the 4 required source coordinates.

```
// chunk coordinate
int cx;
int cy;
// this is the offset of this chunk inside the source image
Vector2 offset = new Vector2(cx * Up, cy * Up);
for(int y = 0; y < chunkSize; y++)
{
for(int x = 0; x < chunkSize; x++)
{
// "p" is the exact point inside the source image including fraction
var p = offset + new Vector2(x,y) / Up;
// get the bottom left and upper right corners
int x0 = Mathf.FloorToInt(p.x);
int y0 = Mathf.FloorToInt(p.y);
int x1 = (x0 >= originalHeight - 1)?0:x0 + 1;
int y1 = (y0 >= originalHeight - 1)?0:y0 + 1;
var t = p - new Vector2(x0, y0); // extract the fractional part
float r0 = Mathf.Lerp(heights[x0, y0], heights[x1, y0], t.x);
float r1 = Mathf.Lerp(heights[x0, y1], heights[x1, y1], t.x);
newHeights[x,y] = Mathf.Lerp(r0, r1, t.y);
}
}
```

Note: I've written this from scratch without testing or syntax checking, so use at your own risk ^^.

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.