added ex02 solution

This commit is contained in:
jp 2022-11-18 11:43:53 +01:00
parent d3e64994d4
commit 8b8a53dde6
8 changed files with 141 additions and 31 deletions

View file

@ -4,20 +4,24 @@
PointLight::PointLight(Vector3d const &position, float intensity, Color const &color) : Light(intensity, color), position(position) {} PointLight::PointLight(Vector3d const &position, float intensity, Color const &color) : Light(intensity, color), position(position) {}
Light::Illumination PointLight::illuminate(Scene const &scene, Ray const &ray) const { Light::Illumination PointLight::illuminate(Scene const &scene, Ray const &ray) const {
// IMPLEMENT ME Vector3d const target = ray.origin + (ray.length - LGT_EPS) * ray.direction;
// Get the point on the surface
// Create an instance of the Illumination object, fill in the direction (from // Illumination object
// surface point to light source) Illumination illum;
Light::Illumination illum; illum.direction = normalized(target - this->position);
// Precompute the distance from the light source
float const distance = length(target - this->position);
// Define a secondary ray from the surface point to the light source. // Define a secondary ray from the surface point to the light source.
Ray lightRay;
lightRay.origin = target;
lightRay.direction = -illum.direction;
lightRay.length = distance - LGT_EPS;
// If the target is not in shadow... (use scene.findOcclusion()) // If the target is not in shadow...
if (!scene.findOcclusion(lightRay))
// Compute the brightness-color of this light using inverse squared distance // ... compute the attenuation and light color
// to light source (i.e. 1/(d^2)), the color of this light source and the illum.color = 1.0f / (distance * distance) * this->color * this->intensity;
// intensity
return illum; return illum;
} }

View file

@ -13,19 +13,78 @@ Box::Box(Vector3d const &center, Vector3d const &size, std::shared_ptr<Shader> c
// Primitive functions ///////////////////////////////////////////////////////// // Primitive functions /////////////////////////////////////////////////////////
bool Box::intersect(Ray &ray) const { bool Box::intersect(Ray &ray) const {
// IMPLEMENT ME! // Project the ray onto the box
Vector3d const minBounds = this->center - this->size / 2;
Vector3d const maxBounds = this->center + this->size / 2;
Vector3d t1 = componentQuotient(minBounds - ray.origin, ray.direction);
Vector3d t2 = componentQuotient(maxBounds - ray.origin, ray.direction);
// Determine whether the ray intersects the box // Determine the intersection points (tNear, tFar)
// We also have to remember the intersection axes (tNearIndex, tFarIndex)
float tNear = -INFINITY;
float tFar = +INFINITY;
int tNearIndex = 0;
int tFarIndex = 0;
for (int d = 0; d < 3; ++d) {
// Test the trivial case (and to avoid division by zero errors)
if (ray.direction[d] == 0 && (ray.origin[d] < minBounds[d] || ray.origin[d] > maxBounds[d]))
return false;
// Swap the bounds if necessary
if (t1[d] > t2[d])
std::swap(t1[d], t2[d]);
// Check for the near intersection
if (t1[d] > tNear) {
tNear = t1[d];
tNearIndex = d;
}
// Check for the far intersection
if (t2[d] < tFar) {
tFar = t2[d];
tFarIndex = d;
}
// Check whether we missed the box completely
if (tFar < 0 || tNear > tFar)
return false;
}
// Check whether we are on the outside or on the inside of the box
float const t = (tNear >= 0 ? tNear : tFar);
int const tIndex = tNear >= 0 ? tNearIndex : tFarIndex;
// Test whether this is the foremost primitive in front of the camera // Test whether this is the foremost primitive in front of the camera
if (ray.length < t)
return false;
// (Optional for now) Calculate the normal // Calculate the normal
ray.normal = Vector3d(0, 0, 0);
// Flip the normal if we are on the inside
ray.normal[tIndex] = std::copysignf(1.0f, ray.direction[tIndex]) * (tNear < 0.0f ? +1.0f : -1.0f);
// (Optional for now) Calculate the surface position // Calculate the surface position and tangent vector
Vector3d const target = ray.origin + t * ray.direction;
Vector3d const surface = componentQuotient(target - minBounds, maxBounds - minBounds);
if (tIndex == 0) {
ray.surface = Vector2d(surface[2], surface[1]);
ray.tangent = Vector3d(0, 0, 1);
} else if (tIndex == 1) {
ray.surface = Vector2d(surface[0], surface[2]);
ray.tangent = Vector3d(1, 0, 0);
} else {
ray.surface = Vector2d(surface[0], surface[1]);
ray.tangent = Vector3d(1, 0, 0);
}
// Set the new length and the current primitive // Set the new length and the current primitive
ray.length = t;
ray.primitive = this;
return false; // True, because the primitive was hit
return true;
} }
// Bounding box //////////////////////////////////////////////////////////////// // Bounding box ////////////////////////////////////////////////////////////////

View file

@ -27,7 +27,7 @@ bool InfinitePlane::intersect(Ray &ray) const {
return false; return false;
// Set the normal // Set the normal
// IMPLEMENT ME ray.normal = this->normal;
// Set the new length and the current primitive // Set the new length and the current primitive
ray.length = t; ray.length = t;

View file

@ -36,7 +36,8 @@ bool Sphere::intersect(Ray &ray) const {
return false; return false;
// Calculate the normal // Calculate the normal
// IMPLEMENT ME Vector3d const hitPoint = ray.origin + t * ray.direction;
ray.normal = normalized(hitPoint - this->center);
// Calculate the surface position and tangent vector // Calculate the surface position and tangent vector
float const phi = std::acos(ray.normal.y); float const phi = std::acos(ray.normal.y);

View file

@ -100,7 +100,7 @@ bool Triangle::intersect(Ray &ray) const {
return false; return false;
// Calculate the normal // Calculate the normal
// IMPLEMENT ME ray.normal = normalized(crossProduct(edge1, edge2));
// Calculate the surface position // Calculate the surface position
ray.surface = u * this->surface[1] + v * this->surface[2] + (1 - u - v) * this->surface[0]; ray.surface = u * this->surface[1] + v * this->surface[2] + (1 - u - v) * this->surface[0];

View file

@ -4,9 +4,16 @@
MirrorShader::MirrorShader() {} MirrorShader::MirrorShader() {}
Color MirrorShader::shade(Scene const &scene, Ray const &ray) const { Color MirrorShader::shade(Scene const &scene, Ray const &ray) const {
// IMPLEMENT ME
// Calculate the reflection vector // Calculate the reflection vector
Vector3d const reflection = ray.direction - 2 * dotProduct(ray.normal, ray.direction) * ray.normal;
// Create a new reflection ray // Create a new reflection ray
Ray reflectionRay = ray;
reflectionRay.origin = ray.origin + (ray.length - REFR_EPS) * ray.direction;
reflectionRay.direction = normalized(reflection);
reflectionRay.length = INFINITY;
reflectionRay.primitive = nullptr;
// Send the new ray out into the scene and return the result // Send the new ray out into the scene and return the result
return Color(0, 0, 1); return scene.traceRay(reflectionRay);
} }

View file

@ -4,12 +4,48 @@
RefractionShader::RefractionShader(float indexInside, float indexOutside) : indexInside(indexInside), indexOutside(indexOutside) {} RefractionShader::RefractionShader(float indexInside, float indexOutside) : indexInside(indexInside), indexOutside(indexOutside) {}
Color RefractionShader::shade(Scene const &scene, Ray const &ray) const { Color RefractionShader::shade(Scene const &scene, Ray const &ray) const {
// IMPLEMENT ME // Circumvent getting environment map color into the mix
// Calculate the refracted ray using the surface normal vector and if (ray.getRemainingBounces() > 0) {
// indexInside, indexOutside // Get the normal of the primitive which was hit
// Also check for total internal reflection Vector3d normalVector = ray.normal;
// Send out a new refracted ray into the scene; recursively call traceRay()
return Color(1, 0, 0); // Calculate the index of refraction
float refractiveIndex = indexOutside / indexInside;
// What if we are already inside the object?
if (dotProduct(normalVector, ray.direction) > 0) {
normalVector = -normalVector;
refractiveIndex = indexInside / indexOutside;
}
// Using the notation from the lecture
float cosineTheta = dotProduct(normalVector, -ray.direction);
float cosinePhi = std::sqrt(1 + refractiveIndex * refractiveIndex * (cosineTheta * cosineTheta - 1));
// Calculate t, the new ray direction
Vector3d t = refractiveIndex * ray.direction + (refractiveIndex * cosineTheta - cosinePhi) * normalVector;
// Create the refraction ray
Ray refractionRay = ray;
// Reset the ray
refractionRay.length = INFINITY;
refractionRay.primitive = nullptr;
// Check whether it is a refraction.
if (dotProduct(t, normalVector) <= 0.0) {
refractionRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
refractionRay.direction = normalized(t);
} else { // Otherwise, it is a total reflection.
refractionRay.origin = ray.origin + (ray.length - REFR_EPS) * ray.direction;
// Next we get the reflection vector
Vector3d const reflectionVector = ray.direction - 2.0f * dotProduct(normalVector, ray.direction) * normalVector;
// Change the ray direction and origin
refractionRay.direction = normalized(reflectionVector);
}
// Send out a new refracted ray into the scene
return scene.traceRay(refractionRay);
}
return Color(0.0f, 0.0f, 0.0f);
} }
bool RefractionShader::isTransparent() const { return true; } bool RefractionShader::isTransparent() const { return true; }

View file

@ -5,8 +5,11 @@
SimpleShadowShader::SimpleShadowShader(Color const &objectColor) : objectColor(objectColor) {} SimpleShadowShader::SimpleShadowShader(Color const &objectColor) : objectColor(objectColor) {}
Color SimpleShadowShader::shade(Scene const &scene, Ray const &ray) const { Color SimpleShadowShader::shade(Scene const &scene, Ray const &ray) const {
// IMPLEMENT ME Color fragmentColor;
// loop over all light sources to check for visibility and multiply "light
// strength" with this objects albedo (color) // Accumulate the light over all light sources
return Color(0, 1, 0); for (const auto &light : scene.lights())
fragmentColor += light->illuminate(scene, ray).color;
return fragmentColor * this->objectColor;
} }