haskell - 光线追踪并找到交点处表面的法向量

标签 haskell haskell-diagrams

使用 rayTraceP 进行光线追踪时,我可以找到射线与图相交的点。

> rayTraceP (p2 (0, 0)) (r2 (1, 0)) ((p2 (1,-1) ~~ p2 (1,1))
Just (p2 (1.0, 0.0))

我想用它不仅可以找到“碰撞点”,还可以找到碰撞时间和该点表面的法向矢量。

-- A Collision has a time, a contact point, and a normal vector.
-- The normal vector is perpendicular to the surface at the contact
-- point.
data Collision v n = Collision n (Point v n) (v n)
  deriving (Show)

给定射线的起点和沿射线的速度矢量,我可以使用rayTraceP找到接触点end :

end <- rayTraceP start vel dia

我可以使用 startend 之间的距离找到碰撞时间:

time = distance start end / norm vel

但我一直在寻找法线向量。我正在这个函数中工作:

rayTraceC :: (Metric v, OrderedField n)
             => Point v n -> v n -> QDiagram B v n Any -> Maybe (Collision v n)
-- Takes a starting position for the ray, a velocity vector for the
-- ray, and a diagram to trace the ray to. If the ray intersects with
-- the diagram, it returns a Collision containing:
--  * The amount of time it takes for a point along the ray going at
--    the given velocity to intersect with the diagram.
--  * The point at which it intersects with the diagram.
--  * The normal vector to the surface at that point (which will be
--    perpendicular to the surface there).
-- If the ray does not intersect with the diagram, it returns Nothing.
rayTraceC start vel dia =
  do
    end <- rayTraceP start vel dia
    let time = distance start end / norm vel
    -- This is where I'm getting stuck. 
    -- How do I find the normal vector?
    let normalV = ???
    return (Collision time end normalV)

我想要它做什么的一些例子:

> -- colliding straight on:
> rayTraceC (p2 (0, 0)) (r2 (1, 0)) (p2 (1,-1) ~~ p2 (1,1))
Just (Collision 1 (p2 (1, 0)) (r2 (-1, 0)))
> -- colliding from a diagonal:
> rayTraceC (p2 (0, 0)) (r2 (1, 1)) (p2 (1,0) ~~ p2 (1,2))
Just (Collision 1 (p2 (1, 1)) (r2 (-1, 0))
> -- colliding onto a diagonal:
> rayTraceC (p2 (0, 0)) (r2 (1, 0)) (p2 (0,-1) ~~ p2 (2,1))
Just (Collision 1 (p2 (1, 0)) (r2 (-√2/2, √2/2)))
> -- no collision
> rayTraceC (p2 (0, 0)) (r2 (1, 0)) (p2 (1,1) ~~ p2 (1,2))
Nothing

除了法向量之外,这些示例中的所有内容都是正确的。

我查看了 Diagrams.Trace 的文档和 Diagrams.Core.Trace ,但也许我找错了地方。

最佳答案

一般来说没有办法做到这一点;这取决于你到底击中了什么。有一个模块Diagrams.Tangent用于计算轨迹的切线,但要计算给定点的切线,您必须知道其相对于轨迹的参数;目前我们缺少的一件事是一种从给定点转换为给定段/踪迹/路径上最近点的参数的方法(它已经在待办事项列表上有一段时间了)。

梦想更大,也许痕迹本身应该返回更多信息——不仅是参数告诉您击中的光线有多远,还包括有关您击中的内容的信息(从中可以更轻松地执行诸如计算法向量)。

您正在计算哪些事物的痕迹?可能有一种方法可以利用您的用例的特定细节,以一种不太糟糕的方式获得您想要的法线。

关于haskell - 光线追踪并找到交点处表面的法向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52028449/

相关文章:

haskell - 打印状态值进行调试

haskell - 理解 Comonad 的 <$$>

haskell - 如何通过集合运算组合形状?

Haskell 图 : arrows with fixed orientation

对交换元素有效的 Haskell 数据结构?

haskell - 如何比较两个函数的等价性,如 (λx.2*x) == (λx.x+x)?

haskell - 为什么预定义的 `const` 函数在某些上下文中的行为与等效的 lambda 函数不同?

haskell - 修复箭头轴(图表库)

haskell - 使用 haskell 图表包设置 id 和 class