Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

24.11.2013, 14:38

Mein Raytracer in C++/SFML

Hey Leute,
mein in C++/SFML 2.1 entwickelter Raytracer nimmt so langsam Form an.
Deswegen hab ich mich entschlossen ihn euch mal zu präsentieren und euch vor allem nach eurer Meinung zu meinem Programmierstil fragen.

Erstmal ein paar aktuelle Bilder:


(Link)

Das ist jetzt so ziemlich die neueste Version. (Renderzeit um die 3s)
Vorhanden (wenn auch teilweise beschränkt):
-Kugeln
-Dreiecke
-Beleuchtung
->Schatten
-Texturen
-Reflektion


(Link)

Das hier stammt aus einer älteren Version und zeigt 256 Kugeln mit unterschiedlicher Farbe und Reflektion.
Allerdings lag die Renderzeit hier bei ca. 330s (5min 30s) :D
Ja man sieht an der Performance hab ich noch garnichts gemacht.

Aber jetzt kommen wir mal zu dem wichtigeren Teil:
dem Code:
main.cpp
Die Renderer-Klasse (.h und .cpp)
Die RenderObject-Klasse (.h und .cpp)
Die Triangle-Klasse (.h und .cpp)
Die Sphere-Klasse (.h und .cpp)
util.h

Sämtlicher Code wurde allein von mir geschrieben, einzig die mathematischen Formeln sind nicht selbst ausgedacht (warum auch? :D ).

Freue mich auf Feedback und Kritik :)

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

24.11.2013, 15:39

- Keine Kommentare im Code?!
- Renderer::render ist furchtbar zu lesen, da viel doppelter Code und sehr tief verschachtelt. Reflexionen kann man auch rekursiv berechnen ...
- Du kennst scheinbar kein const bei Methoden. Alle Methoden, die den Zustand des Objekts nicht verändern (insbesondere Getter), sollten const sein.
- RenderObject sollte einen Zeiger auf ein Material speichern, nicht das Material selbst! Sonst hast du sehr viele eigenständige Materialien.
- Dein Renderer hat eine Variable direction, die nirgendwo benutzt wird (jedenfalls sehe ich das nicht).
- Du brauchst auf jeden Fall Klassen für Kameras und Lichtquellen.
- Ich finde es nicht gut, dass der Renderer die Objekte zerstört, die er gar nicht selbst erzeugt hat.
- Absolute Pfade bei #include sollte man vermeiden.
- Triangle::setVertex und getVertex prüfen zwar, ob der Index nicht zu klein/groß ist, aber tun im Fehlerfall nichts. Da solltest du eine Assertion einbauen oder eine Exception werfen (Performance ist dir ja sowieso egal ;)). Was bringt mir der leere Vertex, den getVertex(42) liefern würde?
- Wenn du unsigned int für Indizes benutzen würdest, müsstest du nicht testen, ob sie kleiner als 0 sind.
- NULL ist C. In C++ gibt es dafür nullptr, das sollte man auf jeden Fall benutzen!
- Schau dir das Schlüsselwort override mal an. Das ist praktisch.
- Perfekt von "hit" ist ebenfalls "hit", nicht "hitted".

3

24.11.2013, 16:50

Ich mache mich an die Arbeit ;)
Danke für die Tipps :)
-Kommentare haben für mich bis jetzt so gereicht. Ich finde es oft schwierig, zu sagen was man kommentieren sollte und was nicht, und wenn was man dann schreiben sollte.
-Ja die Funktion (oder Methode wie auch immer ;) ) ist auch so mein Sorgenkind. Aber ich mach mich gleich daran, wenn ich die kleineren Sachen hab ;) //EDIT: Stark verkürzt. Siehe unten.
-Ist gemacht ;)
-Ich hab jetzt eine Referenz genommen. Kommt ja im Prinzip auf das Gleiche raus oder?
-Das sollte die Blickrichtung der Kamera werden ;) Hab das allerdings noch nicht implementiert. Mir fällt gerade so auf, dass ich der Kamera (in einer eigenen Klasse dann) auch ein Transform geben sollte.
-Siehe Punkt darüber ;)
-Sollte ich dafür lieber einen ObjectManager schreiben?
-Ja ich weiß, aber die hat Visual Studio bei dem Projekt irgendwie nicht erkannt. //EDIT: Hab bei den Includeverzeichnissen einfach $(ProjectDir) hinzugefügt und jetzt gehts wieder relativ. :)
-Wird eingebaut ;)
-Ist geändert :)
-Danke wusste ich nicht, hab es aber geändert.
-Werde ich machen.
-Ja, ich weiß, aber bei "hitted" wird mir klarer was gemeint ist.

Jedenfalls werde ich jetzt ein bisschen daran rumbasteln und dann später nochmal den neuen Code hochladen.
Wem sonst noch was auffällt, darf gerne seine Meinung dazu sagen :D

EDIT:
Vielen Dank für die Idee mit dem rekursiv ;)
So ist es deutlich besser:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
sf::Color Renderer::colorAt(const sf::Vector3f& position, const sf::Vector3f& direction, unsigned int reflectionTimes)
{
    float nearestDistance = 100.0f;
    RenderObject* nearestObject = nullptr;
    sf::Vector3f nearestPoint = position;
    sf::Vector2f nearestUVCoordinates = sf::Vector2f(0.0f, 0.0f);
    for(std::vector<RenderObject*>::iterator itRenderObjects(renderObjects.begin()), itEnd(renderObjects.end());
        itRenderObjects!=itEnd;
        ++itRenderObjects)
    {
        sf::Vector3f curPoint;
        sf::Vector2f curUVCoordinates;
        int outside = (*itRenderObjects)->testRay(position, direction, curPoint, curUVCoordinates);
        if(outside>0)
        {
            float curDistance = length(curPoint - position);
            if(curDistance < nearestDistance)
            {
                nearestDistance = curDistance;
                nearestObject = *itRenderObjects;
                nearestPoint = curPoint;
                nearestUVCoordinates = curUVCoordinates;
            }
        }
    }
    sf::Color color = backgroundColor;
    if(nearestObject != nullptr)
    {
        sf::Vector3f normal = nearestObject->getNormal(nearestPoint);
        sf::Vector3f directionToLight = normalize(lightPos-nearestPoint);
        color = nearestObject->getMaterial().getColorByTexture(nearestUVCoordinates);
        bool lighten = true;
        for(std::vector<RenderObject*>::iterator itRenderObjects(renderObjects.begin()), itEnd(renderObjects.end());
            itRenderObjects!=itEnd;
            ++itRenderObjects)
        {
            sf::Vector3f curPoint;
            sf::Vector2f curUVCoordinates;
            int outside = (*itRenderObjects)->testRay(nearestPoint + 0.00001f * normal , directionToLight, curPoint, curUVCoordinates);
            if(outside>0 && length(curPoint - nearestPoint) < length(lightPos - nearestPoint))
            {
                color = sf::Color::Black;
                lighten = false;
                break;
            }
        }
        if(lighten)
        {
            float dotProduct = dot(normal, directionToLight);
            if(dotProduct>0)
            {
                color = sf::Color(static_cast<sf::Uint8>(color.r * dotProduct), 
                                  static_cast<sf::Uint8>(color.g * dotProduct),
                                  static_cast<sf::Uint8>(color.b * dotProduct));
            }
            else
            {
                color = sf::Color::Black;
            }
            float refl = nearestObject->getMaterial().reflection;
            if(refl>0)
            {
                if(reflectionTimes>0)
                {
                    reflectionTimes--;
                    sf::Vector3f reflected = direction - 2.0f * dot(direction, normal) * normal;
                    sf::Color reflectedColor = colorAt(nearestPoint, reflected, reflectionTimes);
                    color += sf::Color(static_cast<sf::Uint8>(refl * reflectedColor.r),
                                   static_cast<sf::Uint8>(refl * reflectedColor.g),
                                   static_cast<sf::Uint8>(refl * reflectedColor.b));
                }
            }
        }
    }
    return color;
}

void Renderer::render()
{
    sf::Image image;
    image.create(800, 600);
    for(unsigned int y = 0; y < window.getSize().y; ++y)
    {
        for(unsigned int x = 0; x < window.getSize().x; ++x)
        {
            sf::Vector3f curDirection = normalize(sf::Vector3f(x-window.getSize().x/2.0f, window.getSize().y/2.0f-y, 400.0f));
            sf::Color pixelColor = colorAt(position, curDirection, 3);
            image.setPixel(x, y, pixelColor);
        }
    }
    renderResult.loadFromImage(image);
    window.draw(sf::Sprite(renderResult));
}

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »poorsider« (24.11.2013, 17:47)


Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

4

24.11.2013, 19:24

Bei Booleschen Werten schreiben einige Leute ja auch ein Is davor. Vor allem bei Funktionen die einen Bool zurück geben sieht man das oft. Demnach könntest du die Variable ja wasHit nennen. Nur als Vorschlag.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

5

17.03.2014, 15:17

Hey Leute,
ich habe jetzt zwar nicht allzu viel neues vorzuzeigen, doch wollte ich euch mal meine neuen Ergebnisse zeigen:
Als erstes natürlich ein aussagekräftiges Bild:

(Link)


Geändert hat sich eigentlich nur, dass es jetzt eben mehrere Lichtquellen geben kann. Und intern hat sich halt vieles getan. Ich selbst finde, dass das "Endprodukt" jetzt schon viel "runder" wirkt also noch beim Themenstart.
Da ich jetzt allerdings viel mehr Klassen (und somit auch Dateien) habe, möchte ich hier nicht so viele Links einbinden. Gibt es eine Art Online-Speicher für Code, bei dem ich einfach mein Projekt hochladen kann und es sich jeder anschauen kann? Kenne mich da nicht so aus. Aber solange könnt ihr ja schon mal Kritik am derzeitigen Entwicklungsstand da lassen. Würde den Raytracer gerne noch verbessern, vor allem da ich ihn wahrscheinlich für eine mündliche Abiturprüfung brauche. Und da gilt dann natürlich, je mehr der kann, desto mehr kann ich vorführen ;)

Also her mit euren Meinungen und Ideen :)

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

6

17.03.2014, 15:49

Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

7

17.03.2014, 16:35

@Architekt Vielen Dank :) Hab zwar erstmal etwas grübeln müssen aber hat jetzt letztendlich doch geklappt: Raytracing

Wer Lust hat kann sich das gerne mal anschauen und mir dann auch dazu Bescheid geben. Freue mich darauf :)

8

18.03.2014, 16:19

*Push*

Gibt's hier irgendwelche Meinungen/Kritik/Verbesserungsvorschläge zum "Endprodukt" oder zum Code? :)

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

9

18.03.2014, 16:32

Ein Push innerhalb von nur einem Tag ist hier nicht gern gesehen. Da es mitten in der Woche ist, habe ich und sicher auch andere hier, nicht viel Zeit sich da mal durchzuwühlen. Warte doch bis zum WE. ;)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

10

18.03.2014, 17:37

Alles klar :)
Sorry wusste ich nicht ;)

Werbeanzeige