Я не могу отследить более 1 сферы по алгоритму трассировки лучей - PullRequest
0 голосов
/ 13 марта 2020

в приведенном ниже коде я хочу нарисовать все эти 3 сферы (сфера, сфера1, сфера2 в векторе "s") с помощью алгоритма трассировки лучей. Если я рисую 1 сферу, это дает хороший результат, но от 2 до n изображение искажается.

Я не могу поймать свою ошибку в этом коде. Не могли бы вы мне помочь? Как я могу увидеть три сферы?

#include <fstream>
#include <cmath>
#include <vector>
using namespace std;

struct Vec{
    double x,y,z;
    Vec(double x, double y, double z): x(x), y(y), z(z){}

    Vec operator + (const Vec& v) const {
        return Vec(x + v.x, y + v.y, z + v.z); 
    }

    Vec operator - (const Vec& v) const { 
        return Vec(x-v.x, y-v.y, z-v.z); 
    }

    Vec operator * (double d) const {
         return Vec(x*d, y*d, z*d); 
    } 

    Vec operator / (double d) const { 
        return Vec(x/d, y/d, z/d); 
    }

    Vec normalize() const {
        double norm = sqrt(x*x + y*y + z*z);
        return Vec(x/norm,y/norm,z/norm);
    }
};

inline double dot(const Vec& u, const Vec& v) {
  return (u.x*v.x + u.y*v.y + u.z*v.z);
}

struct Ray{
    Vec origin, direction;
    Ray(const Vec& origin, const Vec& direction): origin(origin), direction(direction){}
};



struct Sphere{
    Vec center;
    double radius;
    Sphere(const Vec& center, double radius): center(center), radius(radius){}

    Vec getNormal(const Vec& point) const { return (point - center) / radius; } // Küre üzerindeki normal

    bool intersect(const Ray& ray, double &t) const { // t = parameter
    const Vec ori = ray.origin; //e 
    const Vec dir = ray.direction; //d
    const Vec origintocenter = ori - center; // e-c
    const double b = 2 * dot(origintocenter, dir); 
    const double c = dot(origintocenter, origintocenter) - radius*radius;
    const double a = dot(dir, dir);
    double delta = b*b - 4 * a * c;
    if (delta < 0) return false;
    delta = sqrt(delta);
    const double t0 = (-b - delta)/(2*a);
    const double t1 = (-b + delta)/(2*a);
    t = (t0 < t1) ? t0 : t1;
    return true;
  }
};

void range255(Vec& col) {
  col.x = (col.x > 255) ? 255 : (col.x < 0) ? 0 : col.x;
  col.y = (col.y > 255) ? 255 : (col.y < 0) ? 0 : col.y;
  col.z = (col.z > 255) ? 255 : (col.z < 0) ? 0 : col.z;
}

int main(){
    //image size
    const int width = 1000;
    const int height = 1000;

    //colors
    const Vec white(255, 255, 255);
    const Vec black(0, 0, 0);
    const Vec red(255, 0, 0);
    const Vec green(0,255,0);
    const Vec blue(0,0,255);

    const Sphere sphere(Vec(width*0.8, height*0.2, 30), 50);
    const Sphere sphere1(Vec(width*0.5, height*0.5, 30), 50);
    const Sphere sphere2(Vec(width*0.8, height*0.8, 30), 50);
    const Sphere light(Vec(0, 0, 0), 1);

    vector<Sphere> s;
    s.push_back(sphere);
    s.push_back(sphere1);
    s.push_back(sphere2);
    ofstream out("out.ppm");
    out << "P3\n" << width << ' ' << height << ' ' << "255\n";

    Vec pixelColor(black);

    double t;

    for(int y=0; y<height; ++y){
        for(int x=0; x<width; ++x){
            pixelColor = black;
            const Ray ray(Vec(x,y,0), Vec(0,0,1)); // z'den xy düzlemine gönderiyor
            for(int a=0; a<s.size(); ++a){
                if (s[a].intersect(ray, t)) {

                    const Vec p = ray.origin + ray.direction*t;
                    const Vec n = s[a].getNormal(p); //normal
                    const Vec l = light.center - p; // light condition
                    const double dt = dot(l.normalize(), n.normalize());

                    pixelColor = (red + white*dt) * 0.5;
                    range255(pixelColor);

            }

            out << (int)pixelColor.x << ' ' << (int)pixelColor.y << ' ' << (int)pixelColor.z << '\n';

            }
        } 
    }

}

enter image description here

1 Ответ

0 голосов
/ 13 марта 2020

Я не могу найти в вашем коде ни одной проверки, какая сфера ближе. Если ваш луч пересекает несколько сфер, он должен вернуть сферу и соответствующее значение t для ближайшей.

Кроме того, ваш код неисправен, если t0 или t1 или оба отрицательны, то есть сфера находится позади зрителя.

Если бы я был вами, я бы просто возвратил std::optional<double> из Sphere::intersect(const Ray&) и сравнил бы результат с t, полученным из предыдущих сфер, которые я пытался пересечь. Только в самом конце, когда станет известна ближайшая сфера, я начну затенять (т.е. вычислять освещение и цвет).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...