在使用(x,z)而不是(x,y)的3D空间中沿着我的立方贝塞尔曲线移动时,我遇到了关于切线的问题。 已添加曲线图像。
当实体点击图片上指示的红线时,会出现此问题。切线从 0.0逐渐开始<1.0 ,然后点击红线并开始逐渐从 1.0减少到0.0 ,导致实体的方向翻转。
目前,此剪辑负责切线:
const Vector3 Class::getTangent(const float s) const
{
const float t { 1 - s };
return (3 * t * t * (points.at(1) - points.at(0)) +
6 * s * t * (points.at(2) - points.at(1)) +
3 * s * s * (points.at(3) - points.at(2)));
}
然后我将此功能用于:
Vector3 firstDerivative = curve.getTangent(segment);
firstDerivative.normalise();
Vector3 normal = firstDerivative.crossProduct(Vector3(0, 0, 1)); // Z = forward
normal.normalise();
Vector3 b = firstDerivative.crossProduct(normal);
b.normalise();
然后我简单地使用b
来设置沿曲线的实体方向。当达到翻转实体的点时,我确实通过将b
的符号切换为-b
来创建简单/脏修复。现在,尽管这个“修复”问题我相信如果曲线发生变化,修复将在以后引起问题。
因此,如果有人能够发现我可能出错的地方或我可能需要做些什么来解决这个问题,那么任何帮助都会很棒并且值得赞赏。 请您通过伪代码或c ++代码提供给定问题的解决方案示例。
答案 0 :(得分:1)
这实际上是一个非常常见的问题,我在为游戏演示(wipeout97风格)制作赛道发生器时也面临着这个问题,后来一位同事在使用地形工具制作道路生成器时面临众所周知的3D商业内容创作工具。
要解决此问题,您需要以下两种方法之一:
难以制作硬垂直,您只需使用固定矢量(例如(0,1,0))制作十字产品,但是您的曲线在任何时候都不能完全朝这个方向移动,否则你的十字架产品有一天会变成零,所有的一切都会崩溃。
惯性系统迭代地跟随曲线,在开始时使用一个参考硬矢量,但只是一次。
然后曲线之后是增量增量,并且每次通过前一段的切线和比特数(TBN基础)的逐步改变来发现新的切线和比特数。您使用小t
(曲线参数)增量不会导致巨大的TBN更改的事实,并且您可以使用先前的TBN向量之一来使用新切线生成交叉积以找到新的B和N.这样几乎可以保证你永远不会有这种万向锁定效果。
然后,各种可能的有趣参数也是可能的,例如在每个步骤强制TBN基础的最大旋转速度,或类似,在创建曲目的情况下,这提供了很多艺术力量。
答案 1 :(得分:0)
好的,通过一些额外的实验,我已经设法让它工作,我相信这是一个不错的修复。如果有人能向我解释这是否可能,我将不胜感激。
无论如何,我正在编码的包有两个可用的功能,setDirection
(最初使用)和lookAt
(现在使用) 。
代码之前:
entity->setDirection (firstDerivative, WorldSpace, secondDerivative);
<强>后强>:
entity->lookAt (point - firstDerivative, WorldSpace);
现在结果secondDerivative
现在从未使用过,这完全没问题,但是这是一个更有品味的解决方案吗?
答案 2 :(得分:0)
由于Bezier曲线位于(x,z)平面上,我不太清楚为什么要在一阶导数和z轴(0,0,1)之间取一个交叉乘积。正常&#39;当一阶导数进入(0,0,1)方向时,以这种方式找到的矢量必然变为零。
如果你想在曲线上的任何给定点找到法线方向,你应首先评估一阶导数C&#39;(t)和二阶导数C&#34;(t),然后评估法向矢量vec (n)可以计算为
vec(n)= C&#39; X C&#34; / | C&#39; || C&#34; |
和你的副法向量vec(b)可以计算为vec(b)= vec(t)X vec(n)其中vec(t)是单位切向量vec(t)= C&#39;(t )/ | C&#39;(T)|
。