Colord PerfectSpecular::sample(const HitPoint& hitPoint, const Vector3d& out, Vector3d& in) const {
  double normalDotOut = hitPoint.normal() * out;
  in = -out + hitPoint.normal() * 2.0 * normalDotOut;

  double normalDotIn = hitPoint.normal() * out;
  return reflectionColor() * reflectionCoefficient() / normalDotIn;
}
Exemple #2
0
Colord PhongMaterial::shade(const Raytracer* raytracer, const Rayd& ray, const HitPoint& hitPoint, State& state) const {
  auto texColor = diffuseTexture() ? diffuseTexture()->evaluate(ray, hitPoint) : Colord::black();

  Lambertian ambientBRDF(texColor, ambientCoefficient());
  Lambertian diffuseBRDF(texColor, diffuseCoefficient());

  Vector3d out = -ray.direction();
  auto color = ambientBRDF.reflectance(hitPoint, out) * raytracer->scene()->ambient();

  for (const auto& light : raytracer->scene()->lights()) {
    Vector3d in = light->direction(hitPoint.point());

    if (raytracer->scene()->intersects(Rayd(hitPoint.point(), in).epsilonShifted(), state)) {
      state.shadowHit(this, "PhongMaterial");
    } else {
      state.shadowMiss(this, "PhongMaterial");
      double normalDotIn = hitPoint.normal() * in;
      if (normalDotIn > 0.0) {
        color += (
          diffuseBRDF(hitPoint, out, in)
        + m_specularBRDF(hitPoint, out, in)
        ) * light->radiance() * normalDotIn;
      }
    }
  }

  return color;
}
void HitPoints::AccumulateFlux(scheduling::Range *range) {
	for(unsigned i = range->begin(); i != range->end(); i = range->next()) {
		HitPoint *hp = &(*hitPoints)[i];

		hp->DoRadiusReduction(renderer->sppmi->photonAlpha, GetPassCount(), renderer->sppmi->useproba);
	}
}
void HitPoints::Init() {
	// Not using UpdateBBox() because hp->accumPhotonRadius2 is not yet set
	BBox hpBBox = BBox();
	for (u_int i = 0; i < (*hitPoints).size(); ++i) {
		HitPoint *hp = &(*hitPoints)[i];

		if (hp->IsSurface())
			hpBBox = Union(hpBBox, hp->GetPosition());
	}

	// Calculate initial radius
	Vector ssize = hpBBox.pMax - hpBBox.pMin;
	initialPhotonRadius = renderer->sppmi->photonStartRadiusScale *
		((ssize.x + ssize.y + ssize.z) / 3.f) / sqrtf(nSamplePerPass) * 2.f;
	const float photonRadius2 = initialPhotonRadius * initialPhotonRadius;

	// Expand the bounding box by used radius
	hpBBox.Expand(initialPhotonRadius);
	// Update hit points information
	hitPointBBox = hpBBox;
	maxHitPointRadius2 = photonRadius2;

	LOG(LUX_DEBUG, LUX_NOERROR) << "Hit points bounding box: " << hitPointBBox;
	LOG(LUX_DEBUG, LUX_NOERROR) << "Hit points max. radius: " << sqrtf(maxHitPointRadius2);

	// Initialize hit points field
	for (u_int i = 0; i < (*hitPoints).size(); ++i) {
		HitPoint *hp = &(*hitPoints)[i];

		hp->accumPhotonRadius2 = photonRadius2;
	}

	// Allocate hit points lookup accelerator
	switch (renderer->sppmi->lookupAccelType) {
		case HASH_GRID:
			lookUpAccel = new HashGrid(this);
			break;
		case KD_TREE:
			lookUpAccel = new KdTree(this);
			break;
		case HYBRID_HASH_GRID:
			lookUpAccel = new HybridHashGrid(this);
			break;
		case PARALLEL_HASH_GRID:
			lookUpAccel = new ParallelHashGrid(this, renderer->sppmi->parallelHashGridSpare);
			break;
		default:
			assert (false);
	}
}
Exemple #5
0
const Primitive* ConvexOperation::intersect(const Rayd& ray, HitPointInterval& hitPoints, State& state) const {
  if (!boundingBoxIntersects(ray)) {
    state.miss("ConvexOperation, bounding box miss");
    return nullptr;
  }
  
  // unlike the intersection methods for box, sphere, etc, convexIntersect()
  // only returns a single (closest) hitpoint. So we need to shoot a ray in the
  // opposite direction as well.
  
  // calculate hitpoint in ray direction
  if (convexIntersect(ray, hitPoints)) {
    // if it's a hit, do it again in the opposite direction
    HitPointInterval opposite;
    // If we double the hit distance and take the longest possible length in
    // the bounding box, we should be beyond the other side of the object
    Rayd oppositeRay(
      ray.at(hitPoints.min().distance() * 2.0 + boundingBox().size().length()),
      -ray.direction()
    );
    
    // fire!
    convexIntersect(oppositeRay, opposite);
    HitPoint oppositePoint = opposite.min();
    // now, we have to project that point on the opposite side back to the
    // original ray to find the real distance value
    oppositePoint.setDistance(ray.projectedDistance(oppositePoint.point()));
    
    // add it to the interval
    hitPoints.add(oppositePoint);
    // and merge both points into a single interval. we can do that, since this
    // is by definition a convex object, so there can be only a single interval
    hitPoints = hitPoints.merged();
    
    auto hitPoint = hitPoints.minWithPositiveDistance();
    if (hitPoint.isUndefined()) {
      return nullptr;
      state.miss("ConvexOperation, ray miss");
    } else {
      state.hit("ConvexOperation");

      hitPoints.setPrimitive(this);
      return this;
    }
  }
  state.miss("ConvexOperation, ray miss");
  return nullptr;
}
const double HitPoints::GetPhotonHitEfficency() {
	u_int surfaceHitPointsCount = 0;
	u_int hitPointsUpdatedCount = 0;
	for (u_int i = 0; i < GetSize(); ++i) {
		HitPoint *hp = &(*hitPoints)[i];

		if (hp->IsSurface()) {
			++surfaceHitPointsCount;

			if (hp->GetPhotonCount() > 0)
				++hitPointsUpdatedCount;
		}
	}

	return 100.0 * hitPointsUpdatedCount / surfaceHitPointsCount;
}
Exemple #7
0
void MixMaterial::Pdf(const HitPoint &hitPoint,
		const Vector &localLightDir, const Vector &localEyeDir,
		float *directPdfW, float *reversePdfW) const {
	const Frame frame(hitPoint.GetFrame());
	const float weight2 = Clamp(mixFactor->GetFloatValue(hitPoint), 0.f, 1.f);
	const float weight1 = 1.f - weight2;

	float directPdfWMatA = 1.f;
	float reversePdfWMatA = 1.f;
	if (weight1 > 0.f) {
		HitPoint hitPointA(hitPoint);
		matA->Bump(&hitPointA);
		const Frame frameA(hitPointA.GetFrame());
		const Vector lightDirA = frameA.ToLocal(frame.ToWorld(localLightDir));
		const Vector eyeDirA = frameA.ToLocal(frame.ToWorld(localEyeDir));
		matA->Pdf(hitPointA, lightDirA, eyeDirA, &directPdfWMatA, &reversePdfWMatA);
	}

	float directPdfWMatB = 1.f;
	float reversePdfWMatB = 1.f;
	if (weight2 > 0.f) {
		HitPoint hitPointB(hitPoint);
		matB->Bump(&hitPointB);
		const Frame frameB(hitPointB.GetFrame());
		const Vector lightDirB = frameB.ToLocal(frame.ToWorld(localLightDir));
		const Vector eyeDirB = frameB.ToLocal(frame.ToWorld(localEyeDir));
		matB->Pdf(hitPointB, lightDirB, eyeDirB, &directPdfWMatB, &reversePdfWMatB);
	}

	if (directPdfW)
		*directPdfW = weight1 * directPdfWMatA + weight2 *directPdfWMatB;
	if (reversePdfW)
		*reversePdfW = weight1 * reversePdfWMatA + weight2 * reversePdfWMatB;
}
Exemple #8
0
Spectrum MixMaterial::Sample(const HitPoint &hitPoint,
	const Vector &localFixedDir, Vector *localSampledDir,
	const float u0, const float u1, const float passThroughEvent,
	float *pdfW, float *absCosSampledDir, BSDFEvent *event,
	const BSDFEvent requestedEvent) const {
	const Frame frame(hitPoint.GetFrame());
	HitPoint hitPointA(hitPoint);
	matA->Bump(&hitPointA);
	const Frame frameA(hitPointA.GetFrame());
	const Vector fixedDirA = frameA.ToLocal(frame.ToWorld(localFixedDir));
	HitPoint hitPointB(hitPoint);
	matB->Bump(&hitPointB);
	const Frame frameB(hitPointB.GetFrame());
	const Vector fixedDirB = frameB.ToLocal(frame.ToWorld(localFixedDir));

	const float weight2 = Clamp(mixFactor->GetFloatValue(hitPoint), 0.f, 1.f);
	const float weight1 = 1.f - weight2;

	const bool sampleMatA = (passThroughEvent < weight1);

	const float weightFirst = sampleMatA ? weight1 : weight2;
	const float weightSecond = sampleMatA ? weight2 : weight1;

	const float passThroughEventFirst = sampleMatA ? (passThroughEvent / weight1) : (passThroughEvent - weight1) / weight2;

	// Sample the first material, evaluate the second
	const Material *matFirst = sampleMatA ? matA : matB;
	const Material *matSecond = sampleMatA ? matB : matA;

	HitPoint &hitPoint1 = sampleMatA ? hitPointA : hitPointB;
	HitPoint &hitPoint2 = sampleMatA ? hitPointB : hitPointA;
	const Frame &frame1 = sampleMatA ? frameA : frameB;
	const Frame &frame2 = sampleMatA ? frameB : frameA;
	const Vector &fixedDir1 = sampleMatA ? fixedDirA : fixedDirB;
	const Vector &fixedDir2 = sampleMatA ? fixedDirB : fixedDirA;

	// Sample the first material
	Spectrum result = matFirst->Sample(hitPoint1, fixedDir1, localSampledDir,
			u0, u1, passThroughEventFirst, pdfW, absCosSampledDir, event, requestedEvent);
	if (result.Black())
		return Spectrum();
	*localSampledDir = frame1.ToWorld(*localSampledDir);
	const Vector sampledDir2 = frame2.ToLocal(*localSampledDir);
	*localSampledDir = frame.ToLocal(*localSampledDir);
	*pdfW *= weightFirst;
	result *= *pdfW;

	// Evaluate the second material
	const Vector &localLightDir = (hitPoint2.fromLight) ? fixedDir2 : sampledDir2;
	const Vector &localEyeDir = (hitPoint2.fromLight) ? sampledDir2 : fixedDir2;
	BSDFEvent eventSecond;
	float pdfWSecond;
	Spectrum evalSecond = matSecond->Evaluate(hitPoint2, localLightDir, localEyeDir, &eventSecond, &pdfWSecond);
	if (!evalSecond.Black()) {
		result += weightSecond * evalSecond;
		*pdfW += weightSecond * pdfWSecond;
	}

	return result / *pdfW;
}
HitPoints::HitPoints(SPPMRenderer *engine, RandomGenerator *rng)  {
	renderer = engine;
	Scene *scene = renderer->scene;
	currentPass = 0;

	wavelengthSampleScramble = rng->uintValue();
	timeSampleScramble = rng->uintValue();
	wavelengthStratPasses = RoundUpPow2(renderer->sppmi->wavelengthStratification);
	if (wavelengthStratPasses > 0) {
		LOG(LUX_DEBUG, LUX_NOERROR) << "Non-random wavelength stratification for " << wavelengthStratPasses << " passes";
		wavelengthSample = 0.5f; // non-randomly stratified in IncPass for first N passes
	} else
		wavelengthSample = Halton(0, wavelengthSampleScramble);
	timeSample = Halton(0, timeSampleScramble);

	// Get the count of hit points required
	int xstart, xend, ystart, yend;
	scene->camera()->film->GetSampleExtent(&xstart, &xend, &ystart, &yend);

	// Set the sampler
	eyeSampler = new HaltonEyeSampler(xstart, xend, ystart, yend,
		renderer->sppmi->PixelSampler, renderer->sppmi->hitpointPerPass);

	// the eyeSampler may decide that it allocates less or more hitpointPerPass
	renderer->sppmi->hitpointPerPass = eyeSampler->GetTotalSamplePos();
	nSamplePerPass = renderer->sppmi->hitpointPerPass;

	hitPoints = new std::vector<HitPoint>(nSamplePerPass);
	LOG(LUX_DEBUG, LUX_NOERROR) << "Hit points count: " << hitPoints->size();

	// Initialize hit points field
	for (u_int i = 0; i < (*hitPoints).size(); ++i) {
		HitPoint *hp = &(*hitPoints)[i];

		hp->InitStats();
	}

	store_component = BxDFType(BSDF_DIFFUSE | BSDF_REFLECTION | BSDF_TRANSMISSION);
	bounce_component = BxDFType(BSDF_SPECULAR | BSDF_REFLECTION | BSDF_TRANSMISSION);

	if(engine->sppmi->storeGlossy)
		store_component = BxDFType(store_component | BSDF_GLOSSY);
	else
		bounce_component = BxDFType(bounce_component | BSDF_GLOSSY);
}
Exemple #10
0
Spectrum MixMaterial::Evaluate(const HitPoint &hitPoint,
	const Vector &localLightDir, const Vector &localEyeDir, BSDFEvent *event,
	float *directPdfW, float *reversePdfW) const {
	const Frame frame(hitPoint.GetFrame());
	Spectrum result;

	const float weight2 = Clamp(mixFactor->GetFloatValue(hitPoint), 0.f, 1.f);
	const float weight1 = 1.f - weight2;

	if (directPdfW)
		*directPdfW = 0.f;
	if (reversePdfW)
		*reversePdfW = 0.f;

	BSDFEvent eventMatA = NONE;
	if (weight1 > 0.f) {
		HitPoint hitPointA(hitPoint);
		matA->Bump(&hitPointA);
		const Frame frameA(hitPointA.GetFrame());
		const Vector lightDirA = frameA.ToLocal(frame.ToWorld(localLightDir));
		const Vector eyeDirA = frameA.ToLocal(frame.ToWorld(localEyeDir));
		float directPdfWMatA, reversePdfWMatA;
		const Spectrum matAResult = matA->Evaluate(hitPointA, lightDirA, eyeDirA, &eventMatA, &directPdfWMatA, &reversePdfWMatA);
		if (!matAResult.Black()) {
			result += weight1 * matAResult;

			if (directPdfW)
				*directPdfW += weight1 * directPdfWMatA;
			if (reversePdfW)
				*reversePdfW += weight1 * reversePdfWMatA;
		}
	}

	BSDFEvent eventMatB = NONE;
	if (weight2 > 0.f) {
		HitPoint hitPointB(hitPoint);
		matB->Bump(&hitPointB);
		const Frame frameB(hitPointB.GetFrame());
		const Vector lightDirB = frameB.ToLocal(frame.ToWorld(localLightDir));
		const Vector eyeDirB = frameB.ToLocal(frame.ToWorld(localEyeDir));
		float directPdfWMatB, reversePdfWMatB;
		const Spectrum matBResult = matB->Evaluate(hitPointB, lightDirB, eyeDirB, &eventMatB, &directPdfWMatB, &reversePdfWMatB);
		if (!matBResult.Black()) {
			result += weight2 * matBResult;

			if (directPdfW)
				*directPdfW += weight2 * directPdfWMatB;
			if (reversePdfW)
				*reversePdfW += weight2 * reversePdfWMatB;
		}
	}

	*event = eventMatA | eventMatB;

	return result;
}
Exemple #11
0
bool RayTracer::calculateHitpoint()
{
	HitPoint hp;
	double lastdist = 999999999;
	bool hitted = false;

	//get closest ray target
	std::vector<GameObject*> * gameObjects = Scene::getInstance()->getGameObjects();
	for (std::vector<GameObject*>::iterator it = gameObjects->begin(); it != gameObjects->end(); it++) {
		if ((*it)->rayCast(ray, hp)) {
			//save closest hitpoint
			double dist = (ray.getPoint() - hp.getPoint()).magnitude();
			//double dir = (hp.getPoint() - ray.getPoint()).dot(ray.getDirection()); && dir > 0
			if (dist < lastdist) {
				hitpoint = hp;
				hittingObject = (*it);
				lastdist = dist;
				hitted = true;
			}
		}
	}

	return hitted;
}
Exemple #12
0
Colord TransparentMaterial::shade(const Raytracer* raytracer, const Rayd& ray, const HitPoint& hitPoint, State& state) const {
  Vector3d out = -ray.direction();
  Vector3d in;
  Colord reflectedColor = m_reflectiveBRDF.sample(hitPoint, out, in);
  Rayd reflected(hitPoint.point(), in);
  
  if (m_specularBTDF.totalInternalReflection(ray, hitPoint)) {
    return raytracer->rayColor(reflected.epsilonShifted(), state);
  } else {
    auto color = PhongMaterial::shade(raytracer, ray, hitPoint, state);
    
    Vector3d trans;
    Colord transmittedColor = m_specularBTDF.sample(hitPoint, out, trans);
    Rayd transmitted(hitPoint.point(), trans);
    
    state.recordEvent("TransparentMaterial: Tracing reflection");
    color += reflectedColor * raytracer->rayColor(reflected.epsilonShifted(), state) * fabs(hitPoint.normal() * in);
    
    state.recordEvent("TransparentMaterial: Tracing transmission");
    color += transmittedColor * raytracer->rayColor(transmitted.epsilonShifted(), state) * fabs(hitPoint.normal() * trans);
    
    return color;
  }
}
void HitPoints::UpdatePointsInformation() {
	// Calculate hit points bounding box
	BBox bbox;
	float maxr2, minr2, meanr2;
	u_int minp, maxp, meanp;
	u_int surfaceHits, constantHits, zeroHits;

	assert((*hitPoints).size() > 0);
	HitPoint *hp = &(*hitPoints)[0];

	if (hp->IsSurface()) {
		surfaceHits = 1;
		constantHits = 0;
		u_int pc = hp->GetPhotonCount();
		zeroHits = pc == 0 ? 1 : 0;
		bbox = hp->GetPosition();
		maxr2 = minr2 = meanr2 = hp->accumPhotonRadius2;
		minp = maxp = meanp = pc;
	} else {
		constantHits = 1;
		surfaceHits = 0;
		zeroHits = 0;
		maxr2 = 0.f;
		minr2 = INFINITY;
		meanr2 = 0.f;
		minp = maxp = meanp = 0;
	}

	for (u_int i = 1; i < (*hitPoints).size(); ++i) {
		hp = &(*hitPoints)[i];

		if (hp->IsSurface()) {
			u_int pc = hp->GetPhotonCount();
			if(pc == 0)
				++zeroHits;

			bbox = Union(bbox, hp->GetPosition());

			maxr2 = max<float>(maxr2, hp->accumPhotonRadius2);
			minr2 = min<float>(minr2, hp->accumPhotonRadius2);
			meanr2 += hp->accumPhotonRadius2;


			maxp = max<float>(maxp, pc);
			minp = min<float>(minp, pc);
			meanp += pc;

			++surfaceHits;
		}
		else
			++constantHits;
	}

	LOG(LUX_DEBUG, LUX_NOERROR) << "Hit points stats:";
	if (surfaceHits > 0) {
		LOG(LUX_DEBUG, LUX_NOERROR) << "\tbounding box: " << bbox;
		LOG(LUX_DEBUG, LUX_NOERROR) << "\tmin/max radius: " << sqrtf(minr2) << "/" << sqrtf(maxr2);
		LOG(LUX_DEBUG, LUX_NOERROR) << "\tmin/max photonCount: " << minp << "/" << maxp;
		LOG(LUX_DEBUG, LUX_NOERROR) << "\tmean radius/photonCount: " << sqrtf(meanr2 / surfaceHits) << "/" << meanp / surfaceHits;
	}
	LOG(LUX_DEBUG, LUX_NOERROR) << "\tconstant/zero hits: " << constantHits << "/" << zeroHits;

	hitPointBBox = bbox;
	maxHitPointRadius2 = maxr2;
}