所以我试图用C#重写我的光线跟踪器,我一直在收到这些奇怪的文物。 起初我可能认为它们是由于没有将Epsilon添加到阴影射线as described here而导致的黑点伪影。
但是我添加了一个epsilon并且斑点不是黑色(但我添加了环境)。 这是一个示例图片(我将背景设为黄色,因此它突出了一点)
这是我的照明代码:
private Vector4 CalculateBlinnPhongLight(Ray ray, Intersection its)
{
Vector4 blinnPhongColor = Color.Blue.ToVector4();
//Step 1: Calculate intersection point. Since our direction was never normalized we need to do it here.
Microsoft.Xna.Framework.Vector3 itsPoint = ray.Origin + ray.Direction*its.TimeInterval.StartTime;
//Step 2: Calculate half vector h - bisector of angle of v (from intersection to eye) and l (intersection to light)
Microsoft.Xna.Framework.Vector3 v = -1 * ray.Direction; v.Normalize();
//Step 3: For ecah light in the scene grab it's contribution
foreach (Light light in Lights)
{
//Step 4: Setup unit vectors for Blinn Phong Lighting model: pg.84
Microsoft.Xna.Framework.Vector3 l = light.Position - itsPoint; l.Normalize();
Microsoft.Xna.Framework.Vector3 h = v + l; h.Normalize();
Microsoft.Xna.Framework.Vector3 n = its.Normal;
//Step 5: Shadow-Check - send shadow ray and see if it intersects with anything
if (IsInShadow(l, itsPoint) )
{
continue;
//TO DO: Check if the material is dielectric (see through)
}
//Step 6: Calculate light attenuation
//TODO:
//Step 7: Perform Blinn Phong calculation
//color = color + diffuse * I * max(0, n.l)
//color = color + specular * I * max(0, n.h)^phong
blinnPhongColor += its.ClosestNode.Material.DiffuseColor.ToVector4() * light.Color.ToVector4() * Math.Max(0, Microsoft.Xna.Framework.Vector3.Dot(n, l));
blinnPhongColor += its.ClosestNode.Material.SpecularColor.ToVector4() * light.Color.ToVector4() * (float)Math.Pow(Math.Max(0, Vector3.Dot(n, h)), its.ClosestNode.Material.PhongExponent);
}
//Step 8: Add ambient Color
blinnPhongColor += its.ClosestNode.Material.AmbientColor.ToVector4() * AmbientColor.ToVector4();
return blinnPhongColor;
}
private bool IsInShadow(Microsoft.Xna.Framework.Vector3 dirToLight, Microsoft.Xna.Framework.Vector3 itsPoint)
{
//Step 1: Need to add epsilon go itsPoint otherwise we might intersect ourselves
Microsoft.Xna.Framework.Vector3 epsItsPoint = itsPoint + 0.000001f*dirToLight;
Ray shadowRay = new Ray(epsItsPoint, dirToLight);
return ! this.Root.IntersectRay(shadowRay).Hit;
}
或许值得注意的是,我的光线方向不是单位矢量。我根据我正在阅读的书中的说明有目的地完成了这一点,这样当我可以通过变换矩阵变换光线时,我会给每个原语提供简单的实例化。
答案 0 :(得分:4)
由于这些神器正在获得环境光的贡献,但既没有接收镜面也没有接收漫反射,几乎可以肯定是IsInShadow
计算。根据您定义球体的方式,您应该遇到各种精度误差。
要验证它是您的阴影计算,请使用单个常量贡献替换漫反射和镜面反射贡献。如果文物消失了,那就是你的问题。如果它们没有消失,那么两个光贡献都会出错(不太可能),您可以通过重新定位场景中的灯来验证这一点。
此外,您实际上不需要对阴影线进行标准化处理,并且不这样做会使您无法进行除法计算,通常会发生这种精度错误。