Równanie torusa leżącego w płaszczyźnie XZ:
$(\sqrt{x^2+y^2}-R)^2+y^2=r^2$
Normalna to gradient funkcji:
$f(x,y,z)=(\sqrt{x^2+y^2}-R)^2+y^2-r^2$
$\nabla f=\left[2x-\frac{2xR}{\sqrt{x^2+z^2}},2y,2z-\frac{2zR}{\sqrt{x^2+z^2}}\right]$
Możemy także najpierw lekko uporządkować funkcje:
$(\sqrt{x^2+z^2}-R)^2+y^2=r^2$
$x^2+z^2-2R\sqrt{x^2+z^2}+R^2+y^2=r^2$
$x^2+y^2+z^2+R^2-r^2=2R\sqrt{x^2+z^2}$
$(x^2+y^2+z^2+R^2-r^2)^2=4R^2(x^2+z^2)$
$f(x,y,z)=(x^2+y^2+z^2+R^2-r^2)^2-4R^2(x^2+z^2)$
$\begin{align*}
\nabla f=[& 4x(x^2+y^2+z^2+R^2-r^2)^2-8xR^2, \\& 4y(x^2+y^2+z^2+R^2-r^2)^2, \\& 4z(x^2+y^2+z^2+R^2-r^2)^2-8zR^2]
\end{align*}$
W podejściu geometrycznym mamy punkt w który uderzył promień należący do torusa $P(x,y,z)$. Torus leży w płaszczyźnie $XZ$. Rzut wektora $\vec P$ (od środka torusa do punktu P) na płaszczyznę $XZ$ to $\vec A=[x,y,0]$. Wektor o długości $R$ o takim samym kierunku to $\vec B = R\hat A$. Wektor $\hat{\vec P-\vec B}$ to normalna. Jeśli mamy uderzenie od środka torusa to należy ją wziąć ze znakiem minus.
Kod wszystkich trzech wersji:
public override Vector3 GetNormal(
Intersection a_intersection)
{
Vector3 local_pos = a_intersection.LocalPos;
//float R2 = m_local_big_radius * m_local_big_radius;
//float n = local_pos.SqrLen + R2 - m_local_small_radius * m_local_small_radius;
//
//Vector3 normal = new Vector3(
// local_pos.X * n - 2 * R2 * local_pos.X,
// local_pos.Y * n,
// local_pos.Z * n - 2 * R2 * local_pos.Z);
//
//if (a_intersection.BackHit)
// return (LocalToWorldNormal * -normal).Normalized;
//else
// return (LocalToWorldNormal * normal).Normalized;
if (a_intersection.BackHit)
{
return (LocalToWorldNormal * (new Vector3(local_pos.X, 0,
local_pos.Z).Normalized * m_local_big_radius -
local_pos)).Normalized;
}
else
{
return (LocalToWorldNormal * (local_pos - new Vector3(local_pos.X, 0,
local_pos.Z).Normalized * m_local_big_radius)).Normalized;
}
//var nn = LocalToWorldNormal * new Vector3(
// local_pos.X - local_pos.X * m_local_big_radius /
// (float)Math.Sqrt(local_pos.X * local_pos.X + local_pos.Z * local_pos.Z),
// local_pos.Y,
// local_pos.Z - local_pos.Z * m_local_big_radius /
// (float)Math.Sqrt(local_pos.X * local_pos.X + local_pos.Z * local_pos.Z)
// ).Normalized;
//if (a_intersection.BackHit)
// return -nn;
//else
// return nn;
}
Brak komentarzy:
Prześlij komentarz