光线追踪器阴影问题

7

我正在开发一个光线追踪器,但是在阴影部分卡了好几天。我的阴影效果非常奇怪。下面是光线追踪器的一张图片:

enter image description here

Image of shadow with two spheres

黑色部分应该是阴影。
光线的起点始终为(0.f, -10.f, -500.f),因为这是透视投影,也是相机的位置。当光线与平面相交时,交点始终为光线的起点,但对于球体则不同。这是因为它基于球体的位置。由于原点差异很大,平面和球体之间永远没有交点。我还尝试在盒子上添加阴影,但这也行不通。然而,在两个球之间的阴影确实有效!
如果有人想看交点代码,请告诉我。
感谢您抽出时间来帮助我!
相机
Camera::Camera(float a_fFov, const Dimension& a_viewDimension, vec3 a_v3Eye, vec3 a_v3Center, vec3 a_v3Up) :
m_fFov(a_fFov),
m_viewDimension(a_viewDimension),
m_v3Eye(a_v3Eye),
m_v3Center(a_v3Center),
m_v3Up(a_v3Up)
{
  // Calculate the x, y and z axis
  vec3 v3ViewDirection = (m_v3Eye - m_v3Center).normalize();
  vec3 v3U = m_v3Up.cross(v3ViewDirection).normalize();
  vec3 v3V = v3ViewDirection.cross(v3U);

  // Calculate the aspect ratio of the screen
  float fAspectRatio = static_cast<float>(m_viewDimension.m_iHeight) / 
                       static_cast<float>(m_viewDimension.m_iWidth);
  float fViewPlaneHalfWidth = tanf(m_fFov / 2.f);
  float fViewPlaneHalfHeight = fAspectRatio * fViewPlaneHalfWidth;

  // The bottom left of the plane
  m_v3ViewPlaneBottomLeft = m_v3Center - v3V * fViewPlaneHalfHeight - v3U * fViewPlaneHalfWidth;

  // The amount we need to increment to get the direction. The width and height are based on the field of view.
  m_v3IncrementX = (v3U * 2.f * fViewPlaneHalfWidth);
  m_v3IncrementY = (v3V * 2.f * fViewPlaneHalfHeight);
}

Camera::~Camera()
{
}

const Ray Camera::GetCameraRay(float iPixelX, float iPixelY) const
{
  vec3 v3Target = m_v3ViewPlaneBottomLeft + m_v3IncrementX * iPixelX + m_v3IncrementY * iPixelY;
  vec3 v3Direction = (v3Target - m_v3Eye).normalize();

  return Ray(m_v3Eye, v3Direction);
}

相机设置

Scene::Scene(const Dimension& a_Dimension) :
m_Camera(1.22173f, a_Dimension, vec3(0.f, -10.f, -500.f), vec3(0.f, 0.f, 0.f), vec3(0.f, 1.f, 0.f))
{
  // Setup sky light
  Color ambientLightColor(0.2f, 0.1f, 0.1f);
  m_AmbientLight = new AmbientLight(0.1f, ambientLightColor);

  // Setup shapes
  CreateShapes();

  // Setup lights
  CreateLights();

  // Setup buas
  m_fBias = 1.f;
}

场景对象
Sphere* sphere2 = new Sphere();
sphere2->SetRadius(50.f);
sphere2->SetCenter(vec3(0.f, 0.f, 0.f));
sphere2->SetMaterial(matte3);

Plane* plane = new Plane(true);
plane->SetNormal(vec3(0.f, 1.f, 0.f));
plane->SetPoint(vec3(0.f, 0.f, 0.f));
plane->SetMaterial(matte1);

场景灯
PointLight* pointLight1 = new PointLight(1.f, Color(0.1f, 0.5f, 0.7f), vec3(0.f, -200.f, 0.f), 1.f, 0.09f, 0.032f);

阴影函数
for (const Light* light : a_Lights) {
    vec3 v3LightDirection = (light->m_v3Position - a_Contact.m_v3Hitpoint).normalized();

    light->CalcDiffuseLight(a_Contact.m_v3Point, a_Contact.m_v3Normal, m_fKd, lightColor);

    Ray lightRay(a_Contact.m_v3Point + a_Contact.m_v3Normal * a_fBias, v3LightDirection);

    bool test = a_RayTracer.ShadowTrace(lightRay, a_Shapes);

    vec3 normTest = a_Contact.m_v3Normal;
    float test2 = normTest.dot(v3LightDirection);

    // No shadow
    if (!test) {
        a_ResultColor += lightColor * !test * test2;
    }
    else {
        a_ResultColor = Color(); // Test code - change color to black.
    }
}

@geza 我添加了一张旧照片,两个球体上的阴影效果正常,但是盒子上没有。 - Sander
在那张图片上,阴影不是黑色的。但是在你的第一张图片上,你有黑色像素(我猜你没有将环境颜色改为黑色)。你是否在某个地方遇到了浮点问题?NaN、inf?如果没有完整的源代码,很难确定问题出在哪里。顺便说一句,在未来,对你的图片应用一些伽马校正,可以使其看起来更加逼真 ;) - geza
黑色只是为了清楚地表明它是否为阴影。这只是硬编码颜色为0。我没有看到任何浮点问题。有没有一个程序可以展示我的完整源代码?@geza - Sander
@geza,花了一些时间,但这是GitHub的链接:https://github.com/Sander1801/Ray-Tracer.git。引擎部分包含矩阵和向量类。我需要删除它们,或者我会在那里添加其他东西。 - Sander
听起来像是代码审查,而不是普通的StackOverflow问题。 - v.oddou
显示剩余4条评论
1个回答

5
您有几个bug:
  • Sphere::Collides中,当t2>=t1时,m_fCollisionTime没有被设置
  • Sphere::Collides中,如果m_fCollisionTime是负数,则射线实际上不与球相交(这导致球顶部出现奇怪的阴影)
  • 将平面放低一点,你就会看到球的阴影
  • 从眼睛发射射线时,您需要检查最近的碰撞(只需尝试交换对象的顺序,球突然变成了平面后面)
修复这些问题后,您将得到以下结果:enter image description here

谢谢你的帮助,伙计!我会尽快尝试。第二个 bug 有道理,因为这就是第二张图片看起来更好的原因。我曾经看到过这个 bug 并进行了更改,但后来我没有看到任何区别,所以我将其删除了。 - Sander
它可以工作!我会尽快回答这个问题。当t2 >= t1时,我忘记分配fCollisionTime真的很愚蠢。但这就是编程生活...球体也有两种不同的颜色,原因是我删除了“.normalized()”。最近的碰撞也是一个好提示!我现在只是交换了元素。 - Sander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接