Алгоритм приведения лучей
Алгоритм приведения луча 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).
Ниже приведен мой код на 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
Мне очень хочется услышать мысли по этому поводу и с какими ограничениями / проблемами я могу столкнуться. Заранее спасибо за помощь!