# Raytracer: Lights?

This topic is 4171 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hallo, I'm working on a raytracer, but I am having some problems with adding lights to it. For some reasons all my objects get black, as if no light is hitting them. I have tryed moving the light around to make sure that the objects are not simply placed in front of the light. I have some ideas on why this happens. One problem is that "lightCoef" is allways less or equal to zero. Not sure why, but for some reason it is. I did try to make "lighCoef" posetive by doing AbsDot() insted of Dot(), that made the spheres visible, but they had no gradient on them, so the color was just as flat as befor I tryed to add lights. Any ideas on what is wrong? I have been trying to solve this the whole day and is now close to giving up. If this is not enugh code to see what is wrong I can post more, but I tryed to only post what is needed as it is often boring to read through to much code. Thanks a lot for your time:)
                float r, g, b;

// Check which if there is a light affecting the sphere
for (int currentLight = 0; currentLight <= thisScene.getAmountOfObjects(); currentLight++)
{
Vector3D sphereRayIntersection;
Point rayOrg = currentRay.getOrigin();

// Add the start point of the ray and the direction of the sphere together
// and mult. it with the distance to closest sphere
sphereRayIntersection = currentRay.getDirection();
sphereRayIntersection.setX(sphereRayIntersection.getX() + rayOrg.getX());
sphereRayIntersection.setY(sphereRayIntersection.getY() + rayOrg.getY());
sphereRayIntersection.setZ(sphereRayIntersection.getZ() + rayOrg.getZ());

sphereRayIntersection.scale(closesSphereDistance);

// Find the normal to the sphere at point of intersection
Sphere thisSphere = thisScene.getSphere(closestSphere);
Vector3D normal;

normal = sphereRayIntersection - thisSphere.getPosition();

normal.normalize();

// Get the light direction
Vector3D lightDir;

Sphere thisLight = thisScene.getLight(currentLight);
lightDir = thisLight.getPosition() - sphereRayIntersection;

lightDir.normalize();

// Find light coefficient
float lightCoef = Dot(lightDir,normal);
if (lightCoef < 0)
lightCoef = 0;

// Get the color of the light and how much it affects the sphere
Material thisMaterial = thisLight.getMaterial();

float lightR = thisMaterial.getR() * lightCoef;
float lightG = thisMaterial.getG() * lightCoef;
float lightB = thisMaterial.getB() * lightCoef;

// Add the effect of the light to the color of the sphere
Material sphereColor = thisSphere.getMaterial();

r = ((sphereColor.getR() * lightR) / 255 );
g = ((sphereColor.getG() * lightG) / 255);
b = ((sphereColor.getB() * lightB) / 255);

// Make sure that the color is not higher than 255
if (r > 255)
r = 255;
if (g > 255)
g = 255;
if (b > 255)
b = 255;

//std::cout << r << "," << g << "," << b << std::endl;
}

// Assign the color to the pixel
int colorR = r;
int colorG = g;
int colorB = b;

colorBuffer[arrayTracer + 0] = colorR;
colorBuffer[arrayTracer + 1] = colorG;
colorBuffer[arrayTracer + 2] = colorB;

[/source] [Edited by - h3ro on April 19, 2007 5:42:43 PM]

##### Share on other sites
Are you sure your calculation for getting the intersection point is generating the right result? It should be (origin + (direction * distance)) not ((origin + direction) * distance). Most likely this is causing your surface normal to be incorrect, which is yielding the bogus lighting. Also, note that scaling the normal by the sphere's radius is totally useless since the next step is to normalize it, which forces the length to 1 [wink]

As for posting code - try making your [ code ] tags lowercase, or use [ source ] instead (which is preferable for long bits of code).

##### Share on other sites
Thanks for you post, but it did not really solve my problem.

Here is the picture I have now:
http://img89.imageshack.us/img89/18/raytracedscenehz9.jpg

As you see something must be wrong:P

##### Share on other sites
Perhaps your light is simply way too bright? :) Try to divide the final result by 10 or so.

##### Share on other sites
Hi there!

sphereRayIntersection = currentRay.getDirection();sphereRayIntersection.setX(sphereRayIntersection.getX() + rayOrg.getX());sphereRayIntersection.setY(sphereRayIntersection.getY() + rayOrg.getY());sphereRayIntersection.setZ(sphereRayIntersection.getZ() + rayOrg.getZ());                    sphereRayIntersection.scale(closesSphereDistance);

If 'currentRay' represents a ray of the form 'origin + t*dir' and 'closesSphereDistance' is supposed to be the parameter 't' for the ray at which it intersects the sphere, then the point 'sphereRayIntersection' should be 'origin + t*direction', not '(origin + direction)*t', just as ApochPiQ mentioned. So the above code snippet should be changed to something like this:

sphereRayIntersection = currentRay.getDirection();sphereRayIntersection.scale(closesSphereDistance);sphereRayIntersection.setX(sphereRayIntersection.getX() + rayOrg.getX());sphereRayIntersection.setY(sphereRayIntersection.getY() + rayOrg.getY());sphereRayIntersection.setZ(sphereRayIntersection.getZ() + rayOrg.getZ());

When you changed that you should really debug whether the result can be right or not (best to test that with a single sphere centered around the origin and a radius of 1, because then you only have to check the absolute value of 'sphereRayIntersection' to see whether your results are plausible).
As soon as you're sure these calculations are correct you can go on and calculate the normal like you do (the normalizition is unnecessary because the division by the radius already does that).
For simplicity you should just use the absolute value of the dot-product between light-vector and normal. If that works and you don't like it, it should be easy to take the signed value, but for debugging it just takes away one possible error source.
Now to your color calculation, which looks quite odd to me, even assuming 'lightCoef' is correct:
Material thisMaterial = thisLight.getMaterial();                    float lightR = thisMaterial.getR() * lightCoef;float lightG = thisMaterial.getG() * lightCoef;float lightB = thisMaterial.getB() * lightCoef;                                        // Add the effect of the light to the color of the sphereMaterial sphereColor = thisSphere.getMaterial();             r = ((sphereColor.getR() * lightR) / 255 );g = ((sphereColor.getG() * lightG) / 255);b = ((sphereColor.getB() * lightB) / 255);

The divisions by 255 indicate that colors stored in the material are ints in [0,255]. If they really are that color calculation for 'r', 'g' and 'b' won't work as expected. Convert all the colors you use into [0,1] as floats. The reason for that:
Assume you have a white light shining on a white surface. With the int-colors in [0,255] that makes the last three lines:
r = (255 * 255 * lightCoef) / 255 = 255² * lightCoef / 255 = 255* lightCoef

Same for the 'g' and 'b' values.
Now using float color values in [0,1]:
r = (1.f*1.f*lightCoef) = lightCoef

If your color values are not ints in [0,255], then just ignore what I just said. But then I don't understand your last division by 255.

Hope that helped

PS: you should move the calculation of 'sphereRayIntersection' and 'normal' out of the for-loop that iterates over the lights, because they won't change anyway. Not important yet, still wanted to say that.

##### Share on other sites
Thank you all for your help.

phantomus: The light was to bright, so thanks for pointing me into that direction. That helped me find my error in the code.

matches81: Thanks for the help :)

1. 1
2. 2
Rutin
22
3. 3
4. 4
5. 5
frob
12

• 17
• 9
• 31
• 16
• 9
• ### Forum Statistics

• Total Topics
632615
• Total Posts
3007441

×