文档说
dst
“计算距离向量”:
dest = dst( src0, src1 ) ;
它说,
第一个源操作数 (src0) 假定为向量(忽略、d*d、d*d、忽略),第二个源操作数 (src1) 假设为向量(忽略、1/d、忽略、1) /d)。目的地 (dest) 是结果向量 (1, d, d*d, 1/d)。
//Code
dest.x = 1;
dest.y = src0.y * src1.y;
dest.z = src0.z;
dest.w = src1.w;
这到底是什么意思?为什么要使用它?
在计算机图形学中,计算向量的长度是一项非常常见的工作 - 例如计算两点之间的距离。鉴于您已经计算了点之间的差异,距离可以计算为:
d = sqrt(x*x + y*y + z*z);
不幸的是,计算一个数的根是非常昂贵的;事实上,目前已知最快的方法是首先计算根的逆,然后计算根本身,如下所示:
// invsqrt(x) := 1/sqrt(x)
dSqr = x*x + y*y + z*z;
dInv = invsqrt(d);
d = 1/dInv;
请注意,最后一行可以替换为:
d = dSqr*dInv;
实际上,这可能确实更有效一点,因为除法往往比乘法更昂贵。
现在,通常情况下,在远处运行的部分“下游”代码可能需要的不是在
d
本身上运行,而是在 d*d
上运行(例如,将其插入到进一步的毕达哥拉斯式计算中),或者 1/d
(例如在雾状着色器中),甚至1/(d*d)
(例如在照明计算中)。
通过将最终结果和中间值传递给下游代码,可以优化此类计算,或者至少更有效地实现此类计算;因此,您可能决定传递一整批基于距离的值 - 这可能就是微软所说的“距离向量”的意思:
d
d*d
1/d
现在至于为什么该向量中还有一个
1
,我不确定,但它导致了一个简洁的属性,即该向量包含从 d
到 pow(d,-1)
的 pow(d,2)
的完整幂集(虽然有点混乱)
dst
指令似乎被设计为执行组装这样一个距离向量的最后一步:首先在一个寄存器中计算距离的平方,然后在另一个寄存器中计算距离的倒数之后,dst
指令将把这些值一起放入一个寄存器中,一路计算乘积来计算实际距离。
至于为什么输入寄存器需要在每个组件中“呈现”输入操作数,我想这是为了可以优化实现指令的微代码(实际上这可能是在中包含
1
的真正原因)那里):请注意 dst
运算实际上是两个操作数的逐分量乘法,只不过每个源操作数的两个分量被 1
替换:
dest = (1, src0.y, src0.z, 1) * (1, src1.y, 1, src1.w);
所以:这就是
dst
指令在处理距离时的用处,微软所说的“距离向量”可能意味着什么,以及该指令的一些奇怪之处可能有其根源(双关语)。