문제

I've been working on a raytracing algorithm for a class, and have run into a strange problem.

img

This is the basic scene I'm working on. Nothing major, all okay. Now, my code is organised thusly:

Image* Tracer::render()
{
    int w = _scr.width();
    int h = _scr.height();
    Image* im = new Image(w, h);
    int i, j;
    for(i = 0; i < h; i++)
    {
        for(j = 0; j < w; j++)
        {
            im->setColour(i, j, render(i, j));
        }
    }
    return im;
}

I call this function to generate the image. To colour each pixel:

Vec Tracer::render(int i, int j)
{
    Vec pxlcol(0,0,0);
    Vec p(0,0,0);
    int obj;
    Vec dir = _scr.point(i,j);
    dir = dir - _obs;
    obj = intercept(_obs, dir, p);
    if(obj != -1)
    {
        pxlcol = objCol(_obs, p, obj, _ref);
    }
    return pxlcol;
}

Where int Tracer::intercept(Vec o, Vec d, Vec& p) is the following function

int Tracer::intercept(Vec o, Vec d, Vec& p)
{
    int obj, k;
    Vec temp = o;
    Vec ptry = o;
    obj = -1;
    for(k = 0; k < _nobj; k++)
    {
        temp = _obj[k]->intercept(o, d);
        if( !(temp == o) && (((temp - o).mod() < (ptry - o).mod()) || (ptry == o)))
        {
            ptry = temp;
            obj = k;
        }
    }
    p = ptry;
    return obj;
}

which finds the index k of the object that's intercepted by ray d starting at o and also returns the point p where such interception happens, and Vec Tracer::objCol(Vec o, Vec p, int obj, int r) is the function

Vec Tracer::objCol(Vec o, Vec p, int obj, int r)
{
    Vec colour(0,0,0);
    Vec point(0,0,0), reflected(0,0,0);
    unit ref = _obj[obj]->ref(p);
    if((1 - ref) > 0)
        point = pointCol(o, p, obj);
    if(ref > 0 && r > 0)
        reflected = refCol(o, p, _obj[obj]->normal(o, p), r - 1);
    colour = (point*(1 - ref)) + (reflected*ref);
    return colour;
}

which finds the colour that point p sends in the direction o knowing that it belongs to object obj and that the maximum number of reflections allowed is r.

When I make the back (white) wall reflective, this is the result:

img

Looks pretty ok, no problems there. Now, if I make the right (blue) wall reflective, the result is this:

img

(I can't post more than 2 links yet, remove the parentheses to see the image). And it gets even worse if I decide to make the sphere reflective:

img

It gets transparent! And I don't know why that would happen, since I look for ray interception before getting to the colours.

Here are my codes for finding the point colour and the reflected colour:

Vec Tracer::pointCol(Vec o, Vec p, int obj)
{
    Vec pcol(0,0,0);
    Vec inten(0,0,0);
    unit cos = 0;
    Vec c(0,0,0);
    Vec normal = _obj[obj]->normal(o, p);
    Vec inter = o;
    Vec objcol = _obj[obj]->colour(p);
    bool block = false;
    if(_amb == 1)
        return objcol;
    int l = 0;
    int k = 0;
    for(l = 0; l < _nlight; l++)
    {
        c = _li[l]->getPos() - p;
        block = false;
        if(c*normal > 0)
        {
            for(k = 0; k < _nobj; k++)
            {
                if(k != obj)
                {
                    inter = _obj[k]->intercept(p, c);
                    inter = inter - p;
                    if(!(inter.null()) && (inter.mod() < c.mod()))
                    {
                        block = true;
                        k = _nobj;
                    }
                }
            }

            if(!block)
            {
                cos = (c*normal)/(c.mod()*normal.mod());
                inten = inten + _li[l]->getInt()*cos;
            }
        }
    }

    inten = inten.div(_totalinten);
    pcol = objcol*_amb + objcol.multi(inten)*(1 - _amb);
    return pcol;
}

The constant _amb defines how much of the light is ambient light and how much is diffuse.

The function Vec Vec::div(Vec v) returns the pointwise division of the vectors (e.g. (a, b, c).div((x, y, z)) = (a/x, b/y, c/z)). The function Vec Vec::multi(Vec v) does the same for multiplication.

Vec Tracer::refCol(Vec o, Vec p, Vec n, int r)
{
    Vec rcol(0,0,0);
    Vec i = p - o;
    Vec refl(0,0,0);
    int obj = 0;
    Vec point(0,0,0);
    i.normalise();
    refl = reflected(i, n);
    obj = intercept(p, refl, point);
    if(obj != -1)
    {
        rcol = objCol(p, point, obj, r);
    }
    return rcol;
}

Since objCol calls refCol with parameter r-1, the number of reflections is bounded above by _ref.

Any idea what could be causing these strange reflection effects?

도움이 되었습니까?

해결책

This was a comment, I made an answer out of it because it seems to work:

Although I haven't checked the code yet, this looks like a z-fighting/floating point comparison problem - try to move the intersection point a bit away from the reflecting object along its normal or make sure the reflected ray can't collide with the original object, this could fix it.

What happens here most likely is that randomly the ray gets reflected by the object, but hits the object again as the intersection point isn't exact (floating point inaccuracy) - this will cause the reflected ray to flip again and get reflected more often or finally go in the right (reflected) direction - or pass through the object in the wrong (original) direction, looking like the object being transparent.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top