我正在构建一个简单的光线追踪器用于教育目的,并希望为对象添加折射。使用斯内尔斯定律,我能够在交点处递归地创建新射线。光线追踪器目前仅支持球体,我使用的场景中有多个球体嵌套在彼此内部,具有不同的折射率。
如果我从球体外部发出光线,一切看起来都很简单。从场景的折射率开始,一旦击中第一个球体,就使用之前的折射率和球体材质的折射率来折射光线,直到击中下一个球体,依此类推。使用交点的法线我可以确定是否进入或离开球体。
但是,我不明白应该如何处理球体叶子,以及如果光线不是从场景的外部开始该怎么办。
- 我可以只取一堆折射率并在离开球体后立即向上一层吗?
- 如果我从球体内部开始,如何确定必须从什么折射率开始?
示例
您有三个球体,从外到内的折射率分别为 0.9、1.1 和 0.8。空气指数为 1.0
-
您的相机位于球体外部并指向球体中心:
- 起始折射率为 1.0,您首先撞击折射率为 0.9 的外球体,并从 1.0 折射到 0.9,然后保存光线现在处于 0.9 材质
- 您击中了中间的球体,注意到材质常数为 1.1,因为您已经保存了 0.9,所以您知道必须从 0.9 折射到 1.1,并除了 0.9 之外还保存 1.1
- 您击中内部球体并从 1.1 折射到 0.8,并且到目前为止您已保存 0.9、1.1 和 0.8
- 您再次点击内部球体(这次您退出了它,因此您检查了保存的值并知道您必须切换回 1.1)
- ...直到你走到外面
- < p>现在的问题是,当相机位于球体内部时。您将不知道必须切换到什么折射率。
I am building a simple raytracer for educational purposes and want to add refraction to objects. Using Snells Law, I am able to create a new ray recursively at the intersection points. The raytracer supports currently only spheres and I use a scene where I have multiple spheres nested inside of each other with different refraction indices.
If I start a ray from outside of the spheres, everything seems simple. You start with the refraction index of the scene, and as soon as you hit the first sphere, refract the ray using the refraction index before and the refraction index of the material of the sphere until you hit the next sphere and so on. Using the normals of the intersection I can determine whether I enter or leave the sphere.
However, I don't understand how I should handle sphere leaves and what to do if the ray doesn't start in the outer part of the scene.
- Can I just take a stack of the refraction indices and go one layer up as soon as I leave a sphere?
- How can I determine with what refraction index I have to start if I start inside of the spheres?
Example
You have three spheres, with refraction indices 0.9, 1.1 and 0.8 from outer to inner. Air index is 1.0
-
Your camera is outside of the sphere and points at the center of the sphere:
- start index is 1.0, you first hit the outer sphere with index 0.9 and refract from 1.0 to 0.9 and save that your ray is now in 0.9 material
- you hit the middle sphere and notice the material constant of 1.1, since you have saved the 0.9, you know that you have to refract from 0.9 to 1.1 and save the 1.1 in addition to the 0.9
- you hit the inner sphere and refract from 1.1 to 0.8 and you have save until now 0.9, 1.1 and 0.8
- you hit the inner sphere again (this time you exit it, so you check your saved values and know that you have to switch back to 1.1)
- ... until you are outside
-
Problem now, when the camera is inside the sphere. You won't know to what refraction index you have to switch.
发布评论
评论(2)
我有一个类似的光线追踪器(用 Python 编写),并偶然发现了同样的问题:为了正确计算物理原理,必须知道相交边界每一侧的折射率。这花了相当长的时间才能优雅地解决,但最终我采用了这个解决方案/设计:
设计
1)场景 - 我有一个主场景对象(基本上是场景中所有对象的数组) ),你可能会有类似的东西。它存储几何对象。
方法:
containing_object(ray)
- 返回包含光线的对象。objects()
- 以任意顺序返回所有对象的列表。注意:场景向列表中添加了一个额外的对象:Scene_Boundary。这是一个巨大的盒子(或球体),封装了整个场景,即一切都在这个边界内。
2) 对象——使几何对象(例如球体)实现这些方法。
方法:
contains(ray)
- 如果光线原点位于对象内部,则返回 True;如果在表面,则返回 False;如果在ray_is_on_surface(ray)
外部,则返回 False code> - 如果光线仅在表面上,则返回 True,否则返回 False。intersection_points(ray)
- 返回光线与物体的交点surface_normal(ray)
- 返回光线撞击表面的表面法向量(这将有助于菲涅耳反射和折射)对于光学计算,物体还必须具有折射率。
实例变量:
refractive_index
边界问题
我们要解决的问题:边界内部(n1)和外部(n2)的折射率是多少?为此,我们遵循以下步骤:
1) 在整个场景中追踪光线:
请记住,这些光线是按距光线原点的距离排序的。 ipoints 和 iobjects 中的最后一项是光线与场景边界的交点。我们稍后会用到它!
2) 只需通过查找包含对象即可找到 n1,例如:
3) 通过在 iobject 列表中向前查找一个对象来找到 n2,例如用伪代码:
4) 获取表面法线以后使用:
您拥有计算正确的反射和折射所需的所有信息。即使光线位于物体外部,这也足够通用,但有时我确实需要实现一些逻辑过滤以使算法更加稳健,但基本上就是这样!
反射和折射
只需了解表面法线即可反射矢量。在Python中使用numpy我这样做,
折射(如讨论的)需要n1和n2值:
最后你需要计算光线的反射系数,其中角度是光线方向和表面法线(假设您的光线是“非偏振”)。将其与 0 到 1 之间的随机数进行比较,以确定是否发生反射。
最终评论
这一切都来自我的 Python 光学光线追踪项目,该项目尚未发布(!),但您可以在此处查看一些详细信息:http://daniel.farrell.name/freebies/pvtrace。我喜欢Python!这里列出了许多 Python 光线追踪项目,http://groups.google.com/group/python-ray-tracing-community/web/list-of-python-statistical-ray-tracers 。最后,请注意示例中的分数折射率,方程将崩溃。
更新
在我的光线追踪器中实现的屏幕截图,可在 http://github.com/ 获取丹尼尔法雷尔/pvtrace
I have a similar ray tracer (written in Python) and stumbled over the same problem: in order to correctly work out the physics one must know the refractive index at each side of the intersection boundary. This took quite a while to solve elegantly, but in the end I went with this solution/design:
Design
1) Scene -- I have a master scene object (basically an array of all objects in the scene), you will probably have something similar. It stores geometrical objects.
Methods:
intersection_points(ray)
- returns a list of all intersection points, sorted by distance from the ray.intersection_objects(ray)
- returns a list of all intersection objects, sorted by distance from the ray.containing_object(ray)
- returns the object that contains the ray.objects()
- returns a list of all the objects in arbitrary order.Note: The scene adds an extra object to the list: the Scene_Boundary. This is a giant box (or Sphere) that encapsulate the whole scene i.e. EVERYTHING is inside this boundary.
2) Objects -- Make the geometric objects (e.g. your sphere) implement these methods.
Methods:
contains(ray)
- returns True is the ray origin is inside the object, False if on the surface and False if outsideray_is_on_surface(ray)
- returns True is the ray is on the surface only, otherwise False.intersection_points(ray)
- returns the intersection point(s) that the ray makes with the objectsurface_normal(ray)
- returns the surface normal vector of the surface which the ray struck (this will help with Fresnel reflection and refraction)For optical calculations the objects must also have a refractive index.
Instance variables:
refractive_index
Boundary Problem
The problem we want to solve: what is the refractive index inside (n1) and outside (n2) of the boundary? To do this we follow this procedure:
1) Trace the ray through the whole scene:
Remember these are sorted by distance from the ray origin. The last item in ipoints and iobjects is the intersection the ray makes with the scene boundary. We will use this later!
2) n1 is found simply by finding the containing object, e.g.:
3) n2 is found by looking one object ahead in the iobject list, e.g. in pseudocode:
4) Get the surface normal for later use:
You have all the information you need to calculate the correct reflection and refraction. This is general enough to work even if the ray is outside the object, but occasionally I did need to implement some logical filtering to make the algorithm more robust, but that's basically it!
Reflection and Refraction
You can reflect a vector just by knowing the surface normal. In Python using numpy I do it like this,
Refraction (as discussed) needs n1 and n2 values:
Finally you will need to calculate the reflection coefficient for the ray where angle is the angle between the ray direction and the surface normal (this assumed your ray is 'unpolarised'). Compare this with a random number between 0 and 1 to decide if reflection occurs.
Final comments
This all comes from my Python optical ray tracing project which is not yet released(!), but you can check here for some detail: http://daniel.farrell.name/freebies/pvtrace. I like Python! There are a number of Python ray tracing projects listed here, http://groups.google.com/group/python-ray-tracing-community/web/list-of-python-statistical-ray-tracers . Finally, be careful with fractional refractive indices in your example, the equation will breakdown.
Update
Screenshot of this implemented in my ray tracer, available at http://github.com/danieljfarrell/pvtrace
从物理角度而不是光线追踪实现角度发布此内容:P。
斯涅尔定律指出,入射角和折射角的正弦之比等于边界两侧两种介质的折射率之比的倒数。
因此,当光线接近新材料并且想要知道新材料中的角度时,您需要知道光线撞击新材料的角度、新材料的折射率以及折射率光线当前所在材质的折射率。
正如您所说,折射在进入球体时效果很好,您必须已经知道每个球体和场景的折射率。
我想说,创建一堆折射率是处理进入一堆嵌套材料的好方法,因为当您移出时,您将不得不再次接触推入堆栈的所有折射率嵌套的球体集。
至于确定离开球体时必须从什么折射率开始,您总是说 sin(theta1)/sin(theta2) = [折射率 2]/[折射率 1]。因此,您需要当前所在材料的折射率以及您将要移动的材料的折射率。
如果我误解了你的问题,我深表歉意,但希望能有所帮助!
Posting this from a physics point of view and not a raytracing implementation point of view :P.
Snell's law states that the ratio of the sines of the incident angle and the refractive angle are equal to the inverse of the ratio of the refractive index of the two mediums on either side of the boundary.
Thus, when you have a ray approaching a new material and you want to know the angle in the new material, you need to know the angle that the ray is hitting the new material, the index of refraction of the new material, and the index of refraction of the material the ray is currently in.
As you say refraction works fine moving into the sphere, you must know the index of refraction of each sphere and your scene already.
I'd say creating a stack of refractive indices would be a good way to deal with going into a bunch of nested materials, as you're going to have to touch all the refractive indexes that you push onto the stack again as you move out of the nested set of spheres.
As to determining what refractive index you have to start with as you leave the spheres, you're always saying sin(theta1)/sin(theta2) = [refractive index of 2]/[refractive index of 1]. Thus, you need the refractive index of the material that you're currently in and the index of the material that you're going to be moving towards.
Apologies if I misunderstood your question, but I hope that helps!