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

JavaScript光线追踪器折射功能异常:透明球体显示黑色求助

光线追踪器透明球体显示黑色的问题排查与修复

问题描述

参照教材为JavaScript光线追踪器添加折射功能后,本该透明的球体显示为黑色,多次尝试修复无效。效果如下:
球体效果截图

相关代码片段

球体类定义

// 球体类
var Sphere = function(center, radius, color, specular, reflective, refractive, refractive_index) {
  this.center = center;
  this.radius = radius;
  this.color = color;
  this.specular = specular;
  this.reflective = reflective;
  this.refractive = refractive;
  this.refractive_index = refractive_index;  // 新增属性
}

场景球体配置

// 场景中的球体
var spheres = [
  new Sphere([0, -1, 3], 1, [255, 0, 0], 500, 0.2, false, 1.0),  // 最后两个参数为折射开关和折射率
  new Sphere([2, 0, 4], 1, [0, 0, 255], 500, 0.3, false, 1.0),
  new Sphere([-2, 0, 4], 1, [0, 255, 0], 10, 0.4, true, 1.5),  // 设置为透明球体,折射率1.5
  new Sphere([0, -5001, 0], 5000, [255, 255, 0], 1000, 0.5, false, 1.0)
];

光线追踪核心函数

// 光线追踪函数
var TraceRay = function(origin, direction, min_t, max_t, depth) {
  var intersection = ClosestIntersection(origin, direction, min_t, max_t);
  if (!intersection) {
    return background_color;
  }

  var closest_sphere = intersection[0];
  var closest_t = intersection[1];

  var point = Add(origin, MultiplySV(closest_t, direction));
  var normal = Subtract(point, closest_sphere.center);
  normal = MultiplySV(1.0 / Length(normal), normal);

  var view = MultiplySV(-1, direction);
  var lighting = ComputeLighting(point, normal, view, closest_sphere.specular);
  var local_color = MultiplySV(lighting, closest_sphere.color);

  if (depth <= 0) {
    return local_color;
  }

  var reflected_color = [0, 0, 0];
  if (closest_sphere.reflective > 0) {
    var reflected_ray = ReflectRay(view, normal);
    reflected_color = TraceRay(point, reflected_ray, EPSILON, Infinity, depth - 1);
  }

  var refracted_color = [0, 0, 0];
  if (closest_sphere.refractive) {
    var refracted_ray = RefractRay(view, normal, closest_sphere.refractive_index);  // 需要实现该函数
    refracted_color = TraceRay(point, refracted_ray, EPSILON, Infinity, depth - 1);
  }

  return Add(MultiplySV(1 - closest_sphere.reflective - closest_sphere.refractive, local_color),
             Add(MultiplySV(closest_sphere.reflective, reflected_color),
                 MultiplySV(closest_sphere.refractive, refracted_color)));
}

问题排查方向

  1. 折射函数未实现:代码中标注RefractRay函数需要实现,若未正确返回折射光线方向,会导致后续追踪无有效交点,返回黑色背景。
  2. 介质折射率切换错误:光线进入/离开球体时,未在空气(折射率≈1.0)和球体介质(1.5)间切换折射率,导致折射方向计算错误。
  3. 全反射处理缺失:光线从光密介质射向光疏介质时,可能触发全反射,此时无折射光线,若未 fallback 到反射光线计算,会返回黑色。
  4. 颜色混合参数溢出:当前透明球体的reflective(0.4)+refractive(1.0)>1,导致1 - reflective - refractive为负数,local_color被负系数修正后出现异常。
  5. 内部光线相交误判:折射光线在球体内部时,未排除自身球体的相交检测,可能误判为无有效交点。

修复建议

1. 实现正确的RefractRay函数

function RefractRay(view, normal, refractive_index) {
  var eta = 1.0 / refractive_index;
  var cosi = Dot(view, normal);
  
  // 判断光线是进入还是离开介质,切换折射率与法线方向
  if (cosi < 0) {
    cosi = -cosi;
  } else {
    eta = 1.0 / eta;
    normal = MultiplySV(-1, normal);
  }

  var k = 1 - eta * eta * (1 - cosi * cosi);
  if (k < 0) {
    // 触发全反射,返回反射光线
    return ReflectRay(view, normal);
  }
  
  // 计算并返回折射光线方向
  return Add(MultiplySV(eta, view), MultiplySV(eta * cosi - Math.sqrt(k), normal));
}

2. 调整颜色混合参数

确保reflective与refractive的和不超过1,修改透明球体的配置:

new Sphere([-2, 0, 4], 1, [0, 255, 0], 10, 0.1, 0.8, 1.5)

保留少量漫反射分量,同时让折射、反射效果正常叠加。

3. 修正内部光线相交检测

在追踪折射光线时,修改ClosestIntersection函数,排除当前球体的检测;或调整TraceRay的min_t/max_t范围,避免误判自身相交。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:38:15