3D分形切片渲染方法的验证
Verification of 3D Fractal Slice-Rendering Method
光线投射算法
MandelBulb Ray Casting Algorithm Python Example
因此,如果我理解正确的话,光线投射算法要求观察者位于 3D 分形之外,在该点矢量从观察者绘制到垂直于矢量并与原点相交的平面上的一点.
在我看来,这要么会严重限制分形的渲染视图,要么需要使用多个观察者位置对分形进行立体 3D 重建(这对我来说似乎很难)。此外,无法收集到有关分形内部结构的信息。
或者,直接体积渲染似乎足够直观,但计算成本高且本身可能效率低下。使用移动立方体等算法的间接体积渲染似乎也可能采用一些学习曲线。
在第二个 link 的 pdf 中的某个地方,它讨论了剖切面视图,以便查看分形切片。
问题:
为什么不使用剖切面作为渲染方法?
1) 使用改进的光线追踪算法,假设我们将 observer
放在点 Q
的原点 (0, 0, 0)
。
2) 然后让我们从原点向入射平面发射光线,该入射平面由分割分形的 y
和 z
点组合跨越。
3) 使用第1link中的算法计算到分形表面的距离。如果计算距离的 x
分量在一定公差范围内,即切片平面的 dx
,则 y
和 z
坐标以及 x
值切片平面存储为 x, y, z
坐标。这些坐标现在代表 x
中特定切片的表面。
4) 假设切片平面在x
方向上有一个自由度。通过在其自由度内移动平面,我们可以获得给定切片的另一组 x, y, z
坐标。
5) 最后的结果是由前面步骤创建的点云生成的可计算曲面。
6) 此外,可以更改切片平面的自由度以创建另一个点云,然后可以将其与之前的点云进行验证,作为 post-处理的一种方式.
请参阅下图作为视觉辅助(球体代表曼德尔球)。
下面是我的 Python 代码,改编自第一个 link。我成功生成了点平面,并且能够获得从原点到平面上的点的方向。距离估计器函数中一定存在根本性的缺陷,因为那是一切都崩溃的地方,我得到 nan
s 的总距离
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
我很想听听对此的想法以及 limitations/issues 我可能会遇到的事情。先谢谢您的帮助!
如果我没记错的话,这个算法也不是不可能。对 MandelBulb 的内部结构所做的任何假设以及允许观察者占据的位置都存在固有的潜在问题。也就是说,如果已知观察者最初处于会聚区域,则 return 的光线追踪算法没有任何意义,因为可以测量的最远距离为 0。这是由于当前光线跟踪算法在第一次接触表面时终止。然而,这很可能会被改变。
与其用平面 P
分割分形,更有意义的做法是防止光线在第一次接触时终止,而是根据已知存在于超过物体表面的距离终止曼德尔灯泡。
光线投射算法
MandelBulb Ray Casting Algorithm Python Example
因此,如果我理解正确的话,光线投射算法要求观察者位于 3D 分形之外,在该点矢量从观察者绘制到垂直于矢量并与原点相交的平面上的一点.
在我看来,这要么会严重限制分形的渲染视图,要么需要使用多个观察者位置对分形进行立体 3D 重建(这对我来说似乎很难)。此外,无法收集到有关分形内部结构的信息。
或者,直接体积渲染似乎足够直观,但计算成本高且本身可能效率低下。使用移动立方体等算法的间接体积渲染似乎也可能采用一些学习曲线。
在第二个 link 的 pdf 中的某个地方,它讨论了剖切面视图,以便查看分形切片。
问题:
为什么不使用剖切面作为渲染方法?
1) 使用改进的光线追踪算法,假设我们将
observer
放在点Q
的原点(0, 0, 0)
。2) 然后让我们从原点向入射平面发射光线,该入射平面由分割分形的
y
和z
点组合跨越。3) 使用第1link中的算法计算到分形表面的距离。如果计算距离的
x
分量在一定公差范围内,即切片平面的dx
,则y
和z
坐标以及x
值切片平面存储为x, y, z
坐标。这些坐标现在代表x
中特定切片的表面。4) 假设切片平面在
x
方向上有一个自由度。通过在其自由度内移动平面,我们可以获得给定切片的另一组x, y, z
坐标。5) 最后的结果是由前面步骤创建的点云生成的可计算曲面。
6) 此外,可以更改切片平面的自由度以创建另一个点云,然后可以将其与之前的点云进行验证,作为 post-处理的一种方式.
请参阅下图作为视觉辅助(球体代表曼德尔球)。
下面是我的 Python 代码,改编自第一个 link。我成功生成了点平面,并且能够获得从原点到平面上的点的方向。距离估计器函数中一定存在根本性的缺陷,因为那是一切都崩溃的地方,我得到 nan
s 的总距离
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
我很想听听对此的想法以及 limitations/issues 我可能会遇到的事情。先谢谢您的帮助!
如果我没记错的话,这个算法也不是不可能。对 MandelBulb 的内部结构所做的任何假设以及允许观察者占据的位置都存在固有的潜在问题。也就是说,如果已知观察者最初处于会聚区域,则 return 的光线追踪算法没有任何意义,因为可以测量的最远距离为 0。这是由于当前光线跟踪算法在第一次接触表面时终止。然而,这很可能会被改变。
与其用平面 P
分割分形,更有意义的做法是防止光线在第一次接触时终止,而是根据已知存在于超过物体表面的距离终止曼德尔灯泡。