-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSolidRenderer.cpp
More file actions
186 lines (147 loc) · 6.16 KB
/
SolidRenderer.cpp
File metadata and controls
186 lines (147 loc) · 6.16 KB
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include "SolidRenderer.hpp"
//#include <tbb/tbb.h> // Include, nur wenn TBB genutzt werden soll
#define EPSILON \
(1e-12) // Epsilon um ungenauigkeiten und Rundungsfehler zu kompensieren
/**
** Erstellt mittels Raycast das Rendering der mScene in das mImage
** Precondition: Sowohl mImage, mScene, mCamera müssen gesetzt sein.
**/
void SolidRenderer::renderRaycast() {
// This function is part of the base
if (mImage == NULL || mScene == NULL || mCamera == NULL) {
return;
}
std::cout << "Rendern mittels Raycast gestartet." << std::endl;
// Berechnung der einzelnen Rows in eigener Methode um die
// Parallelisierbarkeit zu verbessern
// Ohne parallelisierung:
// for(size_t i = 0; i < mImage->getHeight(); ++i ){
// computeImageRow( i );
// }
// Parallelisierung mit OpenMP:
#pragma omp parallel for
for(size_t i = 0; i < mImage->getHeight(); ++i )
{
computeImageRow( i );
}
// Parallelisierung mit TBB:
//tbb::parallel_for(size_t(0), mImage->getHeight(),
// /* lambda funktion*/ [&](size_t i) { computeImageRow(i); });
}
/**
* Aufgabenblatt 3: Hier wird das Raycasting implementiert. Siehe Aufgabenstellung!
* Precondition: Sowohl mImage, mScene und mCamera müssen gesetzt sein.
*/
void SolidRenderer::computeImageRow(size_t rowNumber) {
if (mImage == NULL || mScene == NULL || mCamera == NULL) {
return;
}
Color inititalColor = Color(0.0, 0.0, 0.0);
Color backgroundColor = Color(0.0, 0.0, 0.7); // blau
for (unsigned int columnNumber = 0; columnNumber < mImage->getWidth(); ++columnNumber) {
// Strahl zu dem Punkt erzeugen
Ray ray = mCamera->getRay(columnNumber, rowNumber);
// HitRecord für den Punkt aufbauen
HitRecord hitRecord;
// HitRecord initialisieren
hitRecord.color = inititalColor;
hitRecord.parameter = std::numeric_limits<double>::max();
hitRecord.modelId = -1;
hitRecord.triangleId = -1;
hitRecord.sphereId = -1;
hitRecord.recursions = 0;
if (mScene->intersect(ray, hitRecord, 0.1)) {
shade(hitRecord);
mImage->setValue(columnNumber, rowNumber, hitRecord.color);
}
else
mImage->setValue(columnNumber, rowNumber, backgroundColor);
}
}
/**
* Aufgabenblatt 4: Hier wird das raytracing implementiert. Siehe Aufgabenstellung!
*/
void SolidRenderer::shade(HitRecord &r) {
const unsigned int maxRecursions = 5;
// Vektor vom Schnittpunkt zur Lichtquelle
GLVector lightVector = mScene->getPointLights()[0] - r.intersectionPoint;
lightVector.normalize();
GLVector reflectionVector = r.normal * dotProduct(r.normal, lightVector) + crossProduct(crossProduct(r.normal, lightVector), r.normal) * -1;
reflectionVector.normalize();
const double kAmbient = 0.4;
const double kDiffuse = 0.4;
const double kSpecular = 0.2;
const double potency = 10.0;
// Prüfen, ob ein Hit erfolgte
if (r.modelId == -1 && r.sphereId == -1) {
return;
}
if (r.modelId != -1) {
if (r.modelId > mScene->getModels().size()) {
return; // modelId ist zu groß
}
r.color = mScene->getModels()[r.modelId].getMaterial().color;
} else if (r.sphereId != -1) {
if (r.sphereId > mScene->getSpheres().size()) {
return; // sphereId ist zu groß
}
r.color = mScene->getSpheres()[r.sphereId].getMaterial().color;
}
// Das Umgebungslicht und die Lichtuelle senden weißes Licht mit voller Intensität aus
// Dementsprechend sind die Werte von I_i und I_s gleich 1 und müssen nicht beachtet werden
double lightIntensity = kSpecular * ::std::pow( dotProduct(reflectionVector, r.rayDirection), potency)
+ kDiffuse * dotProduct(lightVector, r.normal)
+ kAmbient;
// Rundungsfehler beheben
if (lightIntensity > 1.0)
lightIntensity = 1.0;
if (lightIntensity < 0.0)
lightIntensity = 0.0;
// Da die Lichtquelle weißes Licht emittiert, müssen alle Farbanteile in gleichem Maß angepasst werden
r.color *= lightIntensity;
// Schattenberechnung
Ray shadeRay = Ray();
shadeRay.direction = mScene->getPointLights()[0] - r.intersectionPoint;
shadeRay.direction.normalize();
// Ursprung des Schattenstrahls etwas in Richtung Lichtquelle verschieben, damit sich Objekte nicht selbst schneiden
shadeRay.origin = r.intersectionPoint + shadeRay.direction * 0.1;
HitRecord shadeRecord = HitRecord();
shadeRecord.color = r.color;
shadeRecord.parameter = (mScene->getPointLights()[0] - r.intersectionPoint).norm();
shadeRecord.modelId = -1;
shadeRecord.triangleId = -1;
shadeRecord.sphereId = -1;
shadeRecord.recursions = 0;
if (mScene->intersect(shadeRay, shadeRecord, 0.01)) {
// Der Schnittpunkt liegt im Schatten. Dementsprechend muss die Farbintensität reduziert werden
r.color *= 0.4;
}
// Reflexion berechnen
double reflection = 0.0;
if (r.modelId != -1) {
reflection = mScene->getModels()[r.modelId].getMaterial().reflection;
} else {
reflection = mScene->getSpheres()[r.sphereId].getMaterial().reflection;
}
if (reflection == 0.0 || maxRecursions == r.recursions) {
// Nichtreflektierendes Material getroffen oder maximale Rekursionstiefe erreicht => Abbruch
return;
}
// Bei perfekter Reflexion muss der HitRecord
if (reflection == 1.0) {
r.color = Color(0.0, 0.0, 0.0);
}
Ray reflectionRay = Ray();
reflectionRay.direction = r.normal * dotProduct(r.normal, -1 * r.rayDirection) + crossProduct(crossProduct(r.normal, -1 * r.rayDirection), r.normal) * -1;
reflectionRay.direction.normalize();
// Ursprung des Reflexionsstrahls etwas in Strahlrichtung verschieben, damit sich Objekte nicht selbst schneiden
reflectionRay.origin = r.intersectionPoint + reflectionRay.direction * 0.01;
r.modelId = -1;
r.triangleId = -1;
r.sphereId = -1;
r.parameter = std::numeric_limits<double>::max();
r.recursions++;
if (mScene->intersect(reflectionRay, r, 0.01)) {
shade(r);
}
}