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

光线追踪漫反射光照为何出现生硬截断?

光线追踪漫反射效果异常问题求助

我用JavaScript跟随《Ray Tracing In One Weekend》教程实现光线追踪,完成漫反射光照模块后,输出结果与预期不符:

  • 预期效果:球体呈现柔和的漫反射光影过渡,色彩自然渐变
  • 实际效果:球体表面出现生硬截断线条,效果近似镜面反射

我怀疑问题出在新射线的计算逻辑上,以下是核心代码片段,恳请帮忙排查:

射线颜色递归计算函数

function rayColour(r, world, depth) {
  if (depth <= 0) {
    return new Colour(0, 0, 0);
  }

  var rec = world.hit(r, 0, infinity, rec);
  if (rec[0]) {
    var target = rec[1].p.add(rec[1].normal).add(randomInUnitSphere());
    return rayColour(new Ray(rec[1].p, target.subtract(rec[1].p)), world, depth-1).multiply(0.5);
  }
  var unitDirection = normalize(r.dir);
  var t = 0.5 * (unitDirection.y + 1);
  return new Colour(1, 1, 1).multiply(1-t).add(new Colour(0.5, 0.7, 1).multiply(t));
}

像素主渲染函数

for(var p = 0; p < ppt; p++) {
    var i = curPixel % WIDTH;
    var j = HEIGHT-1 - Math.floor(curPixel / WIDTH);

    var pixelColour = new Colour(0, 0, 0);

    for (var s = 0; s < samplesPerPixel; ++s) {
      var u = (i + Math.random()) / (WIDTH-1);
      var v = (j + Math.random()) / (HEIGHT-1);
      var r = cam.getRay(u, v);
      pixelColour = pixelColour.add(rayColour(r, world, maxDepth));
    }

    putPixel(i, HEIGHT-1-j, pixelColour, samplesPerPixel);
    curPixel++;
  }

球体射线碰撞检测

hit(r, tMin, tMax, rec) {
    var oc = r.origin().subtract(this.center);
    var a = r.dir.lengthSquared();
    var halfb = dot(oc, r.dir);
    var c = oc.lengthSquared() - this.radius*this.radius;
    
    var discriminant = halfb*halfb - a*c;
    if (discriminant < 0) return [false, rec];
    var sqrtd = Math.sqrt(discriminant);

    // 寻找最近碰撞点
    var root = (-halfb - sqrtd) / a;
    if (root < tMin || tMax < root) {
      root = (-halfb + sqrtd) / a;
      if (root < tMin || tMax < root) return [false, rec];
    }

    rec.t = root;
    rec.p = r.at(rec.t);
    var outwardNormal = (rec.p.subtract(this.center)).divide(this.radius);
    rec.setFaceNormal(r, outwardNormal);

    return [true, rec];
  }

物体列表碰撞检测

hit(r, tMin, tMax, rec) {
    var tempRec = new hitRecord();
    var hitAnything = false;
    var closestSoFar = tMax;

    for (var i in this.list) {
      var tempRec = this.list[i].hit(r, tMin, closestSoFar, tempRec)
      if (tempRec[0]) {
        hitAnything = true;
        closestSoFar = tempRec[1].t;
        rec = tempRec[1];
      }
      tempRec = new hitRecord();
    }

    return [hitAnything, rec];
  }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 02:25:27