1
\$\begingroup\$

I'm trying to write a Java class to generate Perlin Noise from a Cartesian coordinate. I'm trying to follow this tutorial but I am struggling to understand the theory.

Specifically, how do you divide coordinates into a unit square or unit cube?

My original though was to a find which was higher the X or Y, then divide one by the other, So either X = 1, y < 1, or Y = 1, X < 1. But doing this doesn't really make sense as the point would always lie on one of the cube/square vertices.

Can someone explain the math to me please.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

First, we divide the x, y, and z coordinates into unit cubes. In other words, find [x,y,z] % 1.0 to find the coordinate's location within the cube.

What that means is you perform the value % 1.0 operation for each member of the [x,y,z] vector (the position):

[x', y', z'] = [x % 1.0, y % 1.0, z % 1.0]

x', y', and z' are the remainders of dividing each floating-point coordinate by 1.0.

In other words, they are the amount you "chop off" of each coordinate when you round towards zero.

[x', y', z'] represents the position inside a unit cube, from 0.0 to 1.0 on each axis.
But you can also imagine that unit cube is actually positioned in 3D space at the rounded (towards zero) coordinates of [(int)x, (int)y, (int)z].

Another way to visualize what [x', y', z'] means is to imagine a 1x1x1 grid superimposed over your game world. Each cell in the grid is a unit cube. If you have a point anywhere in that game world, it must be inside of of those cubes. [x', y', z'] is telling you where the point is inside that cube.

The original position can be recovered by adding the position of the unit cube and the position inside the unit cube:
[x, y, z] = [(int)x, (int)y, (int)z] + [x % 1.0, y % 1.0, z % 1.0]

\$\endgroup\$
1
  • \$\begingroup\$ Thank you so much for the detailed explanation. I understand what it means now. \$\endgroup\$ Mar 5, 2020 at 7:48
0
\$\begingroup\$

Usually 3D Perlin noise would look a bit like this:

float PerlinNoise(Vector3 point) {

    Vector3Int root = new Vector3Int(
         FloorToInt(point.x),
         FloorToInt(point.y),
         FloorToInt(point.z));

    for(int i = 0; i < 8; i++) {
        Vector3Int corner = root + cornerOffset[i];
        Vector3 gradient = GetPerlinGradient(corner);
        contribution[i] = Vector3.Dot(gradient, point - corner);
     }

     Vector3 pointInCell = point - root;

     return Interpolate(
         Interpolate(
              Interpolate(
                   contribution[0],
                   contribution[1],
                   pointInCell.x
              ),
              Interpolate(
                   contribution[4],
                   contribution[5],
                   pointInCell.x
              ),
              pointInCell.y
         ),
         Interpolate(
              Interpolate(
                   contribution[3],
                   contribution[2],
                   pointInCell.x
              ),
              Interpolate(
                   contribution[7],
                   contribution[6],
                   pointInCell.x
              ),
              pointInCell.y
         ),
         pointInCell.z
     );
}

So dividing space into repeated cubes is just a matter of rounding/flooring the coordinate. The position within this cell is just the fraction left over.

\$\endgroup\$
1
  • \$\begingroup\$ thanks for the code sample. I can use this later \$\endgroup\$ Mar 5, 2020 at 7:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .