Шум Перлина не ровный на единичных углах - PullRequest
0 голосов
/ 08 апреля 2019

Я изучаю шум Perlin и написал реализацию на Python. Это выглядит примерно так; однако при его построении стороны единичных квадратов не совпадают (только в направлении оси X). Это трудно объяснить, , так что вот картинка . Я нарисовал красные линии, чтобы выделить области, где одна сторона линии не совпадает с другой. Обратите внимание на то, как линии происходят на одинаковых «высотах», которые на расстоянии 10 точек расположены вертикально. Вертикальное направление - это направление x, и каждая точка отделена на 0.1, так что это действительно происходит между единичными квадратами, только в направлении x.

Вот код шума Перлина:

    def perlin(self, vector: Vector2) -> float:
        # Unit square our vector is in: [0, 255]
        unit_square: Vector2 = np.array([int(coord) & 255 for coord in vector])
        xs: int = unit_square[0]
        ys: int = unit_square[1]

        # The coordinates of our vector inside its unit square: [0, 1] × [0, 1]
        relative_vector: Vector2 = np.array([coord - math.floor(coord) for coord in vector])
        x_rel: float = relative_vector[0]
        y_rel: float = relative_vector[1]

        # Smoothed relative vector: [0, 1] × [0, 1]
        smoothed_vector: Vector2 = np.array([self.fade(coord) for coord in relative_vector])
        (u, v) = smoothed_vector

        # Hashes the vertices of the unit square using Ken Perlin's hash function
        # Uses ((xs, ys), (xs, ys+1), (xs+1, ys), (xs+1, ys+1))
        vertex_hashes: Tuple[int, int, int, int] = tuple(
            self._hash_lookup_table[self._hash_lookup_table[xs + (mask & 2 == 2)] + ys + (mask & 1 == 1)]
            for mask in range(4)
        )

        # Gets the gradient vector for each vertex
        gradient_vectors: Tuple[Vector2] = tuple(self._grad_table[hash_] for hash_ in vertex_hashes)

        # Dot products between a vertex's gradient vector and the vector from the input to that vertex
        grad_1: float = np.dot(gradient_vectors[0], np.array([-x_rel, -y_rel]))    # Bottom left
        grad_2: float = np.dot(gradient_vectors[1], np.array([-x_rel, 1-y_rel]))   # Top left
        grad_3: float = np.dot(gradient_vectors[2], np.array([1-x_rel, 1-y_rel]))  # Top right
        grad_4: float = np.dot(gradient_vectors[3], np.array([1-x_rel, -y_rel]))   # Bottom right

        x1: float = self.lerp(grad_1, grad_4, u)
        x2: float = self.lerp(grad_2, grad_3, u)

        val: float = (self.lerp(x1, x2, v) + 1) / 2  # [0, 1]
        return val

    @staticmethod
    # Linear interpolation
    def lerp(a: float, b: float, x: float) -> float:
        return a + x * (b-a)

    @staticmethod
    # Ken Perlin's fade function to ease values towards integral values to smooth the noise output: 6t^5 - 15t^4 + 10t^3
    def fade(t: float) -> float:
        return 6 * t**5 - 15 * t**4 + 10 * t**3

Вот код "рисования", хотя он не должен иметь значения:

def draw_perlin_plane(rows: int = 50, columns: int = 211, step: float = 0.1, color_precision: int = 6,
                      gradient: Tuple[Color, Color] = (Color("white"), Color("black"))):
    importlib.reload(noise)
    gen: noise.PerlinNoiseGenerator = noise.PerlinNoiseGenerator2D()
    terrain: List[List[float]] = []
    gradient = list(gradient[0].range_to(gradient[1], color_precision))

    for x in range(rows):
        terrain.append([])
        for y in range(columns):
            terrain[x].append(gen.perlin((np.array([x * step, y * step]))))

    for row in terrain:
        line: str = ""
        for value in row:
            color = gradient[int(value // (1 / color_precision))]
            red: int = math.floor(color.get_red() * 255)
            green: int = math.floor(color.get_green() * 255)
            blue: int = math.floor(color.get_blue() * 255)
            line += f"\x1b[38;2;{red};{green};{blue}m#"
        print(line)

(используется со значениями по умолчанию на рисунке выше.)

Мне интересно, почему эти острые края возникают, если они нормальные и как их исправить.

Спасибо

...