代码之家  ›  专栏  ›  技术社区  ›  Etan bbum

如何处理光线从嵌套对象内部开始时的折射

  •  5
  • Etan bbum  · 技术社区  · 15 年前

    如果我从球体外面开始一条光线,一切看起来都很简单。从场景的折射率开始,一旦击中第一个球体,就使用前面的折射率和球体材质的折射率折射光线,直到击中下一个球体,依此类推。使用交点的法线,我可以确定是否进入或离开球体。

    但是,我不明白应该如何处理球体叶子,以及如果光线没有从场景的外部开始,该怎么办。

    • 当我离开一个球体的时候,我能把一堆折射率放到上面一层吗?
    • 如果从球体内部开始,如何确定折射率?

    例子

    • 您的相机位于球体外部,并指向球体的中心:

      • “开始索引”(start index)为1.0,首先使用“索引”(index)0.9撞击外部球体,并从1.0折射到0.9,然后保存光线现在处于0.9材质中
      • 点击中间的球体并注意到材质常数为1.1,因为保存了0.9,所以必须从0.9折射到1.1,并且除了保存0.9之外还要保存1.1
      • 再次命中内部球体(这次退出它,因此检查保存的值并知道必须切换回1.1)
      • ... 直到你在外面
    2 回复  |  直到 14 年前
        1
  •  1
  •   johnw188    15 年前

    斯奈尔定律认为入射角和折射角的正弦之比等于边界两侧两种介质的折射率之比的倒数。

    正如您所说的折射效果很好移动到球体中,您必须已经知道每个球体和场景的折射率。

    我想说,创建一个折射率堆栈将是一个很好的方法来处理进入一堆嵌套的材料,因为你将不得不接触所有的折射率,你推到堆栈再次作为你搬出嵌套的球体集。

    当你离开球体时,首先要确定折射率,你总是说sin(θ1)/sin(θ2)=[折射率2]/[折射率1]。因此,你需要你现在所处的材质的折射率和你将要移动的材质的折射率。

    抱歉,如果我误解了你的问题,但我希望这有帮助!

        2
  •  9
  •   Daniel Farrell Jlondono    13 年前

    我有一个类似的光线跟踪器(用Python编写),遇到了同一个问题:为了正确地计算出物理,必须知道相交边界两边的折射率。这花了很长时间才优雅地解决,但最终我还是采用了这个解决方案/设计:

    设计

    • intersection_points(ray) -返回所有交点的列表,按与射线的距离排序。
    • intersection_objects(ray)
    • containing_object(ray) -返回包含光线的对象。
    • objects() -按任意顺序返回所有对象的列表。

    场景会向列表中添加一个额外的对象:对象 场景边界

    2) 对象——使几何对象(如球体)实现这些方法。

    :

    • contains(ray) -如果光线原点位于对象内部,则返回True;如果光线原点位于曲面上,则返回False;如果光线原点位于对象外部,则返回False
    • ray_is_on_surface(ray)
    • 交点(射线) -返回光线与对象的交点
    • surface_normal(ray)

    对于光学计算,物体也必须有折射率。

    实例变量:

    • refractive_index

    我们要解决的问题是:边界内外的折射率是多少?为此,我们遵循以下步骤:

    1) 在整个场景中追踪光线:

    sphere # origin = (0,0,0), radius = 1
    ray  # origin = (0,0,0), direction = (0,0,1) Note: the ray is inside the sphere
    scene.add_object(sphere)
    ipoints = scene.intersection_points(ray) #  [ (0,0,1), (0,0,10) ]
    iobjects = scene.intersection_objects(ray) # [ Sphere, Scene_Boundary]
    

    请记住,这些是按距离射线原点的距离排序的。ipoints和ioobjects中的最后一项是光线与场景边界的交集。我们以后用这个!

    2) n1只需找到包含的对象即可找到,例如:

    obj1 = scene.containing_object(ray) # Scene_Boundary
    n1 = obj1.refractive_index() # n1 = 1. Scene_Boundary always has refractive index of Air
    

    index = iobjects.index_of_object(obj1)
    obj2 = iobjects[index+1]
    n2 = obj2.refractive_index() # n2 = 1.5 e.g. Glass
    

    4) 获取曲面法线以备以后使用:

    normal = obj1.surface_normal(ray)
    

    您拥有计算正确的反射和折射所需的所有信息。即使光线在对象之外,这也足够通用,但偶尔我确实需要实现一些逻辑过滤,以使算法更健壮,但基本上就是这样!

    反射和折射

    def reflect_vector(normal, vector):
       d = numpy.dot(normal, vector)
       return vector - 2 * d * normal
    

    折射(如上所述)需要n1和n2值:

    def fresnel_refraction(normal, vector, n1, n2):
        n = n1/n2
        dot = np.dot(norm(vector), norm(normal))
        c = np.sqrt(1 - n**2 * (1 - dot**2))
        sign = 1
        if dot < 0.0:
            sign = -1
        refraction = n * vector + sign*(c - sign*n*dot) * normal
        return norm(refraction)
    

    最后,需要计算光线的反射系数

    def fresnel_reflection(angle, n1, n2):
        assert 0.0 <= angle <= 0.5*np.pi, "The incident angle must be between 0 and 90 degrees to calculate Fresnel reflection."
        # Catch TIR case
        if n2 < n1:
            if angle > np.arcsin(n2/n1):
                return 1.0
    
        Rs1 = n1 * np.cos(angle) - n2 * np.sqrt(1 - (n1/n2 * np.sin(angle))**2)
        Rs2 = n1 * np.cos(angle) + n2 * np.sqrt(1 - (n1/n2 * np.sin(angle))**2)
        Rs = (Rs1/Rs2)**2
        Rp1 = n1 * np.sqrt(1 - (n1/n2 * np.sin(angle))**2) - n2 * np.cos(angle)
        Rp2 = n1 * np.sqrt(1 - (n1/n2 * np.sin(angle))**2) + n2 * np.cos(angle)
        Rp = (Rp1/Rp2)**2
        return 0.5 * (Rs + Rp)
    

    最后评论

    这些都来自我的Python光学光线跟踪项目,该项目尚未发布(!),但您可以在此处查看一些详细信息: http://daniel.farrell.name/freebies/pvtrace . 我喜欢蟒蛇!这里列出了许多Python光线跟踪项目, http://groups.google.com/group/python-ray-tracing-community/web/list-of-python-statistical-ray-tracers . 最后,在你的例子中要小心分数折射率,方程会崩溃。

    更新

    http://github.com/danieljfarrell/pvtrace alt text