void fresnel(const Vec3f &incidentDirection, const Vec3f &normal, const float &refractiveIndex, float &kr) { float cosI = clamp(-1, 1, incidentDirection.dotProduct(normal)); float etaI = 1, etaT = refractiveIndex; if (cosI > 0) { std::swap(etaI, etaT); } float sinT = etaI / etaT * sqrtf(std::max(0.f, 1 - cosI * cosI)); if (sinT >= 1) { kr = 1; } else { float cosT = sqrtf(std::max(0.f, 1 - sinT * sinT)); cosI = fabsf(cosI); float Rs = ((etaT * cosI) - (etaI * cosT)) / ((etaT * cosI) + (etaI * cosT)); float Rp = ((etaI * cosI) - (etaT * cosT)) / ((etaI * cosI) + (etaT * cosT)); kr = (Rs * Rs + Rp * Rp) / 2; } }
// Compute the color at the intersection point if any (returns background color otherwise) Vec3f castRay( const Vec3f &orig, const Vec3f &dir, const std::vector<std::unique_ptr<Object>> &objects) { Vec3f hitColor = 0; const Object *hitObject = nullptr; float t; if (trace(orig, dir, objects, t, hitObject)) { Vec3f Phit = orig + dir * t; Vec3f Nhit; Vec2f tex; hitObject->getSurfaceData(Phit, Nhit, tex); // Use the normal and texture coordinates for shading float scale = 5; float pattern = (float)((fmodf(tex.x * scale, 1.0f) > 0.5f) ^ (fmodf(tex.y * scale, 1.0f) > 0.5f)); hitColor = max(0.f, Nhit.dotProduct(-dir)) * mix(hitObject->color, hitObject->color * 0.8f, pattern); } return hitColor; }
bool refract(const Vec3f &incidentDirection, const Vec3f &normal, float refractiveIndex, Vec3f &refractionDirection) { float cosI = incidentDirection.dotProduct(normal); float eta, etaT = refractiveIndex, etaI = 1.0; Vec3f refractionNormal = normal; if(cosI < 0) { cosI *= -1; } else { refractionNormal *= -1; std::swap(etaT, etaI); } eta = etaI / etaT; double k = 1 - eta * eta * (1 - cosI * cosI); if(k < 0) { return false; } else { refractionDirection = eta * incidentDirection + (eta * cosI - sqrtf(k)) * refractionNormal; return true; } }
// [comment] // The main ray-triangle intersection routine. You can test both methoods: the // geometric method and the Moller-Trumbore algorithm (use the flag -DMOLLER_TRUMBORE // when you compile. // [/comment] bool rayTriangleIntersect( const Vec3f &orig, const Vec3f &dir, const Vec3f &v0, const Vec3f &v1, const Vec3f &v2, float &t, float &u, float &v) { #ifdef MOLLER_TRUMBORE Vec3f v0v1 = v1 - v0; Vec3f v0v2 = v2 - v0; Vec3f pvec = dir.crossProduct(v0v2); float det = v0v1.dotProduct(pvec); #ifdef CULLING // if the determinant is negative the triangle is backfacing // if the determinant is close to 0, the ray misses the triangle if (det < kEpsilon) return false; #else // ray and triangle are parallel if det is close to 0 if (fabs(det) < kEpsilon) return false; #endif float invDet = 1 / det; Vec3f tvec = orig - v0; u = tvec.dotProduct(pvec) * invDet; if (u < 0 || u > 1) return false; Vec3f qvec = tvec.crossProduct(v0v1); v = dir.dotProduct(qvec) * invDet; if (v < 0 || u + v > 1) return false; t = v0v2.dotProduct(qvec) * invDet; return true; #else // compute plane's normal Vec3f v0v1 = v1 - v0; Vec3f v0v2 = v2 - v0; // no need to normalize Vec3f N = v0v1.crossProduct(v0v2); // N float denom = N.dotProduct(N); // Step 1: finding P // check if ray and plane are parallel ? float NdotRayDirection = N.dotProduct(dir); if (fabs(NdotRayDirection) < kEpsilon) // almost 0 return false; // they are parallel so they don't intersect ! // compute d parameter using equation 2 float d = N.dotProduct(v0); // compute t (equation 3) t = (N.dotProduct(orig) + d) / NdotRayDirection; // check if the triangle is in behind the ray if (t < 0) return false; // the triangle is behind // compute the intersection point using equation 1 Vec3f P = orig + t * dir; // Step 2: inside-outside test Vec3f C; // vector perpendicular to triangle's plane // edge 0 Vec3f edge0 = v1 - v0; Vec3f vp0 = P - v0; C = edge0.crossProduct(vp0); if (N.dotProduct(C) < 0) return false; // P is on the right side // edge 1 Vec3f edge1 = v2 - v1; Vec3f vp1 = P - v1; C = edge1.crossProduct(vp1); if ((u = N.dotProduct(C)) < 0) return false; // P is on the right side // edge 2 Vec3f edge2 = v0 - v2; Vec3f vp2 = P - v2; C = edge2.crossProduct(vp2); if ((v = N.dotProduct(C)) < 0) return false; // P is on the right side; u /= denom; v /= denom; return true; // this ray hits the triangle #endif }
Vec3f reflect(const Vec3f &incidentDirection, const Vec3f &normal) { return incidentDirection - 2 * incidentDirection.dotProduct(normal) * normal; }