光线追踪中全内反射的问题(周末光线追踪)

问题描述 投票:0回答:1

我正在按照《周末光线追踪》一书中的步骤进行操作,但在第 11.3 节“全内反射”中遇到了一些问题。当我尝试创建图像时,我得到这个结果:

Left sphere with refraction

这是与球体相交的代码,它返回与球体的交集或 null:

std::optional<Intersection> Sphere::intersect(const Ray& r, double tMin, double tMax) const {
    vec o_c = this->center- r.origin();

    auto a = r.direction().length_squared() () 
    auto b = dot(r.direction(), o_c);
    auto c = o_c.length_squared() - radius * radius;
    
    auto d = b * b - a * c;

    // at^2 + tb + c = 0 not real solution

    if (d < 0) {
        return std::nullopt;
    }

    // Verify root in [tMin, tMax]

   double dSqrt = std::sqrt(d);
    double root = (b - dSqrt) / a;
    if (root < tMin || root > tMax) {
        root = (b + dSqrt) / a;
        if (root < tMin || root > tMax) return std::nullopt;
    }

    Intersection i;
    i.t = root;
    i.point = r(i.t);
    i.normal = unit_vector(i.point - center);
        i.material = material;

    return i;
 };

这是折射代码:

inline vec refraction(const vec& v, const vec& normal, double refraction_index) {
    vec rparal{ .0, .0, .0 };
    vec rperp{ .0, .0, .0 };

    bool front_face = (dot(v, normal) < 0);
    double ri = front_face ? 1.0 / refraction_index : refraction_index;

    vec outward_normal = front_face ? normal : -normal;
    
    double cos_tita = fmin(dot(-v, outward_normal ), 1.0);
    double sen_tita = sqrt(1 - cos_tita * cos_tita);

    
    if (ri * sen_tita > 1) {
        return reflect(v, outward_normal);
    }
    
    rperp = ri * (v + (dot(-v, outward_normal) * outward_normal)); 
    rparal = (-sqrt(abs(1 - rperp.length_squared()))) * outward_normal;

    return rparal + rperp;
};

这是 color_ray 的代码:

color color_ray(const Ray& r, int deep, const Geometry& g) {

    if (deep <= 0)
        return color(0, 0, 0);

    auto i = g.intersect(r, 0.001, infinity);

    if (i) {
        color intensity;

         // Check if the material is reflective
        if (i->material->reflective) {

            vec reflectedVector = reflect(unit_vector(r.direction()), i->normal) + 
            (i->material->coef_Reflective * vec::random_Unit_vector());

            Ray reflected_Ray = Ray(i->point, reflectedVector);
            intensity = i->material->DifuseColor * color_ray(reflected_Ray, deep - 1, g);

         // Check if the material is refractive
        } else if (i->material->refractive) {

           vec refractedVector = refraction(unit_vector(r.direction()), i->normal, 
                                 i->material>refraction_index);

       Ray refracted_Ray = Ray(i->point, refractedVector);
           intensity = color_ray(refracted_Ray , deep - 1, g);

        } else {

            intensity = i->material->DifuseColor * color_ray(Ray(i->point, i->normal +                    vec::randomUnitVector()), deep - 1, g);

        }

        return intensity;
    }
    
    vec unit_direction = unit_vector(r.direction());
    auto a = 0.5 * (unit_direction .y() + 1);
    return (1.0 - a) * color(1.0, 1.0, 1.0) + a * color(0.5, 0.7, 1.0);
};

我应该得到以下图像:

Image from Ray Tracing in a weekend section 11.3

如果您需要更多信息,请告诉我,我们将不胜感激:)

c++ graphics raytracing
1个回答
0
投票

嗯,我找到了解决方案,问题就在

rparal = (-sqrt(abs(1 - rperp.length_squared()))) * outward_normal;

我删除了括号,并将“abs”更改为“fabs”,这解决了问题。

rparal = -sqrt(fabs(1 - rperp.length_squared())) * outward_normal;

这是生成的新图像:没有问题的新图像

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.