Processing math: 100%

2011-12-09

Torus - normalna

Normalną możemy policzyć korzystając z gradientu funkcji lub poprzez podejście geometryczne. Podejście geometryczne daje poprawne wyniki kiedy r>R i kiedy R=0.

Równanie torusa leżącego w płaszczyźnie XZ:

(x2+y2R)2+y2=r2

Normalna to gradient funkcji:

f(x,y,z)=(x2+y2R)2+y2r2
f=[2x2xRx2+z2,2y,2z2zRx2+z2]

Możemy także najpierw lekko uporządkować funkcje:

(x2+z2R)2+y2=r2
x2+z22Rx2+z2+R2+y2=r2
x2+y2+z2+R2r2=2Rx2+z2
(x2+y2+z2+R2r2)2=4R2(x2+z2)
f(x,y,z)=(x2+y2+z2+R2r2)24R2(x2+z2)
f=[4x(x2+y2+z2+R2r2)28xR2,4y(x2+y2+z2+R2r2)2,4z(x2+y2+z2+R2r2)28zR2]

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 P (od środka torusa do punktu P) na płaszczyznę XZ to A=[x,y,0]. Wektor o długości R o takim samym kierunku to B=RˆA. Wektor ^PB 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