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