Herausfinden, ob Punkt in einem Kegel ist (3D). (für Lighting-Klasse)

  • VB.NET
  • .NET (FX) 4.0

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von 00yoshi.

    Herausfinden, ob Punkt in einem Kegel ist (3D). (für Lighting-Klasse)

    Also ich habe bereits eine Lighting-Klasse, aber sie unterstützt kein direktionales Licht.
    Deswegen dachte ich, dass ich einfach überprüfe, ob ein Punkt im Lichtkegel ist. Leider habe ich keine Tutorials gefunden, die ich umsetzen konnte, also Frage ich nun euch: Wie kann man mithilfe eines Winkels und einem Richtungsvektor und einem Vektor für die Kegelspitze überprüfen, ob ein punkt in dem Kegel liegt?
    P.S. Ich benutze dafür die Vector3-Klasse von OpenTK.

    00yoshi schrieb:

    ob ein punkt in dem Kegel liegt?
    Dazu solltest Du nicht primär Deine verwendeten Klasse benennen sondern das Prinzip verstehen.
    Du hast eine Kegel-Achse, sie sei die z-Achse, der Ursprung sei die Kegelspitze (es ist egal, ob x-, y- oder z-Achse).
    Wenn das in Deinen Koordinaten nicht so ist, mach eine geeignete Koordinatentransformation.
    Der Kegel wird nun allein durch einen Öffnungswinkel definiert: Alpha = const., der Winkel von der Achse zum Mantel (der halbe Öffnungswinkel).
    Du musst nun zu Deinem Punkt den Winkel durch den Ursprung zur Achse bestimmen.
    Ist der Winkel kleiner als der Öffnungswinkel, liegt der Punkt innerhalb des Kegels.
    Ist der Winkel gleich dem Öffnungswinkel, liegt der Punkt auf dem Kegelmantel.
    Ist er größer, liegt er außerhalb.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Skalarprodukt - Check. Du brauchst nur zwei Vektoren: Den für die Achse und den für den Punkt , also . Die beiden Vektoren müssen von der Kegelspitze aus ihren Ursprung haben, sind also Richtungsvektoren. Dann haben wir noch den Winkel , der den Öffnungswinkel des Kegels darstellt. Dann gilt ja:

    Und wie Blaze schon geschrieben hat, wenden wir hierfür dann das Skalarprodukt an, das uns dann den Cosinus zurückgibt. Umgeformt ergibt das:


    Beispiel:

    Dann eingesetzt:

    (Ui, ist das gross. 8| Habe ich irgendwo 'nen Fehler gemacht? ?( )

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Higlav“ ()

    Man sollte sich den cos und arc cos sparen, wenn möglich. Das geht, wenn man cos alpha zum Skalarprodukt ändert. Es sollte durch eine einfache Ungleichung (bzw. 2 Ungleichungen) möglich sein, die einfach nur die Steigung bereithält. Bin unterwegs, insofern kann ich mich gerade nicht dransetzen.

    Gruß
    ~blaze~

    00yoshi schrieb:

    Kann a auch z.b. (1,1,0).normalize sein?

    Ja, aber .Normalize ist redundant, da das Skalarprodukt sowieso unempfindlich gegenüber Vektorlängen ist.

    ~blaze~ schrieb:

    Man sollte sich den cos und arc cos sparen, wenn möglich. Das geht, wenn man cos alpha zum Skalarprodukt ändert.

    Ich verstehe nicht ganz. Wir haben einerseits einen Winkel und andererseits eine Vektorkonstruktion, die mit Winkel nichts am Hut hat. Wir müssen ja das Skalarprodukt nehmen, da wir entweder Winkel mit Winkel, oder Steigung mit Steigung vergleichen müssen...

    Higlav schrieb:

    da das Skalarprodukt sowieso unempfindlich gegenüber Vektorlängen ist.
    Das ist falsch. Du kannst ja den (von 1 verschiedenen) Skalierungsfaktor ausklammern.
    Deswegen sollten Vektoren, aus denen das Skalarprodukt gebildet wird, normiert sein.
    Insbesondere sollten Richtungsvektoren normiert sein, die "Verschiebung" wird dann mit einem einfachen Faktor gemacht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Steigung mit Steigung ist praktischer. Wenn dann nicht der Winkel, sondern die Steigung verwendet wird, geht das wunderbar. Kann man ja als statische Funktion anbieten, indem man dort den cos vorwegberechnet. Der ist pro cone ja konstant. Richtung, Steigung und Aufpunkt genügen für die Definition.

    Gruß
    ~blaze~

    RodFromGermany schrieb:

    Das ist falsch. Du kannst ja den (von 1 verschiedenen) Skalierungsfaktor ausklammern.
    Deswegen sollten Vektoren, aus denen das Skalarprodukt gebildet wird, normiert sein.

    8o DESHALB habe ich so einen grossen Winkel bekommen! Mist, das habe ich irgendwie völlig vergessen... :/
    Sorry, mein Fehler...

    RodFromGermany schrieb:

    Insbesondere sollten Richtungsvektoren normiert sein, die "Verschiebung" wird dann mit einem einfachen Faktor gemacht.

    Jup. Macht Sinn. ^^

    EDIT:

    ~blaze~ schrieb:

    Kann man ja als statische Funktion anbieten, indem man dort den cos vorwegberechnet. Der ist pro cone ja konstant.

    Ahh. Jetzt verstehe ich , was du meinst. Ja klar, wenn man schon von der Konstante aus vereinfachen kann, soll man das ja auch tun, ne? ^^
    @Higlav Bei deiner Formel ist es dann doch von der Position (0,0,0) oder? also dann müsste ich nur noch die position des Lichtes dazuaddieren, oder?

    EDIT:
    jetzt hab ich

    VB.NET-Quellcode

    1. Private Function IsInCone(Angle As Double, Direction As Vector3, Point As Vector3) As Boolean
    2. Direction.Normalize()
    3. Return Math.Acos((Direction.X * Point.X + Direction.Y * Point.Y + Direction.Z * Point.Z) / Math.Sqrt(Point.X * Point.X + Point.Y * Point.Y + Point.Z * Point.Z) * Math.Sqrt(Direction.X * Direction.X + Direction.Y * Direction.Y + Direction.Z * Direction.Z)) <= Angle
    4. End Function

    und es klappt irg. nicht.

    und zum aufrufen lass ich mir einfach eine Point-Array zeichnen und für jeden Point:

    VB.NET-Quellcode

    1. If IsInCone(20, New Vector3(1, 0, 0), New Vector3(X, Y, Z)) Then
    2. GL.Vertex3(X, Y, Z)
    3. End If


    EDIT 2:
    Ich hatte es ja voll vergessen... Radianten...

    VB.NET-Quellcode

    1. Const DegToRad As Double = Math.PI / 180
    2. Private Function IsInCone(Angle As Double, Direction As Vector3, Point As Vector3) As Boolean
    3. Angle *= DegToRad
    4. Direction.Normalize()
    5. Return Math.Acos((Direction.X * Point.X + Direction.Y * Point.Y + Direction.Z * Point.Z) / Math.Sqrt(Point.X * Point.X + Point.Y * Point.Y + Point.Z * Point.Z) * Math.Sqrt(Direction.X * Direction.X + Direction.Y * Direction.Y + Direction.Z * Direction.Z)) <= Angle
    6. End Function


    EDIT 3:
    Hm irgendwie ist 90° eine Ebene... also nochmal alles / 2

    EDIT 4:
    Soooooooo...
    Hat alles geklappt.
    Bilder im Anhang.
    Bilder
    • 364.png

      22,14 kB, 1.280×962, 168 mal angesehen
    • 684.png

      20,06 kB, 1.280×962, 155 mal angesehen
    • 1269.png

      15,74 kB, 1.280×962, 154 mal angesehen

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „00yoshi“ ()