# Next Event Estimation for Triangle-based Light Sources

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);

while(alpha+beta>1)
{
ran1=rand01();
ran2=rand01();
alpha=1-sqrt(ran1);
beta=(1-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:

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

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

## 1 Answer

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.

• 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$. Jan 8 at 12:52