给定一个带静态相机的three.js场景,0,0,0
的一个球体和一个任意尺寸的矩形精灵(例如一个文本标签),我正在寻找一个'threejs方法'(或公式),允许精灵围绕没有剪裁的球体,可能的最小半径。
到目前为止,我的方法是计算球体上位置的极坐标,然后将精灵偏移一个活动维度的因子,因为它接近球体的原点。我稍微改编了一下:
const xPolar = Math.sin(phi) * Math.sin(theta);
const yPolar = Math.cos(phi);
const zPolar = Math.sin(phi) * Math.cos(theta);
const x = xPolar + sprite.radius * xPolar;
const y = yPolar + sprite.radius * yPolar;
const z = zPolar + (theta < 0 ? -sprite.radius : sprite.radius) * xPolar // ahem;
这里的工作示例:https://codepen.io/theprojectsomething/full/xadQvK/
注意当phi接近极点时的削波。在这个例子中并没有太糟糕,但希望有一个更优雅的解决方案,以及对游戏中的力量有更好理解的人!
笔记:
Spherical
类;手动计算是为了清楚起见。让我们尝试将我们拥有的东西正式化。首先,我们假设我们处于一个坐标系中,其中球体位于原点,而视图方向是z轴。如果我们不在该坐标系中,则很容易将输入数据转换为此坐标系,然后进行计算,最后转换回原始坐标系。
我们有一个方向向量d
,它指定了我们想要精灵中心出现的方向(这就是你在代码片段中称为xyzPolar
的方向)。此外,我们有精灵的宽度w
和高度h
,我们知道宽度沿x轴扩展,高度沿y轴扩展(因为我们有一个视图对齐的坐标系)。
现在,对于任意标量偏移量t
,我们可以将精灵的中心指定为t * d
。然后我们的精灵上的点由以下集描述:
{ t * d + x * (w/2, 0, 0) + y * (0, h/2, 0) | -1 <= x <= 1, -1 <= y <= 1 }
x
和y
是精灵上的参数位置,其中(-1, -1)
定义左下角,(0, 0)
定义中心。我们特别感兴趣的是最接近球体中心的点,我们希望这个点远离它的是r
(球体的半径)。因此:
min (t * dx + x * w/2)^2 + (t * dy + y * h/2)^2 + (t * dz)^2 = r^2
x, y in [-1, 1]
如果我们知道这个最近点的参数x
和y
,我们可以很容易地求解t
,给我们精灵的最终中心位置。
但是,我们不知道这些参数。让我们分开这个公式:
( min (t * dx + x * w/2)^2 ) + ( min (t * dy + y * h/2)^2 ) + (t * dz)^2 = r^2
x in [-1, 1] y in [-1, 1]
如果我们可以设置,前两个术语最小化
x = -2 dx t / w
y = -2 dy t / h
在这种情况下,两个术语都将为零,我们可以解决t = r / abs(dz)
。基本上,这将把精灵放在xy对齐的平面上z = +- r
。如果我们有一个无限的精灵,我们不会限制x
和y
,这是真的。
但是,我们没有无限精灵。我们必须将x
和y
限制在允许的范围内。所以,如果我们有一个候选t
,我们也可以通过简单地用上面的公式计算x
和y
并检查它们是否在允许的范围内来检查它是否是一个有效的解决方案。如果最近的点位于精灵中间的某个位置(而不是在边缘或角落),则会出现这种情况。
幸运的是,我们需要检查的x
和y
只有几个可能的值。因此,算法将为所有可能的值计算t
,然后检查解是否有效,并且仅保留单个有效解。现在,x
和y
有什么价值?
我们已经知道-1 <= x <= 1
和-1 <= y <= 1
的情况。此范围内的所有值都是等效的,因为它们使前两个项为零(对最终结果没有影响)。然后每个变量还有两个案例。无论是x = -1
还是x = 1
(y
都一样)。这总共提供了我们需要解决的9种组合。但我们可以做得更好。我们知道t
,w
和h
是积极的。因此,x
和y
将分别与dx
和dy
具有相反的符号。例如,如果dx
是正数,我们只需要检查x = -1
或第一项消失的情况(基本上,这意味着如果方向向量指向右边,精灵的右边缘永远不会是最近的点)。同样,如果dx
或dy
正好为零,我们立即知道相应的术语消失了,我们不需要考虑其他情况。另外,如果dz = 0
,不要评估前两个术语消失的情况
所以,我们有四个案例。作为参考,以下是每个变量的三种不同情况的术语:
first term
-1 = x dx^2 * t^2 - dx * t * w + w^2 / 4
-1 < x < 1 0
x = 1 dx^2 * t^2 + dx * t * w + w^2 / 4
second term
-1 = y dy^2 * t^2 - dy * t * h + h^2 / 4
-1 < y < 1 0
y = 1 dy^2 * t^2 + dy * t * h + h^2 / 4
对于您需要评估的四种情况,组装二次方程并求解t
。最后,计算x
和y
并检查它们是否与案例匹配(如果你有x = 1
案例,检查x >= 1
等)最后,将精灵中心计算为t * d
。
所以,不幸的是,这并不比你拥有的更优雅,但它更准确。