I'm currently working working on a unbiased path tracer. To test how accurate it is. I created a scene in my path tracer and LuxRender then compare the rendered image. I found that the shadow in the image that my path tracer rendered is too dark. Why? Any possible reason?
Also, I have implemented Gamma 2.2 in my renderer. So it won't be the issue of gamma correction. And, recursive path tracing IS enabled. both image are rendered in global illumination.
Here are the rendering result from LuxRender and my own renderer.(Please ignore the back triangle(light source) in Lux. It's how Lux behaves.)
---- Edit ----
Edit: Here are the trace() function(get radiance)
float4 Renderer::trace(Ray ray, Scene* scene)
{
const int BOUNCE_DEPTH = getBounceDepth();
//Russian roulette: starting at depth 5
const int RUSSIAN_ROULETTE_START_DEPTH = 16;
const float FACTOR_CUT_OFF = 1e-5;
float4 factor(1.0f,1.0f,1.0f,1.0f);
float4 renderedColor;
Ray currentRay = ray;
float4 lastNormal = ray.direction;
float rrFactor = 1.0f;
for(int i=0;i<BOUNCE_DEPTH||BOUNCE_DEPTH < 0;i++)//To ignore bounce limit. set bounceDepth to -1
{
if(i >= RUSSIAN_ROULETTE_START_DEPTH)
{
const float stopProbability = 0.1f;
if(((float)rand()/RAND_MAX) < (1.0-stopProbability))
break;
vrrFactor *= 1.0f/(1.0f-stopProbability);
//cout << rrFactor << endl;
}
//stop bouncing if factor is too small.
//This is a biased method. Remove this if you want unbiased rendering
if(factor.x + factor.y + factor.z <= FACTOR_CUT_OFF)
break;
RayHit hit = acclerator->raycast(currentRay);
if(hit.distance > 0)
{
int index = hit.index;
Triangle emit(scene->emitColor[scene->indices[index*3]],
scene->emitColor[scene->indices[index*3+1]],
scene->emitColor[scene->indices[index*3+2]]);
Triangle triangle(scene->vertices[scene->indices[index*3]],
scene->vertices[scene->indices[index*3+1]],
scene->vertices[scene->indices[index*3+2]]);
Triangle reflectColor(scene->reflectColor[scene->indices[index*3]],
scene->reflectColor[scene->indices[index*3+1]],
scene->reflectColor[scene->indices[index*3+2]]);
//if(i > 1)//Only collect indirect lighting
renderedColor += factor*emit.interpolation(hit.u,hit.v)*rrFactor;
factor *= reflectColor.interpolation(hit.u,hit.v);
//randomly sample on a hemisphere
Ray reflecRay;
reflecRay = createRandomReflect(currentRay, triangle,
currentRay.origin + normalize(currentRay.direction)*hit.distance);
float4 triangleNormal = triangle.normal();
if(dot(triangleNormal,currentRay.direction) < 0)
triangleNormal = -triangleNormal;
currentRay = reflecRay;
lastNormal = triangle.normal();
if(dot(currentRay.direction,lastNormal) < 0)
lastNormal = -lastNormal;
factor *= dot(normalize(currentRay.direction),lastNormal);//Difduse BRDF
}
else
break;
}
return renderedColor;
}
And the render() function (generate image)
void Renderer::render(Scene* scene)
{
//srand(5000);
memset(frameBuffer,0,bufferWidth*bufferHeight*sizeof(float4));
int pixelCount = bufferWidth*bufferHeight;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
int renderIndex = 0;
acclerator->setScene(scene);
acclerator->build();
const int SAMPLE_NUM = getSampleNum();
float4 origin = scene->camera.position
+ 2.0f*scene->camera.right/(float)scene->camera.width
+ 2.0f*scene->camera.up/(float)scene->camera.height;
#pragma omp parallel for schedule(dynamic)
for(int i=0;i<pixelCount;i++)
{
float4 renderedColor = float4(0.0f,0.0f,0.0f,0.0f);
//Create camera ray
int x = i % bufferWidth;
int y = i / bufferWidth;
float4 rayVec = (x/(float)scene->camera.width-0.5f)*scene->camera.right*scene->camera.pixelAspectRatio
+ (0.5f-y/(float)scene->camera.height)*scene->camera.up
+ scene->camera.direction;
for(int j=0;j<SAMPLE_NUM;j++)
{
Ray ray(origin, rayVec);
renderedColor += trace(ray,scene);
}
renderedColor /= (float)SAMPLE_NUM;
//simple gamma correction
const float gamma = 2.2;
const float inversedGamma = 1.0f/gamma;
float4 correctedColor = pow(renderedColor,float4(inversedGamma,inversedGamma,inversedGamma,0));
((float4*)frameBuffer)[i] = correctedColor;
#pragma omp atomic
renderIndex++;
#pragma omp critical
if(renderIndex%500 == 0)
cout << "Rendering " << renderIndex << "/" << pixelCount << ". " << (float)renderIndex*100.0/pixelCount << "\r";
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
double elapsed = duration_cast<duration<double>>( t2 - t1 ).count();
cout << endl << "elapsed: " << elapsed << " ," << pixelCount*SAMPLE_NUM/elapsed/1000/1000 << " MSamples/s"<< endl;
}
---- End Edit ----
Scene Rendered by LuxRender (PBRT gives me the same result)
Renderer: Sampler, Sampler : metropolis, (Other settings are defalut)
The same scene rendered my by renderer. Note the scene is a bit darker and shadow is way too dark.