路径跟踪代码不起作用,尽管我认为我做对了
本文关键字:管我 代码 跟踪 不起作用 路径 | 更新日期: 2023-09-27 18:33:59
所以我想写一个小的路径追踪器来熟悉所有的向量数学和交集计算。因此,我用 C# 创建了一个 Windows 窗体应用程序,并使用 PictureBox 来显示位图。
这是我的类"渲染场景"。它创建位图,遍历每个像素,计算与像素相关的光线。创建光线后,我递归地跟踪它在整个世界中,最后返回像素的颜色。
public void renderScene()
{
Bitmap drawArea = new Bitmap(pB_Result.Size.Width, pB_Result.Size.Height);
pB_Result.Image = drawArea;
int height = pB_Result.Size.Height;
int width = pB_Result.Size.Width;
float fov = 160 * (float)Math.PI / 180;
float zdir = 1.0f / (float)Math.Tan(fov);
float aspect = (float)height / (float)width;
//BWorker.RunWorkerAsync(new Tuple<int, int, Bitmap, float, float, float>(height, width, drawArea, fov, zdir, aspect));
for (int y = 0; y < pB_Result.Height; y++)
{
for (int x = 0; x < pB_Result.Width; x++)
{
float xdir = (x / (float)width) * 2.0f - 1.0f;
float ydir = ((y / (float)height) * 2.0f - 1.0f) * aspect;
Ray ray = new Ray(Camera, new Vector3D(xdir, ydir, zdir).normalize());
float r = 0, g = 0, b = 0;
System.Threading.Tasks.Parallel.For(0, RAYS_PER_PIXEL, i =>
{
Color c = Trace(ray, 0);
r += c.R;
g += c.G;
b += c.B;
});
//for (int i = 0; i < RAYS_PER_PIXEL; i++)
//{
// Color c = Trace(ray, 0);
// r += c.R;
// g += c.G;
// b += c.B;
//}
drawArea.SetPixel(x, y, Color.FromArgb(255, (int)r / RAYS_PER_PIXEL, (int)g / RAYS_PER_PIXEL, (int)b / RAYS_PER_PIXEL));
}
}
pB_Result.Image = drawArea;
}
这是我的跟踪函数,它递归地将光线与场景相交:
public Color Trace(Ray ray, int depth, BaseObject missObject = null)
{
float distance = 5000.0f;
BaseObject lastHitObject = null;
Vector3D HitPoint = null;
foreach (BaseObject obj in this.scene.Objects)
{
if (obj == missObject)
continue;
float currentDistance = obj.Intersect(ray);
if (currentDistance < distance && currentDistance > 0)
{
distance = currentDistance;
lastHitObject = obj;
}
}
if (distance == 5000.0f) //Kein Objekt wurde getroffen
return Color.Black;
if (lastHitObject.isEmitter) //Eine Lichtquelle wurde getroffen
return lastHitObject.surfaceColor;
if (depth == MAX_DEPTH)
return Color.Black;
HitPoint = ray.origin.add(ray.direction.multiply(distance));
Vector3D normal = lastHitObject.Normal(HitPoint);
Ray reflectionRay = null;
if (lastHitObject.mat == Material.Diffuse)
{
Vector3D randomVector = Vector3D.getRandomVectorInHemisphere();
if (randomVector.Dotproduct(normal) < 0.0)
randomVector = randomVector.negate();
reflectionRay = new Ray(HitPoint, randomVector.normalize());
}
Color returnColor = Trace(reflectionRay, depth + 1, lastHitObject);
float r = lastHitObject.surfaceColor.R * returnColor.R;
float g = lastHitObject.surfaceColor.G * returnColor.G;
float b = lastHitObject.surfaceColor.B * returnColor.B;
r /= 255.0f;
g /= 255.0f;
b /= 255.0f;
return Color.FromArgb(255, (int)r, (int)g, (int)b);
}
我使用"missObject"参数来避免一些浮点数学不准确,所以我不会再次检查最后一个命中对象。
这是我的Vector3D类,它表示3D空间中的一个点。我还实现了一些操作向量的函数:
public class Vector3D
{
public float x { get; set; }
public float y { get; set; }
public float z { get; set; }
public Vector3D()
{
}
public Vector3D(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public float Dotproduct(Vector3D Dotvector)
{
return (Dotvector.x * this.x + Dotvector.y * this.y + Dotvector.z * this.z);
}
public float Length()
{
return (float)Math.Sqrt(x*x + y*y + z*z);
}
public Vector3D subtract(Vector3D subVec)
{
return new Vector3D(this.x - subVec.x, this.y - subVec.y, this.z - subVec.z);
}
public Vector3D add(Vector3D addVec)
{
return new Vector3D(this.x + addVec.x, this.y + addVec.y, this.z + addVec.z);
}
public Vector3D add(float value)
{
return add(new Vector3D(value, value, value));
}
public Vector3D multiply(Vector3D multVec)
{
return new Vector3D(this.x * multVec.x, this.y * multVec.y, this.z * multVec.z);
}
public Vector3D multiply(float value)
{
return multiply(new Vector3D(value, value, value));
}
public Vector3D divide(Vector3D divVec)
{
return new Vector3D(this.x / divVec.x, this.y / divVec.y, this.z / divVec.z);
}
public Vector3D divide(float value)
{
return divide(new Vector3D(value, value, value));
}
public Vector3D CrossProduct(Vector3D crossVec)
{
return new Vector3D
{
x = this.y * crossVec.z - this.z * crossVec.y,
y = this.z * crossVec.x - this.x * crossVec.z,
z = this.x * crossVec.y - this.y * crossVec.x
};
}
public Vector3D negate()
{
return new Vector3D
{
x = -x,
y = -y,
z = -z
};
}
public Vector3D normalize()
{
float f = (float)(1.0f / Math.Sqrt(this.Dotproduct(this)));
x *= f;
y *= f;
z *= f;
return new Vector3D(x, y, z);
}
public static Vector3D getRandomVectorInHemisphere()
{
Random rnd = new Random(DateTime.Now.Millisecond);
Vector3D v = new Vector3D
{
x = (float)rnd.NextDouble() * 2.0f - 1.0f,
y = (float)rnd.NextDouble() * 2.0f - 1.0f,
z = (float)rnd.NextDouble() * 2.0f - 1.0f
};
v = v.normalize();
return v;
}
}
问题似乎是System.Threading.Tasks.Parallel.For,如果我将其更改为正常的for循环,我会得到一个非常好的结果:
http://img5.fotos-hochladen.net/uploads/pathtracerv4i84onm23aiz.png