光线跟踪器灯光反射错误
Raytracer light reflection bug
我正试图将99行C++中的smallpt:Global Illumination移植到C#,当光线从漫反射表面反射时,我遇到了这个奇怪的错误。有人知道问题可能来自哪里吗?
这就是我用40个样本得到的
这就是的样子
这是我的漫射表面代码:
if(sphere.Reflection == Sphere.ReflectionType.DIFFUSE)
{
double angleRand = random.NextDouble(seed) *2f*Math.PI;
double distanceRand = random.NextDouble(seed);
double distanceRandSqtr = Math.Sqrt(distanceRand);
Vector3 w = surfaceNormal;
Vector3 u = Vector3.Normalize(Vector3.Cross(Math.Abs(w.X) > .1 ? new Vector3(0f, 1f, 0f) : new Vector3(1f, 0f, 0f), w));
Vector3 v = Vector3.Cross(w, u);
Vector3 ref1 = Vector3.Multiply(u, (float)Math.Cos(angleRand));
ref1 = Vector3.Multiply(ref1, (float)distanceRandSqtr);
Vector3 ref2 = Vector3.Multiply(v, (float)Math.Sin(angleRand));
ref2 = Vector3.Multiply(ref2, (float)distanceRandSqtr);
Vector3 ref3 = Vector3.Multiply(w, (float)Math.Sqrt(1 - distanceRand));
Vector3 ref4 = Vector3.Add(ref1, ref2);
ref4 = Vector3.Add(ref4, ref3);
Vector3 reflectionRayRand = Vector3.Normalize(ref4);
Vector3 nextRadiance = ComputeRadiance(new Ray(intersectionPoint, reflectionRayRand), depth, seed);
Vector3 result = Vector3.Multiply(color, nextRadiance);
result = Vector3.Add(sphere.Emission, result);
if (float.IsNaN(result.X) || float.IsNaN(result.Y) || float.IsNaN(result.Z))
{
throw new Exception();
}
return result;
}
这是原件:
if (obj.refl == DIFF){ // Ideal DIFFUSE reflection
double r1=2*M_PI*erand48(Xi), r2=erand48(Xi), r2s=sqrt(r2);
Vec w=nl, u=((fabs(w.x)>.1?Vec(0,1):Vec(1))%w).norm(), v=w%u;
Vec d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1-r2)).norm();
return obj.e + f.mult(radiance(Ray(x,d),depth,Xi));}
我放弃了Vector3,使用了一个自定义类,该类可以使用doubles而不是float。这就解决了问题。感谢@AmberElferink的帮助!
class Vec
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public Vec(double x=0, double y=0, double z=0)
{
X = x;
Y = y;
Z = z;
}
public static Vec Normalize(Vec vec) { return vec.GetNormal(); }
public static Vec Cross(Vec right, Vec left) { return right.CrossWith(left); }
public static double Dot(Vec right, Vec left) { return right.DotWith(left); }
public static Vec Multiply(Vec right, Vec left) { return right * left; }
public static Vec Multiply(Vec right, double left) { return right * left; }
public static Vec Add(Vec right, Vec left) { return right + left; }
public static Vec Subtract(Vec right, Vec left) { return right - left; }
public static Vec operator+(Vec right, Vec left) { return new Vec(right.X + left.X, right.Y + left.Y, right.Z + left.Z); }
public static Vec operator-(Vec right, Vec left) { return new Vec(right.X - left.X, right.Y - left.Y, right.Z - left.Z); }
public static Vec operator *(Vec right, Vec left) { return new Vec(right.X * left.X, right.Y * left.Y, right.Z * left.Z); }
public static Vec operator *(Vec right, double left) { return new Vec(right.X * left, right.Y * left, right.Z * left); }
public Vec GetNormal() { return this * (1 / Math.Sqrt(X * X + Y * Y + Z * Z)); }
public double DotWith(Vec b) { return X * b.X + Y * b.Y + Z * b.Z; }
public Vec CrossWith(Vec b) { return new Vec(Y * b.Z - Z * b.Y, Z * b.X - X * b.Z, X * b.Y - Y * b.X); }
}
你的效果让我想起了一点阴影粉刺。通常这是一个更圆形的图案,这就是为什么我不确定。阴影粉刺的发生是由于浮动不准确。散射或反射时,会在某个方向上从曲面上的某个原点生成新光线。原点有时会在曲面下方/上方移动,具体取决于浮动的不准确性。这就是为什么您经常在法线方向上偏移带有少量EPSILON的光线。因此,您的新原点变为:交叉点+交叉点。法线*EPSILON。你应该测试不同的ε值,但通常在0.01到0.02左右。在您的代码中,您仍然使用交叉点,我认为它没有偏移量。我不确定这是否有效,因为你的结果看起来与我习惯的阴影痤疮有点不同,但值得一试,对吧?
相关文章:
- 警告处理为错误这里有什么问题
- "error: no matching function for call to"构造函数错误
- boost::进程间消息队列引发错误
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- QT在错误的班级中寻找空位
- vector.resize()中的分配错误
- 代码在main()中运行,但在函数中出现错误
- 释放错误后堆使用
- (C++)分析树以计算返回错误值的简单算术表达式
- Project Euler问题4的错误解决方案
- 我的字符计数代码计算错误.为什么
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 尝试导入pybind-opencv模块时出现libgtk错误
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- 在某些循环内使用vector.push_back时出现分段错误
- MSVC多行宏编译器错误
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 光线跟踪器灯光反射错误