3D分形切片渲染方法的验证

时间:2018-10-31 01:19:14

标签: python rendering point-clouds raycasting fractals

射线投射算法

MandelBulb Ray Casting Algorithm Python Example

因此,如果我理解正确,射线投射算法要求将观察者置于3D分形的外部,在该点上从观察者向矢量的法线平面上与该点相交的点绘制矢量。

在我看来,这要么严重限制分形的渲染视图,要么要求使用多个观察者位置进行分形的立体3D重建(这对我来说似乎很困难)。此外,无法收集有关分形内部结构的信息。

Other Algorithms

或者,直接体积渲染似乎足够直观,但是,计算量很大,并且本身效率低下。使用诸如行进多维数据集之类的算法进行间接体积渲染可能还会使用一些学习曲线。

在第二个链接的pdf中的某个地方,它讨论了剖切平面视图,以便查看分形的切片。

问题:

为什么不使用切面作为渲染方法?

  • 1)使用一种改进的光线跟踪算法,假设我们将observer放在原点Q (0, 0, 0) 点。

  • 2)然后让我们从原点向入射面发出由yz点组合划分的光线,该点组合将分形切成薄片。

  • 3)使用第一个链接中的算法计算到分形表面的距离。如果计算距离的x分量在切片平面的dx的一定公差内,则yz的坐标与x值一起切片平面的坐标值存储为x, y, z坐标。现在,这些坐标表示x中该特定切片处的表面。

  • 4)假设切片平面在x方向上具有一个自由度。通过以自由度移动平面,我们可以接收给定切片的另一组x, y, z坐标。

  • 5)最终结果是由前面步骤中创建的点云生成的可计算表面。

  • 6)此外,可以更改切片平面的自由度以创建另一个点云,然后可以将其与先前的点云进行验证,作为后处理的一种方法。

请参阅下面的图像作为视觉辅助(球形代表MandelBulb)。

enter image description here

下面是到目前为止的我的Python代码,改编自第一个链接。我成功地生成了点平面,并且能够获得从原点到平面上点的方向。距离估算器函数中肯定存在一些根本缺陷,因为那是一切都崩溃了,我得到了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

我很想听听对此的想法以及我可能遇到的限制/问题。先谢谢您的帮助!

1 个答案:

答案 0 :(得分:0)

如果我没记错的话,这种算法并非不可能。关于曼德尔灯泡的内部结构以及允许观察者占据什么位置的任何假设,都存在潜在的问题。也就是说,如果已知观察者最初处于会聚区域,则光线跟踪算法不会返回任何有意义的内容,因为可以测量的最远距离为0。这是由于当前的光线跟踪算法终止于首先接触表面。但是,这很可能会更改。

与其在平面P上切分形,不如在第一次接触时阻止射线终止,而是根据已知的超过MandelBulb表面的距离终止射线。