Проверка метода трехмерной визуализации фрактальных срезов - PullRequest
0 голосов
/ 31 октября 2018

Алгоритм приведения лучей

Алгоритм приведения луча MandelBulb на Python Пример

Таким образом, если я правильно понимаю, алгоритм приведения лучей требует, чтобы наблюдатель находился снаружи от трехмерного фрактала, в котором векторы точек отводятся от наблюдателя к точке на плоскости, перпендикулярной вектору и пересекающей начало координат.

Мне кажется, что это либо серьезно ограничит визуализацию фрактала, либо потребует стереоскопической трехмерной реконструкции фрактала с использованием нескольких позиций наблюдателя (что мне кажется трудным). Кроме того, никакая информация не может быть собрана относительно внутренней структуры фрактала.

Другие алгоритмы

В качестве альтернативы, прямое рендеринг объема кажется достаточно интуитивным, однако вычислительно дорогим и потенциально неэффективным само по себе. Непрямой рендеринг объема с использованием алгоритма, такого как марширующие кубы, также может показаться немного запоминающимся.

Где-то в pdf 2-й ссылки говорится о разрезанных плоскостях, чтобы увидеть кусочки фрактала.

Вопрос:

Почему бы не использовать разрезанные плоскости в качестве метода рендеринга?

  • 1) Используя модифицированный алгоритм трассировки лучей, скажем, мы поставили observer в точку Q в начале координат (0, 0, 0).

  • 2) Давайте тогда испустим лучи от начала координат к падающей плоскости, охватываемой y & z комбинациями точек, которые рассекают фрактал.

  • 3) Рассчитайте расстояние до фрактальной поверхности, используя алгоритм в 1-й ссылке. Если компонент x вычисленного расстояния находится в пределах определенного допуска, dx плоскости разреза, то координаты y & z вместе со значением x плоскости разреза сохраняются как x, y, z координаты. Эти координаты теперь представляют поверхность на этом конкретном срезе в x.

  • 4) Скажем, плоскость среза имеет одну степень свободы в направлении x. Перемещая плоскость в степени ее свободы, мы можем получить еще один набор x, y, z координат для данного среза.

  • 5) Окончательный результат - вычисляемая поверхность, созданная облаком точек, созданным на предыдущих шагах.

  • 6) Кроме того, степень свободы плоскости среза может быть изменена для создания другого облака точек, которое затем может быть проверено по сравнению с предыдущим в качестве средства последующей обработки.

Пожалуйста, смотрите изображение ниже в качестве наглядного пособия (сфера представляет собой MandelBulb).

enter image description here

Ниже приведен мой код на Python, адаптированный по первой ссылке. Я успешно генерирую плоскость точек и могу получить указания от начала координат до точек на плоскости. Должно быть что-то в корне ошибочное в функции оценки расстояния, потому что там все ломается, и я получаю nan с для общего расстояния

def get_plane_points(x, y_res=500, z_res=500, y_min=-10, y_max=10, z_min=-10, z_max=10):
    y = np.linspace(y_min, y_max, y_res)
    z = np.linspace(z_min, z_max, z_res)
    x, y, z = np.meshgrid(x, y, z)

    x, y, z = x.reshape(-1), y.reshape(-1) , z.reshape(-1)

    P = np.vstack((x, y, z)).T
    return P


def get_directions(P):
    v = np.array(P - 0)
    v = v/np.linalg.norm(v, axis=1)[:, np.newaxis]
    return v


@jit
def DistanceEstimator(positions, plane_loc, iterations, degree):
    m = positions.shape[0]

    x, y, z = np.zeros(m), np.zeros(m), np.zeros(m)
    x0, y0, z0 = positions[:, 0], positions[:, 1], positions[:, 2]

    dr = np.zeros(m) + 1
    r = np.zeros(m)

    theta = np.zeros(m)
    phi = np.zeros(m)
    zr = np.zeros(m)

    for _ in range(iterations):
        r = np.sqrt(x * x + y * y + z * z)

        dx = .01
        x_loc = plane_loc
        idx = (x < x_loc + dx) & (x > x_loc - dx)
        dr[idx] = np.power(r[idx], degree - 1) * degree * dr[idx] + 1.0

        theta[idx] = np.arctan2(np.sqrt(x[idx] * x[idx] + y[idx] * y[idx]), z[idx])
        phi[idx] = np.arctan2(y[idx], x[idx])

        zr[idx] = r[idx] ** degree
        theta[idx] = theta[idx] * degree
        phi[idx] = phi[idx] * degree

        x[idx] = zr[idx] * np.sin(theta[idx]) * np.cos(phi[idx]) + x0[idx]
        y[idx] = zr[idx] * np.sin(theta[idx]) * np.sin(phi[idx]) + y0[idx]
        z[idx] = zr[idx] * np.cos(theta[idx]) + z0[idx]

    return 0.5 * np.log(r) * r / dr


def trace(directions, plane_location, max_steps=50, iterations=50, degree=8):
    total_distance = np.zeros(directions.shape[0])
    keep_iterations = np.ones_like(total_distance)
    steps = np.zeros_like(total_distance)

    for _ in range(max_steps):
        positions = total_distance[:, np.newaxis] * directions
        distance = DistanceEstimator(positions, plane_location, iterations, degree)
        total_distance += distance * keep_iterations
        steps += keep_iterations

    # return 1 - (steps / max_steps) ** power
    return total_distance


def run():
    plane_location = 2
    plane_points = get_plane_points(x=plane_location)
    directions = get_directions(plane_points)
    distance = trace(directions, plane_location)

    return distance

Мне очень хочется услышать мысли по этому поводу и с какими ограничениями / проблемами я могу столкнуться. Заранее спасибо за помощь!

1 Ответ

0 голосов
/ 01 марта 2019

Если я не ошибаюсь, этот алгоритм не может не работать. Существует потенциальная возможность возникновения проблем с какими-либо предположениями относительно внутренней структуры MandelBulb и того, какие позиции может занимать наблюдатель. То есть, если известно, что наблюдатель изначально находится в зоне сходимости, то алгоритм трассировки лучей, который ничего не дает, так как самое дальнее расстояние, которое можно измерить, равен 0. Это связано с тем, что текущий алгоритм трассировки лучей заканчивается при Первый контакт с поверхностью. Вполне вероятно, что это может быть изменено, однако.

Вместо того, чтобы разрезать фрактал плоскостью P, может быть более целесообразно предотвратить прекращение луча при первом контакте и вместо этого завершиться на основании расстояния, которое, как известно, существует за поверхностью MandelBulb.

...