You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

《Ray Tracing in One Weekend》全内反射光线追踪问题求助

《Ray Tracing in One Weekend》11.3节全内反射实现问题

我正在跟随《Ray Tracing in One Weekend》一书学习,在11.3节全内反射(Total internal reflection)部分遇到问题。生成的图像如下:

左侧带折射效果的球体

以下是球体相交检测代码,返回std::optional<Intersection>实例或std::nullopt:

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);
};

预期得到的图像如下:

《Ray Tracing in One Weekend》11.3节预期图像

如需更多信息请告知,感谢帮助 :)

内容的提问来源于stack exchange,提问作者Lautaro10263

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:54:51