Why data is lost when calculating shadow and reflections in my ray

I am creating a ray tracer and I can render the diffuse and specular parts of my sphere correctly. When I come to calculate shadows and reflections, however, I end up with a very sharp result as shown in the image below:

enter image description here

I can see that the shadow is being cast in the right place, and if you increase the reflection, it is also visible, but is pixelated again. I call this method to determine if a pixel is in shadow, and it is also called recursively by my reflective ray method to determine reflected colors.

    RGBColour Scene::illumination(Ray incidentRay, Shape *closestShape, RGBColour shapeColour, Ray ray)
{
    RGBColour diffuseLight = _backgroundColour;
    RGBColour specularLight = _backgroundColour;
    double projectionNormalToSource = 0.0;

    for (int i = 0; i < _lightSources.size(); i++)
    {
        Ray shadowRay(incidentRay.Direction(), (_lightSources.at(i).GetPosition() - incidentRay.Direction()).UnitVector());

        Vector surfaceNormal = closestShape->SurfaceNormal(incidentRay);

        //lambertian shading.
        projectionNormalToSource = surfaceNormal.ScalarProduct(shadowRay.Direction());

        if (projectionNormalToSource > 0)
        {
            bool isShadow = false;

            std::vector<double> shadowIntersections;

            Ray temp(incidentRay.Direction(), (_lightSources.at(i).GetPosition() - incidentRay.Direction()));
            for (int j = 0; j < _sceneObjects.size(); j++)
            {
                shadowIntersections.push_back(_sceneObjects.at(j)->Intersection(temp));
            }

            //Test each point to see if it is in shadow.
            for (int j = 0; j < shadowIntersections.size(); j++)
            {
                if (shadowIntersections.at(j) != -1)
                {
                    if (shadowIntersections.at(j) > _epsilon && shadowIntersections.at(j) <= temp.Direction().Magnitude() && closestShape != _sceneObjects.at(j))
                    {
                        isShadow = true;
                    }
                    break;
                }
            }

            if (!isShadow)
            {
                diffuseLight = diffuseLight + (closestShape->Colour() * projectionNormalToSource * closestShape->DiffuseCoefficient() * _lightSources.at(i).DiffuseIntensity());
                specularLight = specularLight + specularReflection(_lightSources.at(i), projectionNormalToSource, closestShape, incidentRay, temp, ray);
            }
        }
    }
    return diffuseLight + specularLight;
}

      

How can I properly separate the spheres from these aspects, I am convinced that the problem must lie in this particular method, so I have not posted others. I think that when the pixel values ​​keep their initial color instead of being shaded, I must be calculating very small values ​​incorrectly, or the other option is that the calculated ray did not intersect, however, I do not think the latter is valid otherwise the same intersection method would return incorrect results elsewhere in the program, but as the spheres display correctly (excluding shading and reflection).

Generally, what leads to such results, and can you find any obvious logical errors in my method?

Edit . I moved my light to the front and now I can see that the shadow looks correct for the green sphere and the blue for the pixelated one. So I think that on any subsequent iterations of the form, something shouldn't update correctly.

Edit 2 . The first issue is fixed and the shadows are no longer pixelated, the resolution was to move the break statement to the if statement immediately preceding it. The problem is the reflections are still jagged, still happening at the moment.

enter image description here

+3


source to share


1 answer


This pixelation can occur due to numerical instability. Example. Suppose you have computed an intersection point that lies on a curved surface. Then you use this point as a ray source (shadow ray, for example). You would assume that the beam will not cross this curved surface, but in practice it can sometimes. You can test this by discarding such self-intersections, but this can cause problems if you choose to embed concave shapes. Another approach would be to move the origin of the generated ray along its direction vector by some infinitesimal amount so that no unwanted self-intersection occurs.



+1


source







All Articles