86{
87 RayTracer::Scene scene;
88
91 Math::Vector3D bs{2.0f * scale * aspect, 0.0f, 0.0f};
92 Math::Vector3D ls{0.0f, 2.0f * scale, 0.0f};
93 Math::Point3D origin{
97 };
98
99 scene.setCamera(
100 RayTracer::Camera(
102 RayTracer::Rectangle3D(origin, bs, ls)
103 )
104 );
105
106 scene.setAmbientLight(
107 std::make_unique<RayTracer::AmbientLight>(
108 static_cast<float>(cfg.
ambient)
109 )
110 );
111
112
114 scene.addLight(
115 std::make_unique<RayTracer::DirectionalLight>(
116 d.direction,
117 static_cast<float>(cfg.
diffuse)
118 )
119 );
120 }
121
122
123 for (
const auto &p : cfg.
points) {
124 scene.addLight(
125 std::make_unique<RayTracer::PointLight>(
126 p.position,
127 static_cast<float>(cfg.
diffuse)
128 )
129 );
130 }
131
132 for (
const auto &s : cfg.
spheres) {
133 scene.addObject(
134 std::make_shared<RayTracer::Sphere>(
135 s.center,
136 s.radius,
137 std::make_shared<RayTracer::FlatColor>(s.color)
138 )
139 );
140 }
141
142 for (
const auto &p : cfg.
planes) {
143 Math::Vector3D normal{0.0f, 0.0f, 0.0f};
144 if (p.axis == 'X') normal.x = 1.0f;
145 else if (p.axis == 'Y') normal.y = 1.0f;
146 else normal.z = 1.0f;
147
148 Math::Point3D pt{0.0f, 0.0f, 0.0f};
149 if (p.axis == 'X') pt.x = p.position;
150 else if (p.axis == 'Y') pt.y = p.position;
151 else pt.z = p.position;
152
153 scene.addObject(
154 std::make_shared<RayTracer::Plane>(
155 pt,
156 normal,
157 std::make_shared<RayTracer::FlatColor>(p.color)
158 )
159 );
160 }
161
164
165
166 for (int y = 0; y < h; ++y) {
167 for (int x = 0; x < w; ++x) {
168 double u = (x + 0.5) / w;
169 double v = (y + 0.5) / h;
170 RayTracer::Ray ray = scene.getCamera().ray(u, v);
171
172 Color finalColor(0, 0, 0);
173 double closest_t = std::numeric_limits<double>::max();
174 std::shared_ptr<RayTracer::IPrimitive> closestObject = nullptr;
175 Math::Point3D hitPoint;
176 Math::Vector3D normal;
177
178 for (const auto &obj : scene.getObjects()) {
179 double t;
180 Math::Point3D pt;
181 Math::Vector3D n;
182 if (obj->intersect(ray, t, pt, n) && t < closest_t) {
183 closest_t = t;
184 closestObject = obj;
185 hitPoint = pt;
186 normal = n;
187 }
188 }
189
190 if (closestObject) {
191
192 if (scene.getAmbient()) {
193 finalColor = scene.getAmbient()->illuminate(ray, *closestObject, hitPoint);
194 }
195
196 for (const auto &light : scene.getLights()) {
197 if (auto *dirLight = dynamic_cast<RayTracer::DirectionalLight *>(light.get())) {
198 Math::Vector3D lightDir = dirLight->getDirection() * -1.0;
199 lightDir = lightDir / lightDir.
length();
200
201
202 const double bias = 1e-4;
203 Math::Point3D shadowOrigin = hitPoint + normal * bias;
204 RayTracer::Ray shadowRay(shadowOrigin, lightDir);
205 bool shadowed = false;
206
207 for (const auto &obj : scene.getObjects()) {
208 if (obj != closestObject) {
209 double tTmp;
210 Math::Point3D tmpPt;
211 Math::Vector3D tmpN;
212 if (obj->intersect(shadowRay, tTmp, tmpPt, tmpN)) {
213 shadowed = true;
214 break;
215 }
216 }
217 }
218 if (!shadowed) {
219 double diff = std::max(0.0, normal.
dot(lightDir));
220 Color lightColor = light->illuminate(ray, *closestObject, hitPoint);
221 finalColor.r = std::min(finalColor.r +
static_cast<int>(lightColor.
r * diff), 255);
222 finalColor.g = std::min(finalColor.g +
static_cast<int>(lightColor.
g * diff), 255);
223 finalColor.b = std::min(finalColor.b +
static_cast<int>(lightColor.
b * diff), 255);
224 }
225
226 } else if (auto *pLight = dynamic_cast<RayTracer::PointLight *>(light.get())) {
227 Math::Vector3D lightDir = pLight->getPosition() - hitPoint;
228 double dist = lightDir.
length();
229 lightDir = lightDir / dist;
230
231 const double bias = 1e-4;
232 Math::Point3D shadowOrig = hitPoint + normal * bias;
233 RayTracer::Ray shadowRay(shadowOrig, lightDir);
234 bool inShadow = false;
235 for (const auto &obj : scene.getObjects()) {
236 if (obj != closestObject) {
237 double tTmp;
238 Math::Point3D tmpPt;
239 Math::Vector3D tmpN;
240 if (obj->intersect(shadowRay, tTmp, tmpPt, tmpN) && tTmp < dist) {
241 inShadow = true;
242 break;
243 }
244 }
245 }
246 if (!inShadow) {
247 double diff = std::max(0.0, normal.
dot(lightDir));
248 Color c = light->illuminate(ray, *closestObject, hitPoint);
249 finalColor.r = std::min(finalColor.r +
static_cast<int>(c.
r * diff), 255);
250 finalColor.g = std::min(finalColor.g +
static_cast<int>(c.
g * diff), 255);
251 finalColor.b = std::min(finalColor.b +
static_cast<int>(c.
b * diff), 255);
252 }
253 }
254 }
255 }
256
257 display.
pushPixel(x, y, Display::Pixel(finalColor.r, finalColor.g, finalColor.b));
258
259 }
260 }
262}
std::vector< Plane > planes
std::vector< Point > points
std::vector< Sphere > spheres
std::vector< Directional > directionals
void pushPixel(int x, int y, const Pixel &px)
double dot(const Vector3D &o) const