样条法线计算
Spline Normal Calculation
我在计算从中挤出网格的样条法线时遇到问题。
检查图片:
正如你所看到的,某个区域的法线出现了翻转,我不知道为什么。
相关代码:
public Vector3 GetNormal(float t)
{
var tangent = GetTangent(t);
var point = GetPoint(t);
var accel = GetAcceleration(t);
// we need to lerp up base don the control points
int i;
if (t >= 1f)
{
t = 1f;
i = _points.Length - 4;
}
else
{
t = Mathf.Clamp01(t) * CurveCount;
i = (int)t;
t -= i;
i *= 3;
}
//var rotaSource = GetControlPointRotation(i);
//var rotaDest = GetControlPointRotation(i + 2);
//var lerp = Mathf.Lerp(rotaSource, rotaDest,t);
//var normalRotation = Quaternion.AngleAxis(lerp,tangent);
var binormal = Vector3.Cross(tangent, accel).normalized;
var normalOr = Vector3.Cross(tangent, binormal).normalized;
Debug.DrawLine(point, point + accel * 5, Color.blue);
Debug.DrawLine(point, point + binormal * 5,Color.black);
Debug.DrawLine(point, point + normalOr * 5, Color.yellow);
Debug.DrawLine(point, point + tangent * 5, Color.magenta);
if (Vector3.Dot(tangent, accel) > 0)
return Vector3.up;
return normalOr;
//return (normalRotation*up).normalized;
}
public Vector3 GetAcceleration(float t)
{
int i;
if (t >= 1f)
{
t = 1f;
i = _points.Length - 4;
}
else
{
t = Mathf.Clamp01(t) * CurveCount;
i = (int)t;
t -= i;
i *= 3;
}
return Bezier.GetSecondDerivative(_points[i], _points[i + 1], _points[i + 2],
_points[i + 3], t).normalized;
}
public Vector3 GetTangent(float t)
{
int i;
if (t >= 1f)
{
t = 1f;
i = _points.Length - 4;
}
else
{
t = Mathf.Clamp01(t) * CurveCount;
i = (int)t;
t -= i;
i *= 3;
}
return
Bezier.GetFirstDerivative(_points[i], _points[i + 1], _points[i + 2],
_points[i + 3], t).normalized;
}
贝塞尔曲线方法在这里:
public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
t = Mathf.Clamp01(t);
float OneMinusT = 1f - t;
return OneMinusT*OneMinusT*OneMinusT*p0 + 3f*OneMinusT*OneMinusT*t*p1 + 3f*OneMinusT*t*t*p2 + t*t*t*p3;
}
public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
float it = oneMinusT;
float it2 = oneMinusT*oneMinusT;
float t2 = t*t;
return (p0 * -it2 +
p1 * (t * (3 * t - 4) + 1) +
p2 * (-3 * t2 + t * 2) +
p3* t2).normalized;
return 3f*oneMinusT*oneMinusT*(p1 - p0) + 6f*oneMinusT*t*(p2 - p1) + 3f*t*t*(p3 - p2);
}
public static Vector3 GetSecondDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
return (6*t*(p1 + 3*(p2 - p3) - p0) + 6*(p0 - 2*p2 + p3));
}
我不知道为什么,也不知道如何解决。我曾尝试使用像 Up 这样的参考向量但无济于事,我什至试图在某些条件下否定法线(加速度和切线的点积 < -1)。
副法线可以根据曲线的曲率翻转。我们在计算
B = T X dT
考虑平面中的 S 形曲线。在曲线的开始,这些将在一个方向上,给出一个向外指向的双法线。最后,它们的方向相反,向内指向法线。
这个翻转的双法线将导致翻转的法线。一个简单的修复方法就是使用
normalOr = accel.normalise
一种更高级的技术是在连续向量之间施加连续性。所以我们在第一个点计算T1、N1、B1,然后计算T2、N1、B1。现在计算 T1 。 T2,N1。 N2,B1。 B2.对于连续向量场,这些点积中的每一个都应该是正的,如果有任何点积是负的,只需翻转适当的向量。
您总是会在曲率和扭转为零的点周围遇到问题。
我在计算从中挤出网格的样条法线时遇到问题。
检查图片:
相关代码:
public Vector3 GetNormal(float t)
{
var tangent = GetTangent(t);
var point = GetPoint(t);
var accel = GetAcceleration(t);
// we need to lerp up base don the control points
int i;
if (t >= 1f)
{
t = 1f;
i = _points.Length - 4;
}
else
{
t = Mathf.Clamp01(t) * CurveCount;
i = (int)t;
t -= i;
i *= 3;
}
//var rotaSource = GetControlPointRotation(i);
//var rotaDest = GetControlPointRotation(i + 2);
//var lerp = Mathf.Lerp(rotaSource, rotaDest,t);
//var normalRotation = Quaternion.AngleAxis(lerp,tangent);
var binormal = Vector3.Cross(tangent, accel).normalized;
var normalOr = Vector3.Cross(tangent, binormal).normalized;
Debug.DrawLine(point, point + accel * 5, Color.blue);
Debug.DrawLine(point, point + binormal * 5,Color.black);
Debug.DrawLine(point, point + normalOr * 5, Color.yellow);
Debug.DrawLine(point, point + tangent * 5, Color.magenta);
if (Vector3.Dot(tangent, accel) > 0)
return Vector3.up;
return normalOr;
//return (normalRotation*up).normalized;
}
public Vector3 GetAcceleration(float t)
{
int i;
if (t >= 1f)
{
t = 1f;
i = _points.Length - 4;
}
else
{
t = Mathf.Clamp01(t) * CurveCount;
i = (int)t;
t -= i;
i *= 3;
}
return Bezier.GetSecondDerivative(_points[i], _points[i + 1], _points[i + 2],
_points[i + 3], t).normalized;
}
public Vector3 GetTangent(float t)
{
int i;
if (t >= 1f)
{
t = 1f;
i = _points.Length - 4;
}
else
{
t = Mathf.Clamp01(t) * CurveCount;
i = (int)t;
t -= i;
i *= 3;
}
return
Bezier.GetFirstDerivative(_points[i], _points[i + 1], _points[i + 2],
_points[i + 3], t).normalized;
}
贝塞尔曲线方法在这里:
public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
t = Mathf.Clamp01(t);
float OneMinusT = 1f - t;
return OneMinusT*OneMinusT*OneMinusT*p0 + 3f*OneMinusT*OneMinusT*t*p1 + 3f*OneMinusT*t*t*p2 + t*t*t*p3;
}
public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
float it = oneMinusT;
float it2 = oneMinusT*oneMinusT;
float t2 = t*t;
return (p0 * -it2 +
p1 * (t * (3 * t - 4) + 1) +
p2 * (-3 * t2 + t * 2) +
p3* t2).normalized;
return 3f*oneMinusT*oneMinusT*(p1 - p0) + 6f*oneMinusT*t*(p2 - p1) + 3f*t*t*(p3 - p2);
}
public static Vector3 GetSecondDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
return (6*t*(p1 + 3*(p2 - p3) - p0) + 6*(p0 - 2*p2 + p3));
}
我不知道为什么,也不知道如何解决。我曾尝试使用像 Up 这样的参考向量但无济于事,我什至试图在某些条件下否定法线(加速度和切线的点积 < -1)。
副法线可以根据曲线的曲率翻转。我们在计算 B = T X dT 考虑平面中的 S 形曲线。在曲线的开始,这些将在一个方向上,给出一个向外指向的双法线。最后,它们的方向相反,向内指向法线。
这个翻转的双法线将导致翻转的法线。一个简单的修复方法就是使用
normalOr = accel.normalise
一种更高级的技术是在连续向量之间施加连续性。所以我们在第一个点计算T1、N1、B1,然后计算T2、N1、B1。现在计算 T1 。 T2,N1。 N2,B1。 B2.对于连续向量场,这些点积中的每一个都应该是正的,如果有任何点积是负的,只需翻转适当的向量。
您总是会在曲率和扭转为零的点周围遇到问题。