Frage

Grundsätzlich versuche ich, eine 2D -Höhenmap mit einem sehr einfachen Raycasting -System zu schatten, das im Grunde genommen nur überprüft, ob der Strahl abgefangen wird, bevor es sein sollte, um es zu schatten. Allerdings funktioniert es nicht richtig und ich habe jetzt einige Stunden mit mir den Kopf geknall Sehen Sie es oder so komplex, dass ich meinen Kopf nie um ihn wickeln werde.

Ich habe eine Karte wie diese:Map

Und das Raycasting gibt mir dies (denken Sie daran, es sind nur Debug-Farben; Rot ist Ray-Interception, aber vor der beabsichtigten Position (so Schattierung) wäre Blue Ray Interception an der richtigen Stelle (so hervorhebt oder einfach wie Is) und ist Gelb bedeutet, dass der Punkt vor dem Ausschnitt der WHHE-Schleife überhaupt keine Strahleninteraktion hatte).Badx2

Das Ergebnis sollte mit rot an Backfacing-Hängen und Bereichen hinter großen Bergen (Schatten) und blau an sonnenverkehrsförmigen Hängen (Höhepunkte) sein. Es sollte kein Gelb geben. Dieses Bild zeigt also, dass entweder alle Strahlen auf den falschen Ort treffen oder die Strahlen immer an einem anderen Ort gekreuzt werden, bevor sie ihr Ziel erreichen, was unmöglich ist.

Zu diesem Zeitpunkt vermute ich sehr, dass das Problem mit meinem Trig ist.

Hier ist die Ray -Klasse:

class Ray
    {
        public Vector2 Position;
        public Vector2 Direction; // Think in XZ coordinates for these (they are on a perpendicular plane to the heightmap)
        // Angle is angle from horizon (I think), and height is height above zero (arbitrary)
        public float Angle, Height;
        private TerrainUnit[,] Terrainmap;
        private float U, V;

        public Ray(ref TerrainUnit[,] Terrainmap, float height, float angle)
        {
            this.Terrainmap = Terrainmap;
            this.Angle = angle;
            this.Height = this.V = height;

            // Create new straight vector
            this.Direction = new Vector2(0, 1);
            // Rotate it to the values determined by the angle
            this.Direction = Vector2.Transform(Direction, Matrix.CreateRotationX(Angle));
            //this.Direction = new Vector2((float)Math.Sin(angle), -(float)Math.Cos(angle));
            // Find the horizontal distance of the origin-destination triangle
            this.U = V / (float)Math.Tan(Angle);
            // Bleh just initialize the vector to something
            this.Position = new Vector2(U, V);
        }

        public void CastTo(int x, int y)
        {
            // Get the height of the target terrain unit
            float H = (float)Terrainmap[x, y].Height;
            // Find where the ray would have to be to intersect that terrain unit based on its angle and height
            Position = new Vector2(x - U, H + V);

            float Z = 1000 * (float)Terrainmap[0, y].Height;

            // As long as the ray is not below the terrain and not past the destination point
            while (Position.Y > Z && Position.X <= x)
            {
                // If the ray has passed into terrain bounds update Z every step
                if (Position.X > 0) Z = 1000 * (float)Terrainmap[(int)Position.X, y].Height;
                Position.X += Direction.X;
                Position.Y += Direction.Y;
            }

            Terrainmap[x, y].TypeColor = Color.Yellow;
            if ((int)Position.X == x) Terrainmap[x, y].TypeColor = Color.Blue;
            else Terrainmap[x, y].TypeColor = Color.Red;
        }
    }

Auch als Formalität, die Funktion, die jeden Strahl wirkt und wie ich das nenne:

if (lighting) CastSunRays(1f, MathHelper.PiOver4);

    private void CastSunRays(float height, float angle)
    {
        Ray ray = new Ray(ref Terrainmap, height, angle);

        for (int x = 0; x < Width; x++)
            for (int y = 0; y < Height; y++)
                ray.CastTo(x, y);
    }
War es hilfreich?

Lösung

Am Ende habe ich einen viel einfacheren Ansatz mit verwendet Bresenhams Linienalgorithmus Um den Abfangpunkt zu finden; Ich stelle mir vor, es ist viel schneller und effizienter als die Art und Weise, wie ich es versucht hätte.

Andere Tipps

Meine Vermutung ist das, wenn deine Direction Der Vektor wird auf angewendet Position, es überschreitet die untere Grenze (Position.Y > -1) Bevor es die Chance hat, die Oberfläche zu treffen (Position.Y <= Terrainmap[(int)Position.X, y].Height).

Sie können versuchen, die untere Grenze zu verringern oder Ihre nachzuordnen if/while Tests.

Ein weiteres Problem könnte sein, dass die Direction Der Vektor ist im Vergleich zu Ihrem Höhenbereich zu groß. Der Abstand zwischen zwei benachbarten Pixeln beträgt 1, während der gesamte Bereich der Höhenunterschiede im Bereich (-1,1) enthalten ist. Dies gibt a sehr Flache Oberfläche aus Sicht der Strahlenkasters. Wenn der Direction Vektor wird auf die angewendet Position Der Vektor ist einen relativ kleinen Schritt über die Länge und einen relativ großen Schritt über die Höhe.

@Maltor: Ich wollte eigentlich Ihre eigene Antwort kommentieren, aber aufgrund meines Rufs bin ich derzeit nicht in der Lage.

Ich habe auch den Linienansatz des Bresenhams verwendet und die Berechnungszeit auf 1/10 gesenkt!

Ein laufendes Beispiel dafür kann in meinem Github -Projekt betrachtet werden Texturgenerator-Online. Das Geländewerkzeug verwendet diesen Ansatz.

Terrain tool

Siehe Funktion setTerrainShadow() bei tex_terrain.js

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top