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

如何在光线追踪系统中正确添加点光源与反射值?

如何在光线追踪系统中正确添加点光源与反射值?

嘿,我来帮你搞定光线追踪里点光源和反射值的事儿~看你已经写了ray_color函数的开头,那咱们一步步来完善它。

首先明确核心思路:点光源要处理漫反射、高光、阴影这三个关键部分,反射值则要靠递归调用ray_color并控制衰减和递归深度来实现。

先结合你现有的代码框架,补全并解释逻辑:

t_color ray_color(t_rt *rt, t_ray ray, int depth) {
    t_color color;
    t_color attenuation;
    t_hit_record rec; // 假设你已定义存储交点信息的结构体,包含法线、材质、交点坐标等

    // 先检测光线是否击中场景中的物体
    if (world_hit(rt->world, ray, &rec)) {
        t_ray scattered;
        t_color light_contribution = color_black(); // 初始化光源贡献色为黑色

        // 遍历场景中所有点光源
        for (int i = 0; i < rt->light_count; i++) {
            t_point_light light = rt->lights[i];
            // 计算交点到光源的方向向量并归一化
            t_vec3 light_dir = vec3_normalize(vec3_sub(light.position, rec.p));
            float light_distance = vec3_length(vec3_sub(light.position, rec.p));

            // 阴影检测:发射一条从交点到光源的光线,检查是否有物体遮挡
            t_ray shadow_ray = ray_create(vec3_add(rec.p, vec3_multiply(rec.normal, 0.001)), light_dir); // 加小偏移避免自遮挡
            t_hit_record shadow_rec;
            if (!world_hit(rt->world, shadow_ray, &shadow_rec) || vec3_length(vec3_sub(shadow_rec.p, rec.p)) >= light_distance) {
                // 计算漫反射分量
                float diff_factor = fmax(vec3_dot(rec.normal, light_dir), 0.0); // 取正,避免负漫反射
                t_color diffuse = color_multiply_scalar(color_multiply(rec.diffuse_color, light.color), diff_factor * light.intensity);

                // 计算高光分量
                t_vec3 view_dir = vec3_normalize(vec3_sub(ray.origin, rec.p)); // 视线方向(从交点看向相机)
                t_vec3 reflect_dir = vec3_reflect(vec3_negate(light_dir), rec.normal); // 光源方向的反射向量
                float spec_factor = pow(fmax(vec3_dot(view_dir, reflect_dir), 0.0), rec.specular_exponent); // 高光指数控制高光大小
                t_color specular = color_multiply_scalar(color_multiply(rec.specular_color, light.color), spec_factor * light.intensity);

                // 叠加漫反射和高光到光源贡献
                light_contribution = color_add(light_contribution, color_add(diffuse, specular));
            }
        }

        // 处理反射效果
        if (depth > 0 && rec.mat.has_reflection) { // 假设材质有是否反射的属性
            attenuation = rec.mat.reflect_color; // 反射衰减,比如金属的衰减接近白色,塑料则偏暗
            // 计算反射光线:同样加小偏移避免自相交
            t_vec3 reflect_dir = vec3_reflect(ray.direction, rec.normal);
            t_ray reflect_ray = ray_create(vec3_add(rec.p, vec3_multiply(rec.normal, 0.001)), reflect_dir);
            // 递归调用ray_color,深度减1
            t_color reflect_color = ray_color(rt, reflect_ray, depth - 1);
            // 最终颜色 = 光源贡献 + 反射颜色 * 衰减系数
            return color_add(light_contribution, color_multiply(attenuation, reflect_color));
        } else {
            // 没有反射或者递归深度耗尽,返回光源贡献 + 环境光
            return color_add(light_contribution, color_multiply(rec.diffuse_color, rt->ambient_color));
        }
    }

    // 没击中任何物体,返回背景色
    return rt->background_color;
}

给你划几个必注意的重点:

  • 阴影检测的小偏移:一定要给阴影光线的起点加个很小的偏移(比如0.001倍的法线),不然光线会和当前交点的物体再次相交,导致阴影出现错误的黑块。
  • 漫反射的取值范围:用fmax把点积结果限制在0以上,不然会出现负的颜色,也就是物体背面反而发光的奇怪效果。
  • 反射深度控制:depth参数一定要设上限(比如5-10),不然会无限递归导致程序崩溃,同时也能平衡渲染质量和性能。
  • 衰减系数:attenuation其实就是物体的反射颜色/强度,比如纯金属的反射衰减是白色(完全反射),而木头的反射衰减就很暗(几乎不反射)。

另外,你需要提前定义好点光源的结构体,比如:

typedef struct s_point_light {
    t_vec3 position;
    t_color color;
    float intensity;
} t_point_light;

还有交点记录结构体t_hit_record里要包含法线、漫反射颜色、高光颜色、高光指数、材质反射属性这些必要信息哦。

备注:内容来源于stack exchange,提问作者delmath

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 16:19:38