示例#1
0
u_int64_t CPU_Worker::AdvancePhotonPath(u_int64_t photonTarget) {



    uint todoPhotonCount = 0;

    PhotonPath* livePhotonPaths = new PhotonPath[rayBuffer->GetSize()];

    rayBuffer->Reset();

    size_t initc = min((int) rayBuffer->GetSize(), (int) photonTarget);

    double start = WallClockTime();


    for (size_t i = 0; i < initc; ++i) {

        int p = rayBuffer->ReserveRay();

        Ray * b = &(rayBuffer->GetRayBuffer())[p];

        engine->InitPhotonPath(engine->ss, &livePhotonPaths[i], b, seedBuffer[i]);
    }

    while (todoPhotonCount < photonTarget) {

        Intersect(rayBuffer);

#ifndef __DEBUG
        omp_set_num_threads(config->max_threads);
        #pragma omp parallel for schedule(guided)
#endif
        for (unsigned int i = 0; i < rayBuffer->GetRayCount(); ++i) {
            PhotonPath *photonPath = &livePhotonPaths[i];
            Ray *ray = &rayBuffer->GetRayBuffer()[i];
            RayHit *rayHit = &rayBuffer->GetHitBuffer()[i];

            if (photonPath->done == true) {
                continue;
            }

            if (rayHit->Miss()) {
                photonPath->done = true;
            } else { // Something was hit

                Point hitPoint;
                Spectrum surfaceColor;
                Normal N, shadeN;

                if (engine->GetHitPointInformation(engine->ss, ray, rayHit, hitPoint, surfaceColor,
                                                   N, shadeN))
                    continue;

                const unsigned int currentTriangleIndex = rayHit->index;
                const unsigned int currentMeshIndex = engine->ss->meshIDs[currentTriangleIndex];

                POINTERFREESCENE::Material *hitPointMat =
                    &engine->ss->materials[engine->ss->meshMats[currentMeshIndex]];

                uint matType = hitPointMat->type;

                if (matType == MAT_AREALIGHT) {
                    photonPath->done = true;
                } else {

                    float fPdf;
                    Vector wi;
                    Vector wo = -ray->d;
                    bool specularBounce = true;

                    float u0 = getFloatRNG(seedBuffer[i]);
                    float u1 = getFloatRNG(seedBuffer[i]);
                    float u2 = getFloatRNG(seedBuffer[i]);

                    Spectrum f;

                    switch (matType) {

                    case MAT_MATTE:
                        engine->ss->Matte_Sample_f(&hitPointMat->param.matte, &wo, &wi, &fPdf, &f,
                                                   &shadeN, u0, u1, &specularBounce);

                        f *= surfaceColor;
                        break;

                    case MAT_MIRROR:
                        engine->ss->Mirror_Sample_f(&hitPointMat->param.mirror, &wo, &wi, &fPdf,
                                                    &f, &shadeN, &specularBounce);
                        f *= surfaceColor;
                        break;

                    case MAT_GLASS:
                        engine->ss->Glass_Sample_f(&hitPointMat->param.glass, &wo, &wi, &fPdf, &f,
                                                   &N, &shadeN, u0, &specularBounce);
                        f *= surfaceColor;

                        break;

                    case MAT_MATTEMIRROR:
                        engine->ss->MatteMirror_Sample_f(&hitPointMat->param.matteMirror, &wo, &wi,
                                                         &fPdf, &f, &shadeN, u0, u1, u2, &specularBounce);
                        f *= surfaceColor;

                        break;

                    case MAT_METAL:
                        engine->ss->Metal_Sample_f(&hitPointMat->param.metal, &wo, &wi, &fPdf, &f,
                                                   &shadeN, u0, u1, &specularBounce);
                        f *= surfaceColor;

                        break;

                    case MAT_MATTEMETAL:
                        engine->ss->MatteMetal_Sample_f(&hitPointMat->param.matteMetal, &wo, &wi,
                                                        &fPdf, &f, &shadeN, u0, u1, u2, &specularBounce);
                        f *= surfaceColor;

                        break;

                    case MAT_ALLOY:
                        engine->ss->Alloy_Sample_f(&hitPointMat->param.alloy, &wo, &wi, &fPdf, &f,
                                                   &shadeN, u0, u1, u2, &specularBounce);
                        f *= surfaceColor;

                        break;

                    case MAT_ARCHGLASS:
                        engine->ss->ArchGlass_Sample_f(&hitPointMat->param.archGlass, &wo, &wi,
                                                       &fPdf, &f, &N, &shadeN, u0, &specularBounce);
                        f *= surfaceColor;

                        break;

                    case MAT_NULL:
                        wi = ray->d;
                        specularBounce = 1;
                        fPdf = 1.f;
                        break;

                    default:
                        // Huston, we have a problem...
                        specularBounce = 1;
                        fPdf = 0.f;
                        break;
                    }

                    if (!specularBounce) // if difuse
                        lookupA->AddFlux(engine->ss, engine->alpha, hitPoint, shadeN, -ray->d,
                                         photonPath->flux, currentPhotonRadius2);

                    if (photonPath->depth < MAX_PHOTON_PATH_DEPTH) {
                        // Build the next vertex path ray
                        if ((fPdf <= 0.f) || f.Black()) {
                            photonPath->done = true;
                        } else {
                            photonPath->depth++;
                            photonPath->flux *= f / fPdf;

                            // Russian Roulette
                            const float p = 0.75f;
                            if (photonPath->depth < 3) {
                                *ray = Ray(hitPoint, wi);
                            } else if (getFloatRNG(seedBuffer[i]) < p) {
                                photonPath->flux /= p;
                                *ray = Ray(hitPoint, wi);
                            } else {
                                photonPath->done = true;
                            }
                        }
                    } else {
                        photonPath->done = true;
                    }
                }
            }
        }

        uint oldc = rayBuffer->GetRayCount();

        rayBuffer->Reset();

        for (unsigned int i = 0; i < oldc; ++i) {

            PhotonPath *photonPath = &livePhotonPaths[i];
            Ray *ray = &rayBuffer->GetRayBuffer()[i];

            if (photonPath->done && todoPhotonCount < photonTarget) {
                todoPhotonCount++;

                Ray n;
                engine->InitPhotonPath(engine->ss, photonPath, &n, seedBuffer[i]);

                livePhotonPaths[i].done = false;

                size_t p = rayBuffer->AddRay(n);
                livePhotonPaths[p] = *photonPath;

            } else if (!photonPath->done) {
                rayBuffer->AddRay(*ray);
            }
        }
    }


//	float MPhotonsSec = todoPhotonCount / ((WallClockTime()-start) * 1000000.f);

    //printf("\nRate: %.3f MPhotons/sec\n",MPhotonsSec);


    profiler->addPhotonTracingTime(WallClockTime() - start);
    profiler->addPhotonsTraced(todoPhotonCount);

    rayBuffer->Reset();

    return todoPhotonCount;
}
示例#2
0
void CPU_Worker::AdvanceEyePaths( RayBuffer *rayBuffer, EyePath* todoEyePaths, uint* eyePathIndexes) {

    const uint max = rayBuffer->GetRayCount();

    omp_set_num_threads(config->max_threads);
    #pragma omp parallel for schedule(guided)
    for (uint i = 0; i < max; i++) {

        EyePath *eyePath = &todoEyePaths[eyePathIndexes[i]];

        const RayHit *rayHit = &rayBuffer->GetHitBuffer()[i];

        if (rayHit->Miss()) {
            // Add an hit point
            //HitPointInfo &hp = *(engine->GetHitPointInfo(eyePath->pixelIndex));
            HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex];

            //HitPoint &hp = GetHitPoint(hitPointsIndex++);
            hp.type = CONSTANT_COLOR;
            hp.scrX = eyePath->scrX;
            hp.scrY = eyePath->scrY;

            //						if (scene->infiniteLight)
            //							hp.throughput = scene->infiniteLight->Le(
            //									eyePath->ray.d) * eyePath->throughput;
            //						else
            //							hp.throughput = Spectrum();

            if (ss->infiniteLight || ss->sunLight || ss->skyLight) {
                //	hp.throughput = scene->infiniteLight->Le(eyePath->ray.d) * eyePath->throughput;

                if (ss->infiniteLight)
                    ss->InfiniteLight_Le(&hp.throughput, &eyePath->ray.d, ss->infiniteLight,
                                         ss->infiniteLightMap);
                if (ss->sunLight)
                    ss->SunLight_Le(&hp.throughput, &eyePath->ray.d, ss->sunLight);
                if (ss->skyLight)
                    ss->SkyLight_Le(&hp.throughput, &eyePath->ray.d, ss->skyLight);

                hp.throughput *= eyePath->throughput;
            } else
                hp.throughput = Spectrum();

            // Free the eye path
            //ihp.accumPhotonCount = 0;
            //ihp.accumReflectedFlux = Spectrum();
            //ihp.photonCount = 0;
            //hp.reflectedFlux = Spectrum();
            eyePath->done = true;

            //--todoEyePathCount;

        } else {

            // Something was hit
            Point hitPoint;
            Spectrum surfaceColor;
            Normal N, shadeN;

            if (engine->GetHitPointInformation(ss, &eyePath->ray, rayHit, hitPoint, surfaceColor,
                                               N, shadeN))
                continue;

            // Get the material
            const unsigned int currentTriangleIndex = rayHit->index;
            const unsigned int currentMeshIndex = ss->meshIDs[currentTriangleIndex];

            const uint materialIndex = ss->meshMats[currentMeshIndex];

            POINTERFREESCENE::Material *hitPointMat = &ss->materials[materialIndex];

            uint matType = hitPointMat->type;

            if (matType == MAT_AREALIGHT) {

                // Add an hit point
                //HitPointInfo &hp = *(engine->GetHitPointInfo(
                //		eyePath->pixelIndex));
                HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex];

                hp.type = CONSTANT_COLOR;
                hp.scrX = eyePath->scrX;
                hp.scrY = eyePath->scrY;
                //ihp.accumPhotonCount = 0;
                //ihp.accumReflectedFlux = Spectrum();
                //ihp.photonCount = 0;
                //hp.reflectedFlux = Spectrum();

                Vector md = -eyePath->ray.d;
                ss->AreaLight_Le(&hitPointMat->param.areaLight, &md, &N,
                                 &hp.throughput);
                hp.throughput *= eyePath->throughput;

                // Free the eye path
                eyePath->done = true;

                //--todoEyePathCount;

            } else {

                Vector wo = -eyePath->ray.d;
                float materialPdf;



                Vector wi;
                bool specularMaterial = true;
                float u0 = getFloatRNG(seedBuffer[eyePath->sampleIndex]);
                float u1 = getFloatRNG(seedBuffer[eyePath->sampleIndex]);
                float u2 = getFloatRNG(seedBuffer[eyePath->sampleIndex]);
                Spectrum f;

                switch (matType) {

                case MAT_MATTE:
                    ss->Matte_Sample_f(&hitPointMat->param.matte, &wo, &wi, &materialPdf, &f,
                                       &shadeN, u0, u1, &specularMaterial);
                    f *= surfaceColor;
                    break;

                case MAT_MIRROR:
                    ss->Mirror_Sample_f(&hitPointMat->param.mirror, &wo, &wi, &materialPdf, &f,
                                        &shadeN, &specularMaterial);
                    f *= surfaceColor;
                    break;

                case MAT_GLASS:
                    ss->Glass_Sample_f(&hitPointMat->param.glass, &wo, &wi, &materialPdf, &f, &N,
                                       &shadeN, u0, &specularMaterial);
                    f *= surfaceColor;

                    break;

                case MAT_MATTEMIRROR:
                    ss->MatteMirror_Sample_f(&hitPointMat->param.matteMirror, &wo, &wi,
                                             &materialPdf, &f, &shadeN, u0, u1, u2, &specularMaterial);
                    f *= surfaceColor;

                    break;

                case MAT_METAL:
                    ss->Metal_Sample_f(&hitPointMat->param.metal, &wo, &wi, &materialPdf, &f,
                                       &shadeN, u0, u1, &specularMaterial);
                    f *= surfaceColor;

                    break;

                case MAT_MATTEMETAL:
                    ss->MatteMetal_Sample_f(&hitPointMat->param.matteMetal, &wo, &wi, &materialPdf,
                                            &f, &shadeN, u0, u1, u2, &specularMaterial);
                    f *= surfaceColor;

                    break;

                case MAT_ALLOY:
                    ss->Alloy_Sample_f(&hitPointMat->param.alloy, &wo, &wi, &materialPdf, &f,
                                       &shadeN, u0, u1, u2, &specularMaterial);
                    f *= surfaceColor;

                    break;

                case MAT_ARCHGLASS:
                    ss->ArchGlass_Sample_f(&hitPointMat->param.archGlass, &wo, &wi, &materialPdf,
                                           &f, &N, &shadeN, u0, &specularMaterial);
                    f *= surfaceColor;

                    break;

                case MAT_NULL:
                    wi = eyePath->ray.d;
                    specularMaterial = 1;
                    materialPdf = 1.f;

                    // I have also to restore the original throughput
                    //throughput = prevThroughput;
                    break;

                default:
                    // Huston, we have a problem...
                    specularMaterial = 1;
                    materialPdf = 0.f;
                    break;

                }

                //						if (f.r != f2.r || f.g != f2.g || f.b != f2.b) {
                //							printf("d");
                //						}

                if ((materialPdf <= 0.f) || f.Black()) {

                    // Add an hit point
                    //HitPointInfo &hp = *(engine->GetHitPointInfo(
                    //		eyePath->pixelIndex));
                    HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex];
                    hp.type = CONSTANT_COLOR;
                    hp.scrX = eyePath->scrX;
                    hp.scrY = eyePath->scrY;
                    hp.throughput = Spectrum();
                    //ihp.accumPhotonCount = 0;
                    //ihp.accumReflectedFlux = Spectrum();
                    //ihp.photonCount = 0;
                    //hp.reflectedFlux = Spectrum();
                    // Free the eye path
                    eyePath->done = true;

                    //--todoEyePathCount;
                } else if (specularMaterial || (!hitPointMat->difuse)) {

                    eyePath->throughput *= f / materialPdf;
                    eyePath->ray = Ray(hitPoint, wi);
                } else {
                    // Add an hit point
                    //HitPointInfo &hp = *(engine->GetHitPointInfo(
                    //		eyePath->pixelIndex));
                    HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex];
                    hp.type = SURFACE;
                    hp.scrX = eyePath->scrX;
                    hp.scrY = eyePath->scrY;
                    //hp.material
                    //		= (SurfaceMaterial *) triMat;
                    //ihp.accumPhotonCount = 0;
                    //ihp.accumReflectedFlux = Spectrum();
                    //ihp.photonCount = 0;
                    //hp.reflectedFlux = Spectrum();
                    hp.materialSS = materialIndex;

                    hp.throughput = eyePath->throughput * surfaceColor;
                    hp.position = hitPoint;
                    hp.wo = -eyePath->ray.d;
                    hp.normal = shadeN;

                    // Free the eye path
                    eyePath->done = true;

                    //--todoEyePathCount;
                }

            }

        }
    }

}
示例#3
0
void Worker::BuildHitPoints(uint /*iteration*/) {

  const unsigned int width = engine->width;
  const unsigned int height = engine->height;
  const unsigned int superSampling = engine->superSampling;

  const unsigned int hitPointTotal = engine->hitPointTotal;

  //Seed* EyePathsSeeds = new Seed[hitPointTotal];

  EyePath* todoEyePaths = new EyePath[hitPointTotal];

  memset(hitPointsStaticInfo_iterationCopy, 0, sizeof(HitPointStaticInfo) * engine->hitPointTotal);

#ifndef USE_SPPM
  memset(hitPoints_iterationCopy, 0, sizeof(HitPoint) * engine->hitPointTotal);
#endif

  unsigned int hitPointsIndex = 0;

  // Generate eye rays
  //std::cerr << "Building eye paths rays with " << superSampling << "x"
  //    << superSampling << " super-sampling:" << std::endl;
  //std::cerr << "  0/" << height << std::endl;

//  double lastPrintTime = WallClockTime();
  const float invSuperSampling = 1.f / superSampling;

  for (unsigned int y = 0; y < height; ++y) {

//    if (WallClockTime() - lastPrintTime > 2.0) {
//      std::cerr << "  " << y << "/" << height << std::endl;
//      lastPrintTime = WallClockTime();
//    }

    //for all hitpoints
    for (unsigned int x = 0; x < width; ++x) {
      for (unsigned int sy = 0; sy < superSampling; ++sy) {
        for (unsigned int sx = 0; sx < superSampling; ++sx) {

          EyePath *eyePath = &todoEyePaths[hitPointsIndex];

          //EyePathsSeeds[hitPointsIndex] = mwc(hitPointsIndex + deviceID);


          eyePath->scrX = x + (sx + getFloatRNG(seedBuffer[hitPointsIndex]))
              * invSuperSampling - 0.5f;

          eyePath->scrY = y + (sy + getFloatRNG(seedBuffer[hitPointsIndex]))
              * invSuperSampling - 0.5f;

          float u0 = getFloatRNG(seedBuffer[hitPointsIndex]);
          float u1 = getFloatRNG(seedBuffer[hitPointsIndex]);
          float u2 = getFloatRNG(seedBuffer[hitPointsIndex]);

          //            scene->camera->GenerateRay(eyePath->scrX,
          //                eyePath->scrY, width, height, &eyePath->ray,
          //                u0, u1, u2);


          ss->GenerateRay(eyePath->scrX, eyePath->scrY, width, height, &eyePath->ray, u0,
              u1, u2, &ss->camera);

          eyePath->depth = 0;
          eyePath->throughput = Spectrum(1.f, 1.f, 1.f);

          eyePath->done = false;
          eyePath->splat = false;
          eyePath->sampleIndex = hitPointsIndex;

          hitPointsIndex++;

        }
      }
    }
  }

  // Iterate through all eye paths
  //std::cerr << "Building eye paths hit points: " << std::endl;
//  lastPrintTime = WallClockTime();
  // Note: (todoEyePaths.size() > 0) is extremly slow to execute


  uint todoEyePathCount = hitPointTotal;
  uint chunk_counter = 0;

  //std::cerr << "  " << todoEyePathCount / 1000 << "k eye paths left"
  //    << std::endl;

  uint* eyePathIndexes = new uint[getRaybufferSize()];

  while (todoEyePathCount > 0) {

//    if (WallClockTime() - lastPrintTime > 2.0) {
//      std::cerr << "  " << todoEyePathCount / 1000 << "k eye paths left" << std::endl;
//      lastPrintTime = WallClockTime();
//    }

    //std::vector<EyePath *>::iterator todoEyePathsIterator =
    //    todoEyePaths.begin() + roundPointer;

    //transversing in chunks
    uint start = (chunk_counter / getRaybufferSize()) * getRaybufferSize();

    uint end;
    if (hitPointTotal - start < getRaybufferSize())
      end = hitPointTotal;
    else
      end = start + getRaybufferSize();

    for (uint i = start; i < end; i++) {

      EyePath *eyePath = &todoEyePaths[i];

      // Check if we reached the max path depth
      if (!eyePath->done && eyePath->depth > MAX_EYE_PATH_DEPTH) {

        // Add an hit point
        //HitPointInfo &hp = *(engine->GetHitPointInfo(
        //    eyePath->pixelIndex));
        HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex];

        hp.type = CONSTANT_COLOR;
        hp.scrX = eyePath->scrX;
        hp.scrY = eyePath->scrY;
        hp.throughput = Spectrum();

        //ihp.accumPhotonCount = 0;
        //ihp.accumReflectedFlux = Spectrum();

        //ihp.photonCount = 0;
        //hp.reflectedFlux = Spectrum();
        eyePath->done = true;

      } else if (!eyePath->done) {
        eyePath->depth++;

        uint p = RaybufferAddRay(eyePath->ray);

        eyePathIndexes[p] = i;
      }

      if (eyePath->done && !eyePath->splat) {
        --todoEyePathCount;
        chunk_counter++;
        eyePath->splat = true;
      }

      //if (rayBuffer->IsFull())
      //  break;

    }

    if (getRayBufferRayCount() > 0) {

      IntersectRayBuffer();

      //printf("%d\n",rayBuffer->GetRayCount());
      AdvanceEyePaths(&todoEyePaths[0], eyePathIndexes);

      resetRayBuffer();
    }
  }

  delete[] todoEyePaths;
  delete[] eyePathIndexes;


}
示例#4
0
void Worker::BuildHitPoints(uint iteration) {

  const unsigned int width = engine->width;
  const unsigned int height = engine->height;
  const unsigned int superSampling = engine->superSampling;

  const unsigned int hitPointTotal = engine->hitPointTotal;

  EyePath* todoEyePaths = new EyePath[hitPointTotal];


#ifndef USE_SPPM
  memset(HPsIterationRadianceFlux, 0, sizeof(HitPointRadianceFlux) * engine->hitPointTotal);
#endif

  unsigned int hitPointsIndex = 0;
  const float invSuperSampling = 1.f / superSampling;

  for (unsigned int y = 0; y < height; ++y) {

    //for all hitpoints
    for (unsigned int x = 0; x < width; ++x) {
      for (unsigned int sy = 0; sy < superSampling; ++sy) {
        for (unsigned int sx = 0; sx < superSampling; ++sx) {

          EyePath *eyePath = &todoEyePaths[hitPointsIndex];

          eyePath->scrX = x + (sx + getFloatRNG(seedBuffer[hitPointsIndex]))
              * invSuperSampling - 0.5f;

          eyePath->scrY = y + (sy + getFloatRNG(seedBuffer[hitPointsIndex]))
              * invSuperSampling - 0.5f;

          float u0 = getFloatRNG(seedBuffer[hitPointsIndex]);
          float u1 = getFloatRNG(seedBuffer[hitPointsIndex]);
          float u2 = getFloatRNG(seedBuffer[hitPointsIndex]);

          ss->GenerateRay(eyePath->scrX, eyePath->scrY, width, height, &eyePath->ray, u0,
              u1, u2, &ss->camera);

          eyePath->depth = 0;
          eyePath->throughput = Spectrum(1.f, 1.f, 1.f);

          eyePath->done = false;
          eyePath->splat = false;
          eyePath->sampleIndex = hitPointsIndex;

          hitPointsIndex++;

        }
      }
    }
  }

  uint todoEyePathCount = hitPointTotal;
  uint chunk_counter = 0;

  uint* eyePathIndexes = new uint[getRaybufferSize()];

  resetRayBuffer();

  while (todoEyePathCount > 0) {

    //transversing in chunks
    uint start = (chunk_counter / getRaybufferSize()) * getRaybufferSize();

    uint end;
    if (hitPointTotal - start < getRaybufferSize())
      end = hitPointTotal;
    else
      end = start + getRaybufferSize();

    for (uint i = start; i < end; i++) {

      EyePath *eyePath = &todoEyePaths[i];

      // Check if we reached the max path depth
      if (!eyePath->done && eyePath->depth > MAX_EYE_PATH_DEPTH) {

        // Add an hit point
        HitPointPositionInfo* hp = GetHitPointInfo(eyePath->sampleIndex);

        hp->type = CONSTANT_COLOR;
        hp->scrX = eyePath->scrX;
        hp->scrY = eyePath->scrY;
        hp->throughput = Spectrum();

        eyePath->done = true;

      } else if (!eyePath->done) {
        eyePath->depth++;

        uint p = RaybufferAddRay(eyePath->ray);

        eyePathIndexes[p] = i;
      }

      if (eyePath->done && !eyePath->splat) {
        --todoEyePathCount;
        chunk_counter++;
        eyePath->splat = true;
      }
    }

    if (getRayBufferRayCount() > 0) {

      IntersectRayBuffer();

      AdvanceEyePaths(&todoEyePaths[0], eyePathIndexes);

      resetRayBuffer();
    }
  }

  delete[] todoEyePaths;
  delete[] eyePathIndexes;

}
示例#5
0
文件: main.cpp 项目: naps62/papi-cuda
void DistrurbeSample(Path *p) {

	p->screenX += getFloatRNG(&p->seed) / 4.f;
	p->screenY += getFloatRNG(&p->seed) / 4.f;

}
示例#6
0
文件: main.cpp 项目: naps62/papi-cuda
bool Shade(Path* path, Geometry *geometry, BVHAccel *bvh, const RayHit& rayHit) {

	uint tracedShadowRayCount;

	if (rayHit.index == 0xffffffffu) {
		return false;
	}

	// Something was hit
	unsigned int currentTriangleIndex = rayHit.index;
	RGB triInterpCol = geometry->triangles[currentTriangleIndex].InterpolateColor(
			geometry->vertColors, rayHit.b1, rayHit.b2);
	Normal shadeN = geometry->triangles[currentTriangleIndex].InterpolateNormal(
			geometry->vertNormals, rayHit.b1, rayHit.b2);

	// Calculate next step
	path->depth++;

	// Check if I have to stop
	if (path->depth >= MAX_PATH_DEPTH) {
		// Too depth, terminate the path
		return false;
	} else if (path->depth > 2) {

		// Russian Rulette, maximize cos
		const float p = min(1.f, triInterpCol.filter() * AbsDot(shadeN, path->pathRay.d));

		if (p > getFloatRNG(&path->seed))
			path->throughput /= p;
		else {
			// Terminate the path
			return false;
		}
	}

	//--------------------------------------------------------------------------
	// Build the shadow ray
	//--------------------------------------------------------------------------

	// Check if it is a light source
	float RdotShadeN = Dot(path->pathRay.d, shadeN);
	if (geometry->IsLight(currentTriangleIndex)) {
		// Check if we are on the right side of the light source
		if ((path->depth == 1) && (RdotShadeN < 0.f))
			path->radiance += triInterpCol * path->throughput;

		// Terminate the path
		return false;
	}

	if (RdotShadeN > 0.f) {
		// Flip shade  normal
		shadeN = -shadeN;
	} else
		RdotShadeN = -RdotShadeN;

	path->throughput *= RdotShadeN * triInterpCol;

	// Trace shadow rays
	const Point hitPoint = path->pathRay(rayHit.t);

	tracedShadowRayCount = 0;
	const float lightStrategyPdf = static_cast<float> (SHADOWRAY)
			/ static_cast<float> (geometry->nLights);

	float lightPdf[SHADOWRAY];
	RGB lightColor[SHADOWRAY];
	Ray shadowRay[SHADOWRAY];

	for (unsigned int i = 0; i < SHADOWRAY; ++i) {
		// Select the light to sample
		const unsigned int currentLightIndex = geometry->SampleLights(getFloatRNG(&path->seed));
		//	const TriangleLight &light = scene->lights[currentLightIndex];

		// Select a point on the surface
		lightColor[tracedShadowRayCount] = Sample_L(currentLightIndex, geometry, hitPoint, shadeN,
				getFloatRNG(&path->seed), getFloatRNG(&path->seed),
				&lightPdf[tracedShadowRayCount], &shadowRay[tracedShadowRayCount]);

		// Scale light pdf for ONE_UNIFORM strategy
		lightPdf[tracedShadowRayCount] *= lightStrategyPdf;

		// Using 0.1 instead of 0.0 to cut down fireflies
		if (lightPdf[tracedShadowRayCount] > 0.1f)
			tracedShadowRayCount++;
	}

	RayHit* rh = new RayHit[tracedShadowRayCount];

	for (unsigned int i = 0; i < tracedShadowRayCount; ++i)
		Intersect(shadowRay[i],  rh[i], bvh->bvhTree, geometry->triangles, geometry->vertices);

	if ((tracedShadowRayCount > 0)) {
		for (unsigned int i = 0; i < tracedShadowRayCount; ++i) {
			const RayHit *shadowRayHit = &rh[i];
			if (shadowRayHit->index == 0xffffffffu) {
				// Nothing was hit, light is visible
				path->radiance += path->throughput * lightColor[i] / lightPdf[i];
			}
		}
	}

	//--------------------------------------------------------------------------
	// Build the next vertex path ray
	//--------------------------------------------------------------------------

	// Calculate exit direction

	float r1 = 2.f * M_PI * getFloatRNG(&path->seed);
	float r2 = getFloatRNG(&path->seed);
	float r2s = sqrt(r2);
	const Vector w(shadeN);

	Vector u;
	if (fabsf(shadeN.x) > .1f) {
		const Vector a(0.f, 1.f, 0.f);
		u = Cross(a, w);
	} else {
		const Vector a(1.f, 0.f, 0.f);
		u = Cross(a, w);
	}
	u = Normalize(u);

	Vector v = Cross(w, u);

	Vector newDir = u * (cosf(r1) * r2s) + v * (sinf(r1) * r2s) + w * sqrtf(1.f - r2);
	newDir = Normalize(newDir);

	path->pathRay.o = hitPoint;
	path->pathRay.d = newDir;

	return true;
}