I have a question regarding the NEE for light sources that are composed from triangles. I implemented the next event estimation (explicit light source sampling) for spherical light sources but after all of the trials, the output is always noisy and not even close to spherical luminaries.

        else if(const Triangle* tr=dynamic_cast<const Triangle*>(prim))
            double ran1=rand01();
            double ran2=rand01();

            double alpha=1-sqrt(ran1);
            double beta=(1-ran2)*sqrt(ran1);
            double gamma=ran2*sqrt(ran1);


            Vec firstEdge=tr->vertex1-tr->vertex0;
            Vec secondEdge=tr->vertex2-tr->vertex0;
            Vec nPrime=secondEdge.cross(firstEdge);
            double A=nPrime.length()*1/2;

            Vec xPrime = tr->vertex0*alpha+tr->vertex1*beta+tr->vertex2*gamma;

            Vec omega=(xPrime-x).normalize();
            Vec inverseOmega=(x-xPrime).normalize();

            double cosTheta=clamp(((n-x).normalize()).dot(inverseOmega))/(n-x).length()*inverseOmega.length();
            double cosThetaPrime=abs(((nPrime-xPrime).normalize()).dot(omega))/(nPrime-xPrime).length()*omega.length();
            double magOfxPrimeToX=(xPrime-x).dot(xPrime-x);
            int idShadowRay=0;
            double tShadowRay;
            Vec xShadowRay;
            Vec nShadowRay;

            if(intersect(Ray(x,xPrime),idShadowRay,tShadowRay,xShadowRay,nShadowRay) && idShadowRay==i)
                L_direct = L_direct + (f.mult(tr->e))*(cosTheta)*(cosThetaPrime/magOfxPrimeToX) /(1/A);

After the loop ends for the light sources, I add direct contribution and indirect contribution in the return statement: return obj.e * emissive + L_direct + f.mult(radiance(Ray(x, d), depth, 0));

The result with 150 sample with 750x500 resolution: enter image description here

However spherical light sources are quite succesful in same specifications (150 sample with 750x500 resolution):

enter image description here

What could be wrong in this case ? Thanks a lot.


1 Answer 1


I found my error which was quite hard to understand but I think it is misleading on it's explanations in books. The visibility term is denoted most of the time as V(x,x'). However, if visibility is taken account as form one point to another, it gives a wrong answer. The correct fix for that is to get the intersection point "x" to direction of " x' ". In that case visibility is changed as V(x,(x'-x).normalized()). So, a direction should be used, not a point.

  • 2
    $\begingroup$ It doesn't give a wrong answer if you implement it correctly, your code was simply not computing visibility between two points but rather expected a point and direction. There is a difference between the ray-tracing function $r(x, \omega)$ and the visibility function $V(x,y)$. Another pitfall you may run into is floating point precision. So typically one uses instead $V(x+\epsilon N_x, y + \epsilon N_y)$ instead of $V(x,y)$ in order to avoid self-intersection. $N_x, N_y$ being the normals such that $N_x\cdot (y-x)>0$ and $N_y \cdot (x-y)>0$. $\endgroup$
    – lightxbulb
    Commented Jan 8, 2022 at 12:52
  • $\begingroup$ i tried to use this but it still doesn't work after your recommended fix, I have a lot of 'white' pixels - which makes me think there's division by zero somewhere $\endgroup$
    – rajasaurus
    Commented Jan 10 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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