Frage

Ich versuche als Hobbyprojekt einen einfachen Raytracer zu schreiben und es funktioniert jetzt alles gut, außer dass ich weiche Schatten überhaupt nicht zum Laufen bringen kann.Meine Vorstellung von weichen Schatten ist, dass die Lichtquelle einen Ort und einen Radius hat.Um einen Schattentest für dieses Licht durchzuführen, nehme ich den Punkt, an dem der Primärstrahl ein Objekt in der Szene trifft, und wirf eine n-Anzahl von Strahlen in Richtung der Lichtquelle, wo jeder neue Strahl eine Zufallskomponente zu jeder Achse hat, wobei die Zufallskomponente variiert zwischen -radius und radius.

Wenn ein solcher Strahl ein Objekt in der Szene trifft, erhöhe ich einen Trefferzähler (wenn ein Strahl mehrere Objekte trifft, erhöht er sich immer noch nur um eins).Wenn es ohne Kollisionen zur Lichtquelle gelangt, füge ich den Abstand des Schnittpunkts des Primärstrahls zum Mittelpunkt der Lichtquelle zu einer Variablen hinzu.

Wenn n Proben genommen wurden, berechne ich das Verhältnis der Strahlen, die kollidiert sind, und multipliziere die Farbe des Lichts mit diesem Verhältnis (also wird ein Licht mit der Farbe 1000,1000,1000 zu 500,500,500 mit einem Verhältnis von 0,5, also der Hälfte der Strahlen). zusammengestoßen sind).Dann berechne ich die durchschnittliche Entfernung zur Lichtquelle, indem ich die Entfernungsvariable von früher durch die Anzahl der nicht kollidierenden Strahlen dividiere.Ich gebe diese Variable zurück und die Funktion wird beendet.

Das Problem ist:es funktioniert nicht.Zumindest nicht ganz.Wie es aussieht, kann man sehen Hier.Sie können sehen, dass es weichen Schatten ähnelt, wenn Sie ganz genau blinzeln.

Ich verstehe es nicht, mache ich hier einen grundsätzlichen Fehler oder handelt es sich um einen winzigen Fehler?Ich bin mir ziemlich sicher, dass das Problem bei dieser Methode liegt, denn wenn ich die Anzahl der teilweise beleuchteten Pixel zähle, die direkt durch diese Methode erzeugt werden, sind es nur etwa 250, obwohl es viel mehr sein sollten.Und wenn Sie sich das Bild genau ansehen, können Sie einige teilweise beleuchtete Pixel erkennen, was darauf hindeutet, dass der Rest des Codes die teilweise beleuchteten Pixel problemlos verarbeitet.

Hier ist das tatsächliche Licht für den Soft-Shadows-Kurs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstRayTracer
{
  public class AreaLight : ILight
  {
    private const int _radius = 5;
    private const int _samples = 16;
    public Color Color { get; set; }
    public Vector Location { get; set; }
    #region ILight Members

    public float GetLightingInformation(Vector point, ISceneObject[] scene, out Color color)
    {
      int intersectCount = 0;
      float distance = -1;
      for(int i = 0; i < _samples; i++)
      {
    bool intersects = false;
    float rand = 0;
    rand = _radius - (float)(new Random().NextDouble()*(2*_radius));
    foreach (ISceneObject obj in scene)
    {
      Vector iPoint;

      Vector loc = new Vector(Location.X + rand, Location.Y + rand, Location.Z + rand);

      if (!obj.Intersect(new Ray(point, loc), out iPoint))
      {
        distance += (Location - point).SqLength;

      }
      else
      {
        intersects = true;
        distance -= (Location - point).SqLength;
      }
    }
    if (intersects)
      intersectCount++;
      }
      float factor = 1-((float)intersectCount/_samples);

      color = new Color(factor*Color.R, factor*Color.G, factor*Color.B);

      return (float)Math.Sqrt(distance / (_samples - intersectCount));
    }


    #endregion
  }
}
War es hilfreich?

Lösung

Versuchen Sie für jede Komponente von „loc“ eine andere „rand“ zu erzeugen. Wie ist Ihre Jitterbasierten Punkte liegen alle auf einer Linie.

Andere Tipps

kleinen Punkt, aber das ist die beste Verwendung der Zufall Klasse ..

 for(int i = 0; i < _samples; i++)
      {
        bool intersects = false;
        float rand = 0;
        rand = _radius - (float)(new Random().NextDouble()*(2*_radius));

sollte dies nicht sein ..

    var rnd = new Random()    
    for(int i = 0; i < _samples; i++)
              {
                bool intersects = false;
                float rand = 0;
                rand = _radius - (float)(rnd.NextDouble()*(2*_radius));

Sie erzeugen tatsächlich den Punkt auf der Linie auf einer Linie mit Richtung (1, 1, 1). Ist die Lichtquelle wirklich linear?

Auch ich kann kaum etwas in Ihrem Beispiel sehen. Könnten Sie Ihre Kamera näher an die seinem Schatten und nicht zeigt aus der Richtung des Lichts machen?

Sehen Sie, deshalb bin ich auf diese Seite gekommen :)

Jede Achse hat jetzt ihren eigenen Zufall und es sieht viel besser aus.Es sieht immer noch etwas seltsam aus, eine Erhöhung der Anzahl der Samples hilft jedoch.Es sieht jetzt so aus Das.

Kennen Sie einen effizienteren Weg, die Musterbildung zu reduzieren?

Die größte Hilfe jedoch:Zufall wird nicht für jede Stichprobe instanziiert.Es hat meine Rendergeschwindigkeit mit weichen Schatten deutlich verdreifacht!Ich wusste nie, dass die Instanziierung von Random so kostspielig ist.Wow.

Vielen Dank.

In Ihrer Antwort aufgefordert, für eine verbesserte Art und Weise, weiche Schatten zu machen. Eine Verbesserung könnte sein, stattdessen alle Strahlen vom selben Punkt von Randomisierung, jedem Strahl effektiv ihnen eine andere auf allen Achsen versetzt zu geben, ein separates kleines Fenster zu geben, randomisieren. Dies führt zu einer gleichmäßigeren Verteilung führen soll. Ich weiß nicht, ob das klar war, sondern eine andere Art und Weise zu beschreiben, als ein Gitter ist, die senkrecht zur Schattenstrahl ist. Jede Fliese im Gitter enthält eine der n Schattenstrahl aber die Lage in dem Gitter ist zufällig. Hier Sie einen Teil eines Tutorials finden können, die beschreibt, wie diese verwendet werden können, für weiche Schatten.

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