我有三个顶点构成3D空间中的平面/多边形,v0,v1& V2。
要计算此平面上3D点的重心坐标,我必须先将平面和点投影到2D空间。
在浏览网页后,我非常了解如何计算2D空间中的重心坐标,但我仍然坚持找到将3D点投影到合适的2D平面的最佳方法。
有人告诉我,实现这一目标的最佳方法是“以最小的投影”放下轴。如果不测试在每个世界轴(xy,yz,xz)上投影时形成的多边形区域,我如何确定哪个投影最佳(具有最大面积),因此最适合计算最精确的重心坐标?
答案 0 :(得分:2)
根据OP的要求计算3D空间中的重心坐标的示例。给出:
“x”表示两个3D矢量之间的叉积 “len”表示3D矢量的长度 “u”,“v”,“w”分别是属于v0,v1和v2的重心坐标。
triArea = len((v1 - v0) x (v2 - v0)) * 0.5
u = ( len((v1 - p ) x (v2 - p )) * 0.5 ) / triArea
v = ( len((v0 - p ) x (v2 - p )) * 0.5 ) / triArea
w = ( len((v0 - p ) x (v1 - p )) * 0.5 ) / triArea
=> p == u * v0 + v * v1 + w * v2
交叉产品的定义如下:
v0 x v1 := { v0.y * v1.z - v0.z * v1.y,
v0.z * v1.x - v0.x * v1.z,
v0.x * v1.y - v0.y * v1.x }
答案 1 :(得分:2)
警告 - 昨天我学到了几乎所有关于使用重心坐标和使用矩阵求解线性方程的知识,因为我发现这个问题非常有趣。所以以下可能是错误的,错误的,错误的 - 但是我已经放入的一些测试值似乎可以工作。 男孩和女孩,如果我完全搞砸了,请随意把它拆开 - 但是这里有。
在3D空间中找到重心坐标(在维基百科的帮助下)
假设:
v0 = (x0, y0, z0)
v1 = (x1, y1, z1)
v2 = (x2, y2, z2)
p = (xp, yp, zp)
找到重心坐标: 相对于由v0,v1和v2
定义的三角形的点p的b0,b1,b2知道:
xp = b0*x0 + b1*x1 + b2*x2
yp = b0*y0 + b1*y1 + b2*y2
zp = b0*z0 + b1*z1 + b2*z2
可以写成
[xp] [x0] [x1] [x2]
[yp] = b0*[y0] + b1*[y1] + b2*[y2]
[zp] [z0] [z1] [z2]
或
[xp] [x0 x1 x2] [b0]
[yp] = [y0 y1 y2] . [b1]
[zp] [z0 z1 z2] [b2]
重新安排为
-1
[b0] [x0 x1 x2] [xp]
[b1] = [y0 y1 y2] . [yp]
[b2] [z0 z1 z2] [zp]
3x3矩阵的行列式是:
det = x0(y1*z2 - y2*z1) + x1(y2*z0 - z2*y0) + x2(y0*z1 - y1*z0)
它的伴随是
[y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1]
[y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2]
[y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0]
,并提供:
[b0] [y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1] [xp]
[b1] = ( [y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2] . [yp] ) / det
[b2] [y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0] [zp]
如果您需要针对三角形测试多个点,请在此处停止。计算三角形的上述3x3矩阵一次(除以行列式),然后得到每个点得到每个点的重心坐标的点积。
如果你每个三角形只做一次,那么以上是乘以(由Maxima提供):
b0 = ((x1*y2-x2*y1)*zp+xp*(y1*z2-y2*z1)+yp*(x2*z1-x1*z2)) / det
b1 = ((x2*y0-x0*y2)*zp+xp*(y2*z0-y0*z2)+yp*(x0*z2-x2*z0)) / det
b2 = ((x0*y1-x1*y0)*zp+xp*(y0*z1-y1*z0)+yp*(x1*z0-x0*z1)) / det
这是相当多的加法,减法和乘法 - 三个除法 - 但没有sqrts或trig函数。它显然需要比纯2D计算更长的时间,但是根据投影启发式和计算的复杂性,这可能最终成为最快的路径。
正如我所提到的 - 我不知道我在说什么 - 但也许这会奏效,或者也许其他人可以出现并纠正它。
答案 2 :(得分:1)
更新:无视,此方法并非在所有情况下都适用
我想我找到了解决这个问题的有效方法。
注意:我需要投影到2D空间而不是使用3D重心坐标,因为我面临的挑战是使最有效的算法成为可能。通过找到合适的投影平面所产生的额外开销应该仍然小于使用更复杂的操作(例如sqrt或sin()cos()函数时产生的开销(我想我可以使用查找表进行sin / cos但这会增加内存占用并且无法实现此任务的目的。)
我的第一次尝试在多边形的每个轴上找到了最小值/最大值之间的差值,然后消除了具有最小增量的轴。然而,正如@PeterTaylor所建议的那样,有一些情况下,丢弃具有最小三角形的轴,当投影到二维空间时,可以产生直线而不是三角形。 这很糟糕。
因此我修改后的解决方案如下......
我没有时间对这种方法进行单元测试,但经过初步测试后似乎工作得相当好。我很想知道这其实是最好的方法吗?
答案 3 :(得分:1)
经过多次讨论,实际上有一种非常简单的方法可以解决在投影到2D空间时知道哪个轴下降的原始问题。答案在3D Math Primer for Graphics and Game Development中描述如下......
“解决这个难题的办法是 选择投影平面 最大化投影面积 三角形。这可以通过 检查飞机正常;该 最大的坐标 绝对值是坐标 我们会丢弃。例如,如果 normal是[-1,0,0],那我们就是 丢弃顶点的x值 和p,投射到yz平面上。“
我的原始解决方案涉及计算每轴的分数(使用子增量)是有缺陷的,因为可以为所有三个轴生成零分数,在这种情况下,下降的轴仍未确定。
使用碰撞平面的法线(可以预先计算效率)来确定投影到2D时要丢弃的轴是最佳方法。
答案 4 :(得分:1)
将点p投影到由顶点v0,v1和amp;定义的平面上。 v2你必须计算一个旋转矩阵。我们称之为预测点pd
e1 = v1-v0
e2 = v2-v0
r = normalise(e1)
n = normalise(cross(e1,e2))
u = normalise(n X r)
temp = p-v0
pd.x = dot(temp, r)
pd.y = dot(temp, u)
pd.z = dot(temp, n)
现在可以通过设置pd.z = 0将pd投影到平面上 此外,pd.z是点和由3个三角形定义的平面之间的距离。即如果投影点位于三角形内,则pd.z是到三角形的距离。
上面提到的另一点是,在旋转和投影到这个平面上之后,顶点v0位于原点,v1位于x轴上。
HTH
答案 5 :(得分:0)
我不确定这个建议实际上是最好的建议。投射到包含三角形的平面并不太难。我在这里假设p实际上在那个平面上。
令d1 = sqrt((v1-v0)。(v1-v0)) - 即距离v0-v1。 同样地,让d2 = sqrt((v2-v0)。(v2-v0))
v0 - > (0,0)
v1 - > (d1,0)
v2怎么样?嗯,你知道距离v0-v2 = d2。您只需要角度v1-v0-v2。 (v1-v0)。(v2-v0)= d1 d2 cos(theta)。 Wlog你可以把v2视为具有正y。
然后对p应用类似的过程,但有一个例外:你不一定认为它具有正y。相反,你可以通过取(v1-v0)x(v2-v0)的符号来检查它是否与y具有相同的符号。 (V1-V0)×(P-V0)。
作为替代解决方案,您可以在matrix equation上使用线性代数求解器作为四面体情况,将四面体v0 +(v1-v0)x(v2-v0)的第四个顶点作为标准化如果有必要的话。
答案 6 :(得分:0)
您不需要确定找到合适投影的最佳区域。
根本不需要找到“最佳”投影,只有一个足够好,并且在投影到2D时不会退化为直线。
编辑 - 由于退化的情况删除了算法我没有想到