2011-12-09

Dysk

Czyli intersekcja sfery z płaszczyzną. Takie kółko w przestrzeni 3D. Bardzo przydatne do zatykania walców i stożków.

Bardzo prosty do utworzenia element. Zbudowany z niewielkimi modyfikacjami na kodzie płaszczyzny.

Jeśli chodzi o intersekcję promienia z dyskiem, wyliczamy najpierw intersekcję promienia z płaszczyzną w której leży dysk. Następnie liczymy odległość do środka dysku i porównujemy ją z promieniem dysku.

W stosunku do kodu płaszczyzny modyfikujemy jeszcze kod zwracający współrzędne UVW i UV i gotowe.

Przykładowy kod:
public override Intersection GetIntersection(
    Intersection a_source_ray_intersection, Ray a_ray)
{
    Vector3 local_start;
    Vector3 local_dir;
    TransformToLocal(a_ray, out local_dir, out local_start);

    if (OneSide)
    {
        if (local_dir.Y > 0)
            return Scene.NoIntersection;
    }

    if ((a_source_ray_intersection != null) && 
        (a_source_ray_intersection.SceneObject == this))
    {
        return Scene.NoIntersection;
    }

    if (local_dir.Y.AlmostRelativeEquals(0))
        return Scene.NoIntersection;

    double dist = local_start.Y / -local_dir.Y;

    if (dist <= 0)
        return Scene.NoIntersection;
    else
    {
        bool back_hit = (local_dir.Y > 0);

        if (back_hit && OneSide)
            return Scene.NoIntersection;
        else
        {
            Vector3 local_pos = local_start + local_dir * dist;

            if (local_pos.X * local_pos.X + local_pos.Z * local_pos.Z > 1)
                return Scene.NoIntersection;

            Vector3 world_pos = LocalToWorld * local_pos;
            dist = (world_pos - a_ray.Start).Length;

            return new Intersection()
            {
                PrevIntersection = a_source_ray_intersection,
                SceneObject = this,
                SourceRay = a_ray,
                Dist = dist,
                Scene = Scene,
                BackHit = back_hit,
                Pos = world_pos,
                LocalPos = local_pos
            };
        }
    }  
}

public override Vector3 GetNormal(Intersection a_intersection)
{
    if (a_intersection.BackHit)
        return -Normal;
    else
        return Normal;
}
public override Vector3 GetUVW(Intersection a_intersection)
{
    return base.GetUVW(a_intersection) * 0.5 + new Vector3(0.5, 0, 0.5);
}

public override Vector2 GetUV(Intersection a_intersection)
{
    Debug.Assert(a_intersection.UVW.Y.AlmostRelativeEquals(0));
    return new Vector2(a_intersection.UVW.X, a_intersection.UVW.Z);
}

public override void GetTangents(Intersection a_intersection,
    out Vector3 a_tangent_x, out Vector3 a_tangent_y)
{
    a_tangent_x = Right;
    a_tangent_y = Forward;
}

protected override Vector3 LocalScale
{
    get
    {
        return new Vector3(Radius, Radius, Radius);
    }
}

protected override AABB GetLocalBoundBox()
{
    return new AABB(new Vector3(-Radius, -Constants.MINIMAL_DISTANT, -Radius),
                    new Vector3(Radius, Constants.MINIMAL_DISTANT, Radius));
}

Brak komentarzy:

Prześlij komentarz