Jump to content
  • Advertisement
Sign in to follow this  
h3ro

Raytracer: Lights?

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

If you intended to correct an error in the post then please contact us.

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;
                    float oneOverRadius = 1/thisSphere.getRadius();
                    
                    normal = sphereRayIntersection - thisSphere.getPosition();
                    normal.scale(oneOverRadius);
                    
                    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 this post


Link to post
Share on other sites
Advertisement
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 this post


Link to post
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 this post


Link to post
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 sphere
Material 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 this post


Link to post
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 :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!