Raycasting - komme nicht weiter

  • C#

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von FreakJNS.

    Raycasting - komme nicht weiter

    hi

    nachdem ich hier auf ein raycasting projekt gestossen bin wollte ich mich selbst daran versuchen (diesmal in c#). leider hakt es noch etwas. vor allem kommt als bild (bisher nur rudimentär und einfarbig) nicht genu das raus was ich will. vllt könnte mir einer etwas auf die sprünge helfen?

    Ich weiß, das mit dem threading ist net besonders elegant aber es ist 100 % nur vorläufig!

    im anhang nen screen wies bisher ausschaut

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Text;
    7. using System.Windows.Forms;
    8. namespace RayCasting
    9. {
    10. public partial class Form1 : Form
    11. {
    12. const int wid = 6;
    13. private int[,] field;
    14. double fieldAngle = 60.0F;
    15. double gridSize = 64.0F;
    16. Point playerPosition = new Point(64*3+32, 64*4+32);
    17. public Form1()
    18. {
    19. InitializeComponent();
    20. field = new int[wid, wid]{
    21. {1,1,1,1,1,1},
    22. {1,0,0,0,0,0},
    23. {1,0,0,1,0,0},
    24. {1,0,0,0,0,0},
    25. {1,0,0,0,0,0},
    26. {1,1,1,1,1,1}};
    27. System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ThreadFunction));
    28. t.Start((object)this.CreateGraphics());
    29. }
    30. private double DTR(double angle)
    31. {
    32. return Math.PI * angle / 180.0;
    33. }
    34. void ThreadFunction(object o)
    35. {
    36. Graphics g = (Graphics)o;
    37. double px = 160+32, py = 160+64+64+64;
    38. const double blockSize = 64;
    39. double fieldWidth = 60;
    40. double lookDirection = 0;
    41. double ay, ax, gx, gy, bx, by;
    42. double delta = fieldWidth / this.ClientSize.Width;
    43. while (true)
    44. {
    45. System.Threading.Thread.Sleep(500);
    46. g.Clear(Color.White);
    47. py++;
    48. for (int ray = 0; ray < this.ClientSize.Width; ray++)
    49. {
    50. // Horizontal Intersections
    51. double actAngle = lookDirection - (fieldWidth / 2.0) + delta * ray;
    52. ay = py - (py % blockSize);
    53. ax = px - (Math.Tan(DTR(actAngle) * (py % blockSize)));
    54. gy = Math.Floor(ay / blockSize) -1;
    55. gx = Math.Floor(ax / blockSize);
    56. if (gy < 0 ||gx < 0|| gx >= wid ||gy >= wid)
    57. break;
    58. while (field[(int)gx,(int)gy] != 1)
    59. {
    60. ay -= blockSize;
    61. ax -= Math.Tan(DTR(actAngle)) * blockSize;
    62. gy = Math.Floor(ay / blockSize) - 1;
    63. gx = Math.Floor(ax / blockSize);
    64. if (gy < 0 || gx < 0 || gx >= wid || gy >= wid)
    65. {
    66. goto leave;
    67. }
    68. }
    69. double distHori = Math.Sqrt(Math.Pow(px - ax, 2) + Math.Pow(py- ay, 2));
    70. double distVert;
    71. // vertical Intersections
    72. bx = px - (px % blockSize);
    73. by = py - (Math.Tan(DTR(actAngle) * (px % blockSize)));
    74. gy = Math.Floor(by / blockSize) - 1;
    75. gx = Math.Floor(bx / blockSize);
    76. if (gy < 0 || gx < 0 || gx >= wid || gy >= wid)
    77. {
    78. goto leave;
    79. }
    80. while (field[(int)gx, (int)gy] != 1)
    81. {
    82. bx -= blockSize;
    83. by -= blockSize / (Math.Tan(DTR(actAngle))) ;
    84. gy = Math.Floor(ay / blockSize) - 1;
    85. gx = Math.Floor(ax / blockSize);
    86. if (gy < 0 || gx < 0 || gx >= wid || gy >= wid)
    87. {
    88. goto leave;
    89. }
    90. }
    91. distVert = Math.Sqrt(Math.Pow(px - bx, 2) + Math.Pow(py - by, 2));
    92. double dist;
    93. if (distVert < distHori)
    94. dist = distVert;
    95. else
    96. dist = distHori;
    97. float h = 10000 / ((float)dist);
    98. try
    99. {
    100. g.DrawLine(new Pen(Brushes.Red), ray, this.ClientSize.Height / 2F - (h / 2.0F), ray, this.ClientSize.Height / 2F + h / 2.0F);
    101. }
    102. catch (Exception)
    103. {
    104. return;
    105. }
    106. }
    107. leave:
    108. ;
    109. }
    110. }
    111. }
    112. }
    Bilder
    • ray.png

      28,95 kB, 300×300, 180 mal angesehen

    Quadsoft schrieb:

    Quellcode

    1. System.Threading.Thread.Sleep(500);
    Wozu dies?
    Was für ein Bild soll den rauskommen?
    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!
    ay = py - (py % blockSize);
    ax = px - (Math.Tan(DTR(actAngle) * (py % blockSize)));


    Dein Hauptproblem wird hier liegen (sofern ich den Code verstehe. Hier mal eine Grafische darstellung wie du die map abtastest:


    Du handhabst das ganze sicher wie in A dargestellt, vllt verminderst du die Schrittanzahl wie in B um die Qualität zu erhöhen. Meine Lösung ist aber in C dargestellt und hier sehr gut erklärt (mache es aber über Vektoren, ist schneller und du hast bei z.b. bei tan(270°) keine Probleme.

    Das zweite, was dich stören wird ist vermutlich ein "Fischaugen-Effekt". Dieser kommt hier zustande:
    float h = 10000 / ((float)dist);


    Die Mauern an der Seite des Blickfeldes sind natürlich weiter von dem Betrachter entfernt und werden desshalb kleiner dargestellt. Fischaugeneffekt eben. Diesen kannst du ganz einfach Rausrechnen:
    Höhe = Höhe * Cos(Einfallswinkel)
    Einfallswinkel ist in dem Fall der Winkel zwischen Blickrichtung und Sehstrahl. Und zack, der Fischaugeneffekt ist weg - hierauch nochmal gut dargestelt.

    Warum eigentlich die Gridsize als double (int wäre denke ich passender) und die position als point statt PointF? Das sieht später sicher ruckelig aus wenn man sich auf einem 64x64 Raster bewegt..

    LG

    PS: Wenn du es NICHT wie in C dargestellt machst, wie willst du dann die Texturen einberechnen? Du brauchst theoretich schon den exakten Schnittpunkt um berechnen zu können welcher vertikale Texturstreifen auf die Mauer gelegt werden soll.
    PS2: ich habe mir eine Funktion gemacht die eienn Ray castet. Sie gibt mir nur einen Informationsdatensatz zurück der so aussieht:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Structure GridIntersection
    2. Public BlockX As Integer
    3. Public BlockY As Integer
    4. Public X As Single
    5. Public Y As Single
    6. Public Distant As Single
    7. Public TexturScaleFaktor As Single
    8. Public HitWall As Boolean
    9. Public Shared Function Emty() As GridIntersection
    10. Dim tmp As New GridIntersection
    11. With tmp
    12. .HitWall = False
    13. .Distant = Single.MaxValue
    14. End With
    15. Return tmp
    16. End Function
    17. End Structure


    Hilft dir Vllt weiter. LG

    Edit: Habe den Code nur überflogen - ich glaube du machst das Raycasten schon wie in C dargestellt^^ Habe aber keine Zeile gefunden, die den Fischaugeneffekt rausrechnet

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

    @FreakJNS
    Danke für die antwort

    nein im prinzip verusche ich es wie in abbildung c zu machen. ich suche erst den ersten schnittpunkt horizontal/vertikal und dann ergeben sich die weiteren jaautomatisch (habe mich auch an dem tut von permadi orientiert).

    habe nun es etwas verbessern können,aber es geht immer noch nicht ganz so wie ich will: drehe ich zu stark nach links oder rechts kommt es zu fehlern. es geht iwie nur mit lookdirection im bereich von ca. -70° bis 70° ... Und -180° ergibt nicht die andere wand, sondern die ansicht von 0°... ich hasse trigonometrie...

    und bewegt man sich im feld so kommen komische streifen als bildfehler^^

    vllt kannst du mir noch helfen?

    im anhang die exe bisher. pfeiltasten hoch/runter änderst und die position in y-Richtung und links/rechts den lookdirection-Winkel. (und das flackern ist nur weil ich noch keine lust hatte eine performate darstellungsmethode zu wählen. CreateGraphics ist egtl das schlimmste was man machen kann :D)
    Dateien
    • RayCasting.exe

      (11,26 kB, 103 mal heruntergeladen, zuletzt: )

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

    desswegen, mach es mit vektoren und strahlensatz. Da fallen all die Probleme weg. Das ist der einzige Punkt der mir an permadi nicht gefällt - die erklärungen sind top, auf die Grenzwerte wird aber nicht eingegangen.

    Geb mal nur für spass Tan(270) in den Taschenrechner ein - der wird sich dann verabschieden. Darum geht es auch nur in diesem kleinen Bereich "fehlerfrei".
    Das du vorne das gleiche siehst wie hinten liegt daran, dass du keine abfrage machst in welche richtung du guckst. Tan(x) = Tan(x-180) = tan(x+180). Kommt also genau das gleiche Vorzeichen/Wert bei raus.

    Und wie gesagt, den Fischaugeneffekt kannst du rausrechnen.

    EDIT
    Geh am besten so vor wie ich: Erstelle als erstes den Algo zum Casten der Rays. Das hat noch nichts mit 3D/2.5D zutun und lässt sich wunderbar in 2D darstellen. So kannst du ausgiebig testen ob deine Berechnungen stimmen. Hier mal mein Testprogramm für meine verwendete Routine (das teil ist sehr ruckelig, da kein bisschen GDI optimiert). Verschieben kannst du Per linker Mausklick, rechter mausklick um Blöcke als Wand zu setzen und die Trackbar um den Winkel zu verändern.


    Ich Antworte mal hier im Thread:

    Sieh dir mal das Tutorial an, dort wird mit vektoren gerechnet. Den Code versteh ich zwar größtenteils nicht, die Beschreibungen sind aber ganz gut. Vektoren hört sich immer so kompliziert an, passiert eigentlich alles mit der logik des strahlensatzes: Erstes Bild ist für mich das Wichtigste.

    Hier mal eine Skizze von mir. LookX und LookY sind quasi die Vektoren der Blickrichtung - berechnet aus dem Winkel. Die 0.4 aus dem Beispiel kannst du anhand der Spielerposition berechnen, denn schnittpunkt mit dem Raster in X-Richtung ist dann = px - offsetX. Mit dem Schnittpunkt in y-richtung verfährt man genauso. Jede Menge Skizzen machen! Bei mir liegt alles voll davon xD



    Und wie gesagt, mach dir wirklich ein Demoprogramm um deinen Algo zu testen! Ich hatte vorher die Position nicht verändert (lag also genau auf dem Raster) und alles lief fehlerfrei. War ein kleiner Weltuntergang als ich das erstemal keine exakte Rasterposition hatte xDD darum Testen testen testen.
    Dateien

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „FreakJNS“ ()