I am getting weird artifacts in my simple ray tracer that I made using the book Ray Tracing in One Weekend by Peter Shirley.
Example:
(circular pattern on the ground and black tint on the spheres.)
I suspect these artifacts are due to hit point of the primary rays being under or above the surface, which causes secondary rays to intersect with the object itself.
I tried to fix this by moving the hit point of primary rays along the surface normal at that point. Here's the result :
The artifacts are gone but that broke the dielectric material (sphere on the left). It is acting as a reflective sphere rather than a transparent one.
Code for the dielectric material :
virtual bool scatter(const Ray &inRay, const HitInfo &hitInfo, Vector3 &attenuation, Ray &scatteredRay) const {
attenuation = Vector3(1.0f);
Vector3 normal;
Vector3 refracted;
float refractiveIndexRatio; //n1/n2 = sin(a2)/sin(a)
float cosine = 0.0f;
if (hitInfo.hitNormal * inRay.direction() > 0) {
normal = -hitInfo.hitNormal;
refractiveIndexRatio = refractiveIndex;
cosine = hitInfo.hitNormal * inRay.direction();
}
else {
normal = hitInfo.hitNormal;
refractiveIndexRatio = 1.0f/refractiveIndex;
cosine = -hitInfo.hitNormal * inRay.direction();
}
float reflectProb = 0.0f;
if (Vector3::refract(inRay.direction(), normal, refractiveIndexRatio, refracted)) {
reflectProb = schlickApproximation(cosine, refractiveIndex);
}
else {
reflectProb = 1.0f;
}
if (randomfloatGenerator() < reflectProb) {
Vector3 reflected(Vector3::reflect(inRay.direction(), normal));
scatteredRay = Ray(hitInfo.hitPoint + normal * CORRECTION_FACTOR, reflected);
}
else {
scatteredRay = Ray(hitInfo.hitPoint + normal * CORRECTION_FACTOR, refracted);
}
return true;
}
I changed hitInfo.hitPoint
to hitInfo.hitPoint + normal * CORRECTION_FACTOR
, in the if - else
case at the bottom of the function, to correct those artifacts. (CORRECTION_FACTOR = 0.0001f
)
How can I correct this "self intersection" problem without breaking my materials ?