微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用简单漫反射计算时的透明/嘈杂球体

如何解决使用简单漫反射计算时的透明/嘈杂球体

我一直在尝试编写光线跟踪器,但在尝试实现简单的漫反射计算时遇到了一个问题(尝试复制 一个周末的光线跟踪中的第一个计算,但没有指南)

相关代码如下:

交点/漫反射计算:

#pragma once

#include "Camera.h"
#include <cmath>
#include "Defs.h"

template<typename O>
class Sphere{
  O Radius;
  Point3<O> Center;
  Color<O> Col;

public:
  Sphere(O radius,Point3<O> center,Color<O> color);

    O quadratic(Ray<O> ray_in,O &disc,O t_Min,O t_Max);
    bool intersect(Ray<O> ray_in,rayInfo<O> &info,O t_Max);
};

template<typename O>
Sphere<O>::Sphere(O radius,Color<O> color) : Radius(radius),Center(center),Col(color) {}

template<typename O>
O Sphere<O>::quadratic(Ray<O> ray_in,O t_Max){
  Point3<O> origin = ray_in.Origin;
  Vec3<O> direction = ray_in.Direction;

  Vec3<O> o = origin-Center;
  O a = direction.dot(direction);
  O b = 2 * direction.dot(o);
  O c = o.dot(o) - (Radius * Radius);
  O discriminant = b * b - 4 * (a * c);

  if (discriminant < 0){
      return false;
  }

  disc = ((-b - sqrt(discriminant)) / (2 * a));

  if (disc > t_Max || t_Min > disc){
      disc = ((-b + sqrt(discriminant)) / (2 * a));
      if (disc > t_Max || t_Min > disc){
          return false;
      }
  }

  return true;
}

template<typename O>
bool Sphere<O>::intersect(Ray<O> ray_in,O t_Max){

    O disc;

    if (quadratic(ray_in,disc,info.Min,t_Max)){

        Point3<O> p = ray_in.at(disc);
        Vec3<O> normal = (p - Center) / Radius;

        info.Point = p;
        info.normal = normal;
        info.front_face();
        info.Min = disc;

        return true;
    }
    else{
        return false;
    }
}

示踪类:

#pragma once

#include <iostream>
#include "Shapes.h"
#include "Defs.h"
#include "Image.h"

template<typename O>
class Tracer{
  std::vector<Sphere<O>> Shapes;

public:
  Tracer(std::vector<Sphere<O>> shapes);
  void iterator(Ray<O> &ray,O &depth,O t_Max,O t_Min);

};

template<typename O>
Tracer<O>::Tracer(std::vector<Sphere<O>> shapes) : Shapes(shapes) {}

template<typename O>
void Tracer<O>::iterator(Ray<O> &ray,O t_Min){

  O conc = 1;
  Color<O> col(0.4f,0.8f,0.9f);
  bool hit = false;

  rayInfo<O> info;
  info.Min = t_Min;

  if (depth <= 0)
      conc = 0;

  while (depth > 0){

    for (auto i = Shapes.begin(); i != Shapes.end(); i++){

      if (i->intersect(ray,info,t_Max)){
        conc *= 0.28;
        hit = true;
      }
    }

    if (!hit){
      break;
    }

    Vec3<O> circ = Vec3<O>::random_in_unit_sphere();
    Point3<O> target = info.Point + info.normal + circ;
    ray = Ray<O>(info.Point,target - info.Point);
    info.Min = t_Min;
    hit = false;
    depth--;
  }

  col = col * conc;
  Image<O>::ColorPixel(std::cout,col);
}

主要以防万一:

#include <iostream>
#include <cmath>
#include "../Matrix.h"
#include "Camera.h"
#include <vector>
#include "Image.h"
#include "Shapes.h"
#include "Tracer.h"
#include "../Defs.h"

template<typename O>
using Point3 = Vec3<O>;

template<typename O>
using Color = Vec3<O>;

int main(){
  const int img_width = 640;
  const int img_height = 480;
  const float img_ratio = img_width/img_height;
  float t_Max = infinity; float t_Min = 0.01; float depth = 50.0f;

  float inv_width = 1 / float(img_width);
  float inv_height = 1 / float(img_height);

  std::vector<Sphere<float>> shapes;

  Camera<float> cam1(40.0f,img_ratio,Point3<float>(0.0f,0.0f,0.0f),-1.0f),Vec3<float>(0.0f,1.0f,0.0f));

  Sphere<float> cir1(0.4f,Color<float>(0.7f,0.3f,0.2f));
  Sphere<float> cir2(3.0f,-3.0f,Color<float>(0.2f,0.7f,0.8f));
  Sphere<float> cir3(0.5f,Point3<float>(1.0f,0.7f));
  shapes.push_back(cir1);
  shapes.push_back(cir2);
  shapes.push_back(cir3);

  Tracer<float> tracer(shapes);

  std::cout << "P3\n" << img_width << ' ' << img_height << "\n255" << std::endl;

  Ray<float> ray(Point3<float>(0.0f),Vec3<float>(0.0f));

  for (int j = 0; j < img_height; j++)
  {
    std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
    for (int i = 0; i < img_width; i++){
        depth = 50.0f;
        float x = i;
        float y = j;

        cam1.screenCords(x,y,img_width,img_height);

        ray = cam1.get_raydir(x,y);
        //ray = Ray<float>(Vec3<float>(x1,y1,1),0.0f));
        tracer.iterator(ray,depth,t_Max,t_Min);
    }
  }
  std::cerr << "\n done " << std::endl;
}

这是现在的样子:

enter image description here

编辑:当我在形状循环外衰减时(通过将 `conc *= 0.28 移到它的外面)我的图像最终看起来像这样:

enter image description here

我可以看到一些看起来像阴影的东西,但这显然不是预期的行为。

编辑 2:

正如 Yavok 所指出的,将 info.Min 设置为每个交叉点命中的顶点是反向逻辑。我应该减少 info.Max,这样光线就不会一直到达比当前最近的物体更远的物体。

添加了 3(三次方根)的抗锯齿和伽马校正,现在图像看起来好多了。仍然有点奇怪,但它的进步:

enter image description here

编辑 3:

终于成功了!结果我的 random_in_unit_sphere() 函数出错了。它应该看起来像这样:

static Vec3<T> random_in_unit_sphere(){
        bool flag = true;
        Vec3<T> p;
        while (flag){
            p = randomm(-1,1);
            auto l = p.length();
            if (l * l < 1) { flag = false; }
        }

        return p;

    }

感谢 Yakov 和 Spektre!非常感谢。

解决方法

噪音是存在的,因为你随机化了你的漫射光线:

Vec3<O> circ = Vec3<O>::random_in_unit_sphere();

每次您的光线击中某物时,您都会衰减颜色:

    conc *= 0.28;

显然,有些光线会比其他光线反射得更多,因此会变暗。

这种噪声是任何蒙特卡罗积分器的预期产物。要降低噪声,您需要增加每个像素的样本数并在最后应用降噪器。 >

之所以存在“透明度”,是因为您在相交循环中应用了这种衰减:

for (auto i = Shapes.begin(); i != Shapes.end(); i++){
  if (i->intersect(ray,info,t_Max)){
    conc *= 0.28; // <-- here
    hit = true;
  }
}

与多个球体相交的光线将被多次衰减,即使是应该被遮挡的球体也是如此。相反,当您发现光线反弹时,您必须在循环外进行衰减:

if (!hit){
  break;
}
conc *= 0.28; // <-- apply attenuation once per bounce
,

懒得调试您的代码,但是屏幕截图和快速查看源代码提示准确性问题。所以尝试使用 64 位 doubles 而不是 32 位 floats...

光线和椭球体/球体之间的相交在浮标上往往会产生噪声......一旦在其之上添加折射和反射,噪声就会成倍增加......

有时也有助于使用相对坐标而不是绝对坐标(即使对浮动也会产生巨大影响)。有关更多信息,请参阅:

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。