RayIntersection Sphere::intersectWithRay(const Ray &ray) const { // Solve square equation x^2 + b * x + c = 0 Vector cameraToRayOrigin = ray.getOriginPosition() - mCenter; float b = ray.getDirection().dotProduct(cameraToRayOrigin); float c = cameraToRayOrigin.dotProduct(cameraToRayOrigin) - mRadius * mRadius; float descriminant = b * b - c; if (descriminant < 0) { return RayIntersection(); } descriminant = sqrt(descriminant); std::vector<float> intersectionDistances; float closestRoot = -1.f; // Get closest root float root = -b - descriminant; float rayExit = -1.f; if (root >= 0.f) { closestRoot = root; intersectionDistances.push_back(root); } root = -b + descriminant; if (root >= 0.f) { intersectionDistances.push_back(root); if (closestRoot < 0.f) { closestRoot = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } if (closestRoot > 0.f) { if (rayExit < 0.f) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } SpherePointer pointer = SpherePointer(new Sphere(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); }
Color PointLight::calculateColor(const Scene &scene, const Ray &ray, float distance, const Vector &normal, MaterialPointer material) const { Vector point = ray.getPointAt(distance); Color ambientComponent; Color diffuseComponent; Color specularComponent; ambientComponent = componentwiseProduct(material->ambientColor, mAmbientIntensity); Color result = ambientComponent; Vector shadowRayDirection = mPosition - point; float distanceToLight = shadowRayDirection.length(); float attenuation = 1 / (mConstantAttenutaionCoefficient + mLinearAttenutaionCoefficient * distanceToLight + mQuadraticAttenutaionCoefficient * distanceToLight * distanceToLight); result *= attenuation; shadowRayDirection.normalize(); float shadowRayDotNormal = shadowRayDirection.dotProduct(normal); // If the point is not illuminated if (shadowRayDotNormal <= 0.0) { return result; } Ray shadowRay(point + shadowRayDirection * EPS_FOR_SHADOW_RAYS, shadowRayDirection); RayIntersection shadowRayIntersection = scene.calculateNearestIntersection(shadowRay); // If object is not in shadow if (!shadowRayIntersection.rayIntersectsWithShape || shadowRayIntersection.distanceFromRayOrigin > distanceToLight) { Color diffuseColor = material->diffuseColor; diffuseComponent = componentwiseProduct(diffuseColor, mDiffuseIntensity * attenuation * shadowRayDotNormal); Vector lightReflect = shadowRayDirection - normal * 2 * shadowRayDirection.dotProduct(normal); lightReflect.normalize(); Vector cameraDirection = ray.getOriginPosition() - point; cameraDirection.normalize(); float cosLightReflect = cameraDirection.dotProduct(lightReflect); if (cosLightReflect > 0.0) { Color specularColor = material->specularColor; specularComponent = componentwiseProduct(specularColor, mSpecularIntensity * powf(cosLightReflect, material->specularPower) * attenuation); } } result += (diffuseComponent + specularComponent); return result; }
RayIntersection Plane::intersectWithRay(const Ray &ray) const { float cosineRayNormal = mNormal.dotProduct(ray.getDirection()); if (fabs(cosineRayNormal) < FLOAT_ZERO) { return RayIntersection(); } float distance = -(ray.getOriginPosition().dotProduct(mNormal) + mDistance) / cosineRayNormal; if (distance > 0.0) { PlanePointer pointer = PlanePointer(new Plane(*this)); std::vector<float> intersectionDistances; intersectionDistances.push_back(distance); return RayIntersection(true, pointer, distance, getNormal(ray, distance), intersectionDistances); } return RayIntersection(); }
RayIntersection TrianglePatch::intersectWithRay(const Ray &ray) const { Vector rayOrigin = ray.getOriginPosition(); Vector rayDirection = ray.getDirection(); Vector e1 = mVertex1->getCoordinates() - mVertex0->getCoordinates(); Vector e2 = mVertex2->getCoordinates() - mVertex0->getCoordinates(); Vector pvector = rayDirection.crossProduct(e2); float determinant = e1.dotProduct(pvector); if (fabs(determinant) < FLOAT_ZERO) { return RayIntersection(); } const float invertedDeterminant = 1.0f / determinant; Vector tvec = rayOrigin - mVertex0->getCoordinates(); float lambda = tvec.dotProduct(pvector); lambda *= invertedDeterminant; if (lambda < 0.0f || lambda > 1.0f) { return RayIntersection(); } Vector qvec = tvec.crossProduct(e1); float mue = rayDirection.dotProduct(qvec); mue *= invertedDeterminant; if (mue < 0.0f || mue + lambda > 1.0f) { return RayIntersection(); } float f = e2.dotProduct(qvec); f = f * invertedDeterminant - FLOAT_ZERO; if (f < FLOAT_ZERO) { return RayIntersection(); } TrianglePatchPointer pointer = TrianglePatchPointer(new TrianglePatch(*this)); return RayIntersection(true, pointer, f, lambda, mue); }
RayIntersection Cone::intersectWithRay(const Ray &ray) const { Vector coneAxis = (mBottomCenter - mTop); coneAxis.normalize(); Vector rayOriginPosition = ray.getOriginPosition(); Vector rayDirection = ray.getDirection(); Vector bottomCenterToRayOrigin = rayOriginPosition - mTop; float rayDirectionDotAxis = rayDirection.dotProduct(coneAxis); float bottomCenterToRayOriginDotAxis = bottomCenterToRayOrigin.dotProduct(coneAxis); float radiansPerHeight = mRadius / (mBottomCenter - mTop).length(); Vector u = rayDirection + coneAxis * (-rayDirectionDotAxis); Vector v = bottomCenterToRayOrigin + coneAxis * (-bottomCenterToRayOriginDotAxis); float w = bottomCenterToRayOriginDotAxis * radiansPerHeight; float radiansPerDirection = rayDirectionDotAxis * radiansPerHeight; // Solve square equation a * x^2 + b * x + c = 0 float a = u.dotProduct(u) - radiansPerDirection * radiansPerDirection; float closestRoot = -1.f; float rayExit = -1.f; float root = 0.f; std::vector<float> intersectionDistances; if (fabs(a) > FLOAT_ZERO) { float b = 2 * (u.dotProduct(v) - w * radiansPerDirection); float c = v.dotProduct(v) - w * w; float discriminant = b * b - 4 * a * c; if (discriminant < 0.0) { return RayIntersection(); } discriminant = sqrtf(discriminant); float denominator = 1.0 / (2.0 * a); root = (-b - discriminant) * denominator; if (root > 0.0) { Vector point = ray.getPointAt(root); Vector bottomCenterToPoint = point - mTop; Vector topToPoint = point - mBottomCenter; if (coneAxis.dotProduct(bottomCenterToPoint) > 0.0 && (-coneAxis).dotProduct(topToPoint) > 0.0) { intersectionDistances.push_back(root); closestRoot = root; } } root = (-b + discriminant) * denominator; if (root > 0.0) { Vector point = ray.getPointAt(root); Vector bottomCenterToPoint = point - mTop; Vector topToPoint = point - mBottomCenter; if (coneAxis.dotProduct(bottomCenterToPoint) > 0.0 && (-coneAxis).dotProduct(topToPoint) > 0.0) { intersectionDistances.push_back(root); if (closestRoot < 0.0) { closestRoot = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } } } // Intersection with bottom if (fabs(rayDirectionDotAxis) < FLOAT_ZERO) { if (closestRoot > 0.0) { if (rayExit < 0.f) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } ConePointer pointer = ConePointer(new Cone(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); } // Intersection with top and bottom points root = (-coneAxis).dotProduct(rayOriginPosition - mBottomCenter) / rayDirectionDotAxis; if (root > 0.0) { Vector topToPoint = ray.getPointAt(root) - mBottomCenter; if (topToPoint.dotProduct(topToPoint) < mRadius * mRadius) { intersectionDistances.push_back(root); if (closestRoot < 0.0) { closestRoot = root; rayExit = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } } if (closestRoot > 0.0) { if (rayExit < 0.0) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } ConePointer pointer = ConePointer(new Cone(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); }