В настоящее время я работаю над трассировщиком лучей для школьного проекта, и для этого этапа курса нам нужно реализовать затенение объектов с помощью системы освещения и Blinn-Phong
алгоритм.
Ниже приведено окончательное изображение, если все сделано правильно …
На данный момент я еще не дошел до отражений и теней, просто пытаясь сначала заставить затенение работать и продолжать получать полученное изображение …
Как видно, области с наибольшим количеством зеркальных отражений становятся зелеными, и в некоторых местах вокруг чайника появляются странные черные артефакты. Я часами читаю и тестирую и не могу понять, почему! Я на 90% уверен, что правильно реализую алгоритм.
Вот мой код, который имеет отношение к этой проблеме …
void shade(RGB& shading, std::vector<Light> lights, Triangle t, Ray& r, Vector3 loc) {
float intensity = 1 / std::sqrt(lights.size());
for (std::size_t i = 0; i < lights.size(); ++i) {
Vector3 n = t.get_normal();
n.normalize();
Vector3 v = r.dir * -1;
v.normalize();
Vector3 l = lights[i].position - loc;
l.normalize();
Vector3 h = v + l;
h.normalize();
float diffuse = MAX(0, n.dot(l));
float spec = std::pow(MAX(0, n.dot(h)), t.fill.shine);
shading.r += (t.fill.kd * diffuse * t.fill.rgb.r + t.fill.ks * spec) * intensity;
shading.g += (t.fill.kd * diffuse * t.fill.rgb.g + t.fill.ks * spec) * intensity;
shading.b += (t.fill.kd * diffuse * t.fill.rgb.b + t.fill.ks * spec) * intensity;
}
}
// Main function
int main(int argc, char* argv[]) {
// Set input and output file names
std::string in_file = (argc > 1) ? argv[1] : "teapot-3.nff";
std::string out_file = (argc > 2) ? argv[2] : "output.ppm";
// Parse the NFF file and get the Viewpoint and Background data
NFFParser parser(in_file);
parser.read_file();
Viewpoint view = parser.getViewpoint();
Background background = parser.getBackground();
// Camera creation
Camera camera(view);
// Allocate array of pixels and create camera instance
Pixel* pixels = new Pixel[camera.x_res * camera.y_res];
// Collect object data to iterate over
std::vector<Polygon> polygons = parser.getPolygons();
std::vector<Patch> patches = parser.getPatches();
std::vector<Light> lights = parser.getLights();
std::vector<Triangle> triangles;
// Convert all polygons and patches to trianlges and
// build a vector of triangles to iterator over
for (std::size_t i = 0; i < polygons.size(); ++i) {
std::vector<Triangle> v = polygons[i].fan_to_triangles();
triangles.insert(triangles.end(), v.begin(), v.end());
}
for (std::size_t i = 0; i < patches.size(); ++i) {
std::vector<Triangle> v = patches[i].fan_to_triangles();
triangles.insert(triangles.end(), v.begin(), v.end());
}
std::cout << "Testing for intersections among objects..." << std::endl
<< "...this may take a moment..." << std::endl
<< "==========================================" << std::endl;// Iterator over all pixels in the array
for (int y = 0; y < camera.y_res; ++y) {
for (int x = 0; x < camera.x_res; ++x) {
float t = INF;
Triangle closest;
// Map pixel to image plane coordinates
Vector3 image_location = camera.map_to_image(x, y);
Ray r(camera.e, image_location - camera.e);
// Iteration over Polygons
for (std::vector<Triangle>::iterator it = triangles.begin(); it != triangles.end(); ++it) {
if (it->intersects(&r, t) && t < r.t_min) {
closest = *it;
r.t_min = t;
}
}
if (r.t_min == INF) {
set_pixel(pixels, y, x, camera.y_res, background.rgb);
continue;
}
RGB shading;
shade(shading, lights, closest, r, image_location);
set_pixel(pixels, y, x, camera.y_res, shading);
}
}// Write the array of pixels to the output PPM file
PPMWriter writer(out_file);
writer.write_pixels(pixels, camera.x_res, camera.y_res);
// Deallocate pixels array to avoid memory leaks
delete [] pixels;
return 0;
}
Любое руководство или помощь будет принята с благодарностью!
РЕДАКТИРОВАТЬ
Зеленая окраска исправлена, но RGB-компонент ограничен, но черный артефакт все еще остается проблемой.
Что касается зеленых битов, то при расчете цвета вы переполняете то, что может вписаться в красный компонент пикселя. Это можно увидеть, если посмотреть на RGB медного цвета рядом с зеленым (0xFE9E4E) по сравнению с тем, что находится в зеленой зоне (0x019D4F).
Вам нужно будет включить некоторые проверки переполнения в ваши расчеты.
Других решений пока нет …