6
$\begingroup$

After spending a few days making very little headway with a simple Raytracing program that implements Phong illumination (with shadows and no attenuation), I'm convinced I've made a logic error that I'm overlooking.

As I understand it, the pseudo-code should look like this:

ambient light
for each light source
    direction of light = light point - point on the object
    test for an intersection starting at the point on the object, until you hit something
    if (the intersection test returned a distance > distance from point on object to light point)
    (do  diffuse and specular shading)

A one quick thing to mention about my implementation: the intersection test will return 9999999 if there is no intersection.

Some of the things I've tried are: inverting the direction of the shadow ray - no effect. Making the comparison intersection distance - light distance > (some small epsilon value) - no change. Manually moving the light source to the opposite side - the specular reflection moved to a new spot, but otherwise, no change.

Here's a picture of my most recent output, I'm trying to get a shadow in the bottom left corner of the light gray plane.

The shadow should be in the lower left corner of the plane

Any help would be greatly appreciated.

Here's the relevant part of my code:

    //iterate through all lights
    if (myLights.size() > 0)
    {
        for (int i = 0; i < myLights.size(); i++)
        {
            //calculate the direction of the light
            glm::vec3 ldir = (myLights[i].position - surfacePoint);
            //this the length of the distance between the light and the surface
            float ldist= sqrt(pow(ldir.x, 2.0f) + pow(ldir.y, 2.0f) + pow(ldir.z, 2.0f)); 
//check if the light can see the surface point
            float intersections = myObjGroup->testIntersections(surfacePoint, normalize(ldir));
            if (abs(intersections-ldist)  > 0.0000001f)
            {
                //diffuse and specular shading have been cut for brevity
            }
        }
    }

edit: New image: New image!

$\endgroup$
  • 4
    $\begingroup$ Pro tip: x * x is much faster than pow(x, 2.0f). $\endgroup$ – Dan Hulme Nov 19 '15 at 9:49
6
$\begingroup$

Your if condition makes me suspicious. You should include the diffuse and specular shading if the intersection test didn't hit an object; that is, if intersections > ldist. So, your code should look as follows:

if (intersections > ldist)
{
    colour += diffuse(...);
    colour += specular(...);
}

Your comparison with 0.0000001f suggests that you've also been having trouble with self-intersections (that is, with the ray intersecting the object being shaded). In a one-hit tracer, you can't fix that problem by simply discarding the intersection, because you still don't know whether the shadow ray would have intersected another object further along. To avoid self-intersections, you need to push the start point of the ray along its direction by epsilon:

glm::vec3 direction = normalize(ldir);
glm::vec3 start = surfacePoint + epsilon * direction;
float intersections = myObjGroup->testIntersections(start, direction);

One more thing: don't forget to test that the light is in front of the surface that you're illuminating. You can do this with the dot product of ldir and the surface normal: if the dot product is positive, the light is on the correct side; if it's negative, the light is behind the surface and thus shadowed before you even cast a ray.

$\endgroup$
  • $\begingroup$ Thank you very much for your help, I really appreciate you taking the time to write it. I have implemented your suggestions. Unfortunately, my shadows are still missing. My most recent output is in the original qustion. I'm assuming this means the problem is somewhere upstream in my code. Of course, that's about 200-300 lines of setting my stage. If you've got the stomach for it, I've put it on pastebin. If you don't, I totally understand. I really appreciate your assistance; I've been so close to this for so long I think I've become blind to my mistakes $\endgroup$ – user1764241 Nov 19 '15 at 23:55
  • 1
    $\begingroup$ If you're still having trouble, just apply the usual debugging techniques. Keep simplifying your code to cut the problem space in half. Try removing all the shading computation and just set the colour to intersections / 999999, so your unshadowed intersections are just white. Draw an object at the light position to make sure it's correct: in both your renders, it looks like it might be in the bottom-right of the image, between the two objects. Put a breakpoint conditional on the shading co-ordinates and step through the shading of one particular point that you know ought to be in shadow. $\endgroup$ – Dan Hulme Nov 20 '15 at 9:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.