bool BoundingBox::RayIntersects(const Ray& ray, float tMin, float tMax) const { Vector3f dirFrac = ray.GetDir().Reciprocal(); Vector3f minD = (Min - ray.GetPos()) * dirFrac, maxD = (Max - ray.GetPos()) * dirFrac; float _tMin = max(max(min(minD.x, maxD.x), min(minD.y, maxD.y)), min(minD.z, maxD.z)), _tMax = min(min(max(minD.x, maxD.x), max(minD.y, maxD.y)), max(minD.z, maxD.z)); return (_tMin >= tMin && _tMin <= tMax) || (_tMax >= tMin && _tMax <= tMax); }
bool Material_Dielectric::Scatter(const Ray& rIn, const Vertex& surface, const Shape& shpe, FastRand& prng, Vector3f& attenuation, Vector3f& emission, Ray& rOut) const { float indexOfRefraction = (float)IndexOfRefraction->GetValue(rIn, prng, &shpe, &surface); float ratioOfIndices; Vector3f outwardNormal; float cosAngle; if (surface.Normal.Dot(rIn.GetDir()) > 0.0f) { ratioOfIndices = indexOfRefraction; outwardNormal = -surface.Normal; cosAngle = indexOfRefraction * rIn.GetDir().Dot(surface.Normal) / rIn.GetDir().Length(); } else { ratioOfIndices = 1.0f / indexOfRefraction; outwardNormal = surface.Normal; cosAngle = -rIn.GetDir().Dot(surface.Normal) / rIn.GetDir().Length(); } //Try refracting. Possibly reflect instead. float reflectionChance; Vector3f refracted; if (rIn.GetDir().Refract(outwardNormal, ratioOfIndices, refracted)) { //Approximation of chance of refraction by Christophe Schlick: float r0 = (1.0f - indexOfRefraction) / (1.0f + indexOfRefraction); r0 *= r0; reflectionChance = r0 + ((1.0f - r0) * std::powf((1.0f - cosAngle), 5.0f)); } else { reflectionChance = 1.01f; } if (prng.NextFloat() < reflectionChance) rOut = Ray(surface.Pos, rIn.GetDir().Reflect(surface.Normal)); else rOut = Ray(surface.Pos, refracted); //Move the ray forward a tiny bit to get off the surface. rOut.SetPos(rOut.GetPos() + (rOut.GetDir() * PushoffDist)); attenuation = Vector3f(1.0f, 1.0f, 1.0f); return true; }
bool Mesh::CastRay(const Ray& ray, Vertex& outHit, FastRand& prng, float tMin, float tMax) const { //TODO: Try not bothering to normalize the local ray's direction. Ray newRay(Tr.Point_WorldToLocal(ray.GetPos()), Tr.Dir_WorldToLocal(ray.GetDir()).Normalize()); if (!bounds.RayIntersects(newRay, tMin, tMax)) return false; const Triangle* closest = nullptr; float hitDist = std::numeric_limits<float>().infinity(); for (size_t i = 0; i < Tris.GetSize(); ++i) { float tempT; Vector3f tempPos; if (Tris[i].RayIntersect(newRay, tempPos, tempT, tMin, tMax)) { if (tempT < hitDist) { hitDist = tempT; outHit.Pos = tempPos; closest = &Tris[i]; } } } if (closest != nullptr) { closest->GetMoreData(outHit, Tr); return true; } return false; }