1 叉乘是什么
先简单介绍一下叉乘(cross product)
:
a
→
×
b
→
\overrightarrow{a} \times \overrightarrow{b}
a×b,其结果,还是一个向量。
其方向,符合右手螺旋定则(右手手指头从a转向b,看大拇指指向哪里);
其模,等于
∣
a
→
∣
∣
b
→
∣
s
i
n
θ
|\overrightarrow{a}||\overrightarrow{b}|sin\theta
∣a∣∣b∣sinθ (其实就是a和b组成的平行四边形面积)
也可以直接用下面的式子表示:
a
→
×
b
→
=
∣
i
→
j
→
k
→
a
x
a
y
a
z
b
x
b
y
b
z
∣
=
(
a
y
b
z
−
a
z
b
y
)
i
→
+
(
a
z
b
x
−
z
x
b
z
)
j
→
+
(
a
x
b
y
−
a
y
b
x
)
k
→
\overrightarrow{a} \times \overrightarrow{b} = \left | \begin{matrix} \overrightarrow{i} & \overrightarrow{j} & \overrightarrow{k}\\ a_x & a_y & a_z\\ b_x & b_y & b_z \end{matrix} \right | = (a_ybz - a_zb_y)\overrightarrow{i} + (a_zb_x - z_xb_z)\overrightarrow{j} + (a_xb_y - a_yb_x)\overrightarrow{k}
a×b=
iaxbxjaybykazbz
=(aybz−azby)i+(azbx−zxbz)j+(axby−aybx)k
其中,
i
→
,
j
→
,
k
→
\overrightarrow{i}, \overrightarrow{j}, \overrightarrow{k}
i,j,k是3个轴的单位向量
。
他的重要性质:
a
→
×
a
→
=
0
→
\overrightarrow{a} \times \overrightarrow{a} = \overrightarrow{0}
a×a=0
a
→
×
b
→
=
−
b
→
×
a
→
\overrightarrow{a} \times \overrightarrow{b} = - \overrightarrow{b} \times \overrightarrow{a}
a×b=−b×a
a
→
×
(
b
→
+
c
→
)
=
a
→
×
b
→
+
a
→
×
c
→
\overrightarrow{a} \times (\overrightarrow{b} + \overrightarrow{c}) = \overrightarrow{a} \times \overrightarrow{b} + \overrightarrow{a} \times \overrightarrow{c}
a×(b+c)=a×b+a×c
2 几何意义
在图形学中,向量的叉乘主要用于计算两个向量所在平面的法向量,以及计算出相机朝向和物体朝向之间的旋转轴,具体应用包括:
-
计算表面法向量:通过计算两个相邻的三角形的法向量来得到表面法向量,可以用于光照计算和渲染中的纹理映射等。
-
计算相机朝向和物体朝向之间的旋转轴:在相机跟随和相机旋转等操作中使用。
-
计算三角形面积:通过向量叉积的模长可以计算三角形面积,可以用于计算多边形的面积和法向量。
-
计算向量夹角:通过向量叉积的模长和点积的结果可以计算向量之间的夹角,可以用于计算光源和物体的夹角以及阴影的计算等。
-
判断一个点是否在三角形内
下文针对5,具体讲一下如何使用。
3 使用例子- 判断一个点是否在三角形内
3.1 使用背景
判断一个点,是否在三角形内,有什么用途呢?一个经典的用途是,在光栅化阶段,GPU会去挨个处理每个像素,应该显示什么数据,或者说,显示哪个三角形面的数据。
咱们来最简化的描述这个过程:
假色我们的3D画面非常简单,只有4个顶点,即2个三角形,映射到屏幕上,如下图所示
现在开始扫描每个像素该显示啥。方法就是,判断是否在2个三角形内,如果不在,就显示默认色了,如果在,就采样三角形的对应纹理色值。
所以,现在的问题,就可以归纳为一个函数:
isInTringle(Trangle tr)
3.2 如何判断
请看下面一组图,Q点在三角形内,可以看看有什么规律:
向量P1P2与P1Q,右手螺旋定则,朝外;
向量P2P3与P2Q,右手螺旋定则,朝外;
向量P3P1与P3Q,右手螺旋定则,朝外;
再看一组图,Q点在三角形外:
向量P1P2与P1Q,右手螺旋定则,朝内
;
向量P2P3与P2Q,右手螺旋定则,朝外;
向量P3P1与P3Q,右手螺旋定则,朝外;
极端情况,如果Q刚好在三角形的边上,例如P1P2的边上,那么,向量P1P2与P1Q为同方向,螺旋定则芭比Q了,找不到z轴方向,即,z值为0。
结论:只要计算三次叉乘,如果z值有一个为0,则在三角形边上; 如果z值正负一致,则在里面;如果z值正负不一致,则在外面
3.3 代码实现
从第一节可知,计算叉乘的
z
z
z值,很简单,为
(
a
x
b
y
−
a
y
b
x
)
(a_xb_y - a_yb_x)
(axby−aybx)
所以,从程序上,可以非常简单的实现了,我们来写个python:
#!/usr/bin/python
#这是一个判断一个点是否在三角形内的例子
print("Hello, World! Let's do some test");
def check_signs(a, b, c):
"""
判断三个浮点数的符号
:param a: 第一个浮点数
:param b: 第二个浮点数
:param c: 第三个浮点数
:return: True 如果三个数都为正数或都为负数,True 否则False
"""
if a > 0 and b > 0 and c > 0:
return True
if a < 0 and b < 0 and c < 0:
return True
return False
def cal_z_value(v1, v2):
"""
计算2个三维向量,叉乘的z值
"""
return v1[0] * v2[1] - v1[1]* v2[0]
def subtract_vectors(vector1, vector2):
"""
计算两个三维向量的差向量
:param vector1: 第一个向量,格式为 [x, y, z]
:param vector2: 第二个向量,格式为 [x, y, z]
:return: 差向量,格式为 [x, y, z]
"""
x = vector1[0] - vector2[0]
y = vector1[1] - vector2[1]
z = vector1[2] - vector2[2]
return [x, y, z]
def is_point_in_triangle(p1, p2, p3, q):
"""
判断一个点是否在某个三角形内
"""
p1_q = subtract_vectors(q, p1)
p1_p2 = subtract_vectors(p2, p1)
z1 = cal_z_value(p1_p2, p1_q)
p2_q = subtract_vectors(q, p2)
p2_p3 = subtract_vectors(p3, p2)
z2 = cal_z_value(p2_p3, p2_q)
p3_q = subtract_vectors(q, p3)
p3_p1 = subtract_vectors(p1, p3)
z3 = cal_z_value(p3_p1, p3_q)
print("z1 ",z1)
print("z2 ",z2)
print("z3 ",z3)
return check_signs(z1, z2, z3)
"""
p1=[0, 0, 0]
p2=[0.5, 0.5, 0]
p3=[0.5, 1, 0]
q=[0.25, 0.5, 0]
"""
#测试代码
p1=[0, 0, 0]
p2=[1, 0, 0]
p3=[0.5, 1, 0]
q=[0.25, 0.35, 0]
result = is_point_in_triangle(p1, p2, p3, q)
print("result ",result)