刚刚开始写光线跟踪,今天准备实现阴影的效果,但是发现了一些问题。
先上图:
球体自身的阴影叠加在了球体上方,
并且来自其他球体的影子显示也不正确。我想了很久也没发现问题在哪。
还请各位前辈指点一下。
相关代码:
RGBColor Phong::Shade(ShadeRec &sr)
{
Vector3D wo(-sr.m_ray.d);
RGBColor L = m_ambientBRDF->rho(sr, wo) * sr.m_world.m_ambient->L(sr);
int lightsNum = sr.m_world.m_lights.size();
for (int i = 0; i < lightsNum; ++i)
{
Vector3D wi = sr.m_world.m_lights[i]->GetDirection(sr);
float ndotwi = sr.m_hitPointNormal * wi;
if(ndotwi > 0.0)
{
bool inShadow = false;
if(sr.m_world.m_lights[i]->castsShadow())
{
Ray shadowRay((sr.m_worldHitPoint + kEpsilon), wi);
inShadow = sr.m_world.m_lights[i]->inShadow(shadowRay, sr);
}
if(!inShadow)
{
L += (m_diffuseBRDF->fr(sr, wo, wi) + m_specularBRDF->fr(sr, wo, wi))
* sr.m_world.m_lights[i]->L(sr) * ndotwi;
}
}
}
return L;
}
bool PointLight::inShadow(const Ray &shadowray, const ShadeRec &sr)
{
float ht(sr.m_t);
float t;
int ObjectNum = sr.m_world.m_objects.size();
float d = m_location.distance(shadowray.o);
for (int i = 0; i < ObjectNum; ++i)
{
if(sr.m_world.m_objects[i]->ShadowHit(shadowray, t) && t < d)
{
return true;
}
}
return false;
}
bool Sphere::ShadowHit(const Ray &ray, float &tmin) const
{
const double ep = 0.01;
double t0, t1;
Vector3D oc = ray.o - center;
double a = ray.d * ray.d;
double b = 2.0 * oc * ray.d;
double c = oc * oc - radius * radius;
double disc = b * b - 4.0 * a * c;
if (disc < 0.0)
{
return false;
}
double e = sqrt(disc);
double denom = 2.0 * a;
t0 = (-b - e) / denom;
if (t0 > ep)
{
tmin = t0;
return true;
}
t1 = (-b + e) / denom;
if (t1 > ep)
{
tmin = t1;
return true;
}
return true;
}
On the importance of naming variables, I don’t even know what you are writing when you write it like this. However, according to my experience, when you are calculating the shadow of a point, you may forget to judge whether the object that may cause the shadow is not between the point and the light source , or the equivalent effect is caused by a clerical error.
Also, when you obtain an intersection point to calculate the shadow, you may need to move the point one epsilon outward in the normal direction. It looks like you did something similar to me.
The way to solve this problem: write detailed comments on your code. Once you write it, you will understand.
Finally, I will give you a ray tracing I wrote before for your reference. What I wrote was relatively casual, and I only did reflection, refraction, shadow, AO and some mapping functions. There is no performance optimization at all, no matter how beautiful the code is, you can write it. When intersecting complex objects, it is completely divided into kd-trees evenly (the normal method is to cut according to the distribution of points, and try to cut out the blank areas).
Graphics is really a good series to kill time
http://www.cppblog.com/vczh/archive/2011/01/09/138196.html
http://www.cppblog.com/vczh/archive/2011/01/21/138990 .html
http://www.cppblog.com/vczh/archive/2011/01/22/139112.html
1 I don’t see where your kEpsilon is calculated. I guess what you want to express is to re-project the shadow ray floating a little bit on the intersection surface. Then should you use kEpsilon * normal as bias?
2 The inShadow function does not judge the situation of t < 0. Has the negative direction been excluded when calculating the intersection in ShadowHit?
3 I noticed that you did the reverse to get the Li Direction. I wonder if the direction of wi=light::GetDirection(sr) is correct when getting the shadow ray direction?