反射镜角度的解析法
Analytic method for calculate a mirror angle
我在3D中有一个space固定的光线Lr
和一个可以围绕固定点Mrot
旋转的镜子M
,这个点不在镜子的同一平面,换句话说,镜子平面与以 Mrot
为中心、半径固定 d
的球体相切。使用该配置,我想找到一个方程式,该方程式接收点 P
作为参数,并随着 3D space.
中镜子的旋转而产生结果
我们可以认为镜像平面是没有边界的(无限平面),它的旋转是无限的。另外,镜子只在其旋转点的另一侧反射。
图中是输入点P1
和P2
不同的两种情况,分别有解角alpha1
和alpha2
。图片为2D,简化绘图,真实案例为3D。
此刻我正在计算随机旋转与镜面的交点,然后计算光线反射,看看离我想到达的点(P)有多远。最后迭代一些条件改变旋转直到它匹配。
显然这是一种矫枉过正,但我不知道如何以分析方式对其进行编码。
有什么想法吗?
注意:我注意到,如果镜子围绕其平面中的一个点 (Mrot) 旋转并且光线到达该点 (Mrot),我可以轻松计算出镜子角度,但不幸的是不是我的案件。
我会把它作为两个独立的平面问题来做(一个在 xy 平面上,第二个在 xz 或 yz 平面上)。我首先想到的是这个迭代过程:
开始
- 镜子以恒定距离围绕 Mrot 转动,形成圆(3D 球体)
- 所以计算 Lr 和球体的第一个交点
- 如果没有找到交点,则在球体上找到离 Lr 最近的点
- 计算
n0
法线为 Lr
和红线从交点到 P
的半角
- 这是镜像起始位置
将镜子(水绿色)放置到 n0
角度
- 计算
Lr
的反射
- 并计算半角
da0
这是新迭代的步骤
将 da0
添加到 n0
角度并将镜子放置到这个新的角度位置
- 计算
Lr
的反射
- 并计算半角
da1
这是新迭代的步骤
循环项目符号 3 直到
da(i)
够小
- 达到最大迭代次数
[备注]
- 这应该比 random/linear 探测
更快地收敛到解决方案
- P离镜子越远(或旋转半径越小)收敛越快
- 不确定这个问题的解析解是否存在它看起来会导致超越系统...
首先注意这里只有一个参数,即光线到达镜子的距离t
。
任意测试值t
,依次计算
- 发生反射的点。
- 入射光线和反射光线的矢量。
- 镜子的法向量,通过取归一化入射向量和反射向量的平均值得到。连同 1,你现在知道镜子的平面了。
- 镜子到旋转点的距离
d
现在的问题是选择t
使d
取想要的值。这归结为t
中的一个八进制多项式,所以没有解析公式[1],唯一的解决办法就是迭代 .[2]
这是一个代码示例:
vec3 r; // Ray start position
vec3 v; // Ray direction
vec3 p; // Target point
vec3 m; // Mirror rotation point
double calc_d_from_t(double t)
{
vec3 reflection_point = r + t * v;
vec3 incident = normalize(-v);
vec3 reflected = normalize(p - reflection_point);
vec3 mirror_normal = normalize(incident + reflected);
return dot(reflection_point - m, mirror_normal);
}
现在将 calc_d_from_t(t) = d
传递给您最喜欢的根查找器,确保使用 t > 0
找到根。任何像样的求根器(例如 Newton-Raphson)都应该比您当前的方法快得多。
[1] 即涉及算术运算、n 次根和系数的公式。
[2] 除非八进制因式分解相同,否则可能会将问题简化为四次。
我在3D中有一个space固定的光线Lr
和一个可以围绕固定点Mrot
旋转的镜子M
,这个点不在镜子的同一平面,换句话说,镜子平面与以 Mrot
为中心、半径固定 d
的球体相切。使用该配置,我想找到一个方程式,该方程式接收点 P
作为参数,并随着 3D space.
我们可以认为镜像平面是没有边界的(无限平面),它的旋转是无限的。另外,镜子只在其旋转点的另一侧反射。
图中是输入点P1
和P2
不同的两种情况,分别有解角alpha1
和alpha2
。图片为2D,简化绘图,真实案例为3D。
此刻我正在计算随机旋转与镜面的交点,然后计算光线反射,看看离我想到达的点(P)有多远。最后迭代一些条件改变旋转直到它匹配。
显然这是一种矫枉过正,但我不知道如何以分析方式对其进行编码。
有什么想法吗?
注意:我注意到,如果镜子围绕其平面中的一个点 (Mrot) 旋转并且光线到达该点 (Mrot),我可以轻松计算出镜子角度,但不幸的是不是我的案件。
我会把它作为两个独立的平面问题来做(一个在 xy 平面上,第二个在 xz 或 yz 平面上)。我首先想到的是这个迭代过程:
开始
- 镜子以恒定距离围绕 Mrot 转动,形成圆(3D 球体)
- 所以计算 Lr 和球体的第一个交点
- 如果没有找到交点,则在球体上找到离 Lr 最近的点
- 计算
n0
法线为Lr
和红线从交点到P
的半角
- 这是镜像起始位置
将镜子(水绿色)放置到
n0
角度- 计算
Lr
的反射
- 并计算半角
da0
这是新迭代的步骤
- 计算
将
da0
添加到n0
角度并将镜子放置到这个新的角度位置- 计算
Lr
的反射
- 并计算半角
da1
这是新迭代的步骤
- 计算
循环项目符号 3 直到
da(i)
够小- 达到最大迭代次数
[备注]
- 这应该比 random/linear 探测 更快地收敛到解决方案
- P离镜子越远(或旋转半径越小)收敛越快
- 不确定这个问题的解析解是否存在它看起来会导致超越系统...
首先注意这里只有一个参数,即光线到达镜子的距离t
。
任意测试值t
,依次计算
- 发生反射的点。
- 入射光线和反射光线的矢量。
- 镜子的法向量,通过取归一化入射向量和反射向量的平均值得到。连同 1,你现在知道镜子的平面了。
- 镜子到旋转点的距离
d
现在的问题是选择t
使d
取想要的值。这归结为t
中的一个八进制多项式,所以没有解析公式[1],唯一的解决办法就是迭代 .[2]
这是一个代码示例:
vec3 r; // Ray start position
vec3 v; // Ray direction
vec3 p; // Target point
vec3 m; // Mirror rotation point
double calc_d_from_t(double t)
{
vec3 reflection_point = r + t * v;
vec3 incident = normalize(-v);
vec3 reflected = normalize(p - reflection_point);
vec3 mirror_normal = normalize(incident + reflected);
return dot(reflection_point - m, mirror_normal);
}
现在将 calc_d_from_t(t) = d
传递给您最喜欢的根查找器,确保使用 t > 0
找到根。任何像样的求根器(例如 Newton-Raphson)都应该比您当前的方法快得多。
[1] 即涉及算术运算、n 次根和系数的公式。
[2] 除非八进制因式分解相同,否则可能会将问题简化为四次。