aboutsummaryrefslogtreecommitdiff
path: root/src/illuminate/illuminate.cpp
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2023-12-07 16:23:20 -0500
committersotech117 <michael_foiani@brown.edu>2023-12-07 16:23:20 -0500
commitcaa765bff49d54217b75aaf0e7acf4e5392a11e4 (patch)
tree9b92914dfb88b99599e8e60e4512e9e9ea9a25db /src/illuminate/illuminate.cpp
parenta9274459443f1d560d7580a162deb581549980cb (diff)
upload base code
Diffstat (limited to 'src/illuminate/illuminate.cpp')
-rw-r--r--src/illuminate/illuminate.cpp304
1 files changed, 304 insertions, 0 deletions
diff --git a/src/illuminate/illuminate.cpp b/src/illuminate/illuminate.cpp
new file mode 100644
index 0000000..d6d43c8
--- /dev/null
+++ b/src/illuminate/illuminate.cpp
@@ -0,0 +1,304 @@
+#include "raytracer/raytracer.h"
+
+glm::vec4 RayTracer::illuminationFromPointLight(
+ const SceneLightData &light,
+ glm::vec3 intersectionWorld,
+ glm::vec3 normalWorld,
+ glm::vec3 directionToCamera,
+ const RenderShapeData &shape,
+ const RayTraceScene &scene
+ )
+{
+ auto directionFromIntersectionToLight = light.pos.xyz() - intersectionWorld;
+ directionFromIntersectionToLight = glm::normalize(directionFromIntersectionToLight);
+
+ // check if this light is blocked by an object
+ auto distanceToLight = glm::distance(light.pos.xyz(), intersectionWorld);
+ bool isShadow = RayTracer::isShadowed(
+ light.pos,
+ distanceToLight,
+ glm::vec4(directionFromIntersectionToLight, 0.f),
+ glm::vec4(intersectionWorld, 1.f),
+ scene);
+ if (isShadow)
+ {
+ // if this is a shadow, then no light contribution
+ return glm::vec4(0.f);
+ }
+
+ // calculate attenuation
+ float c1 = light.function.x;
+ float c2 = light.function.y;
+ float c3 = light.function.z;
+ float attenuation = std::min(1.f, 1.f / (c1 + distanceToLight * c2 + (distanceToLight * distanceToLight) * c3));
+
+ return phong(
+ light.color,
+ attenuation,
+ directionFromIntersectionToLight,
+ directionToCamera,
+ intersectionWorld,
+ normalWorld,
+ shape,
+ scene);
+}
+
+glm::vec4 RayTracer::illuminationFromSpotLight(
+ const SceneLightData &light,
+ glm::vec3 intersectionWorld,
+ glm::vec3 normalWorld,
+ glm::vec3 directionToCamera,
+ const RenderShapeData &shape,
+ const RayTraceScene &scene
+)
+{
+ auto distance = glm::distance(light.pos.xyz(), intersectionWorld);
+
+ // calculate the angle from the shape to the spot light
+ auto directionFromIntersectionToLight = glm::normalize(light.pos.xyz() - intersectionWorld);
+
+ // calculate intensity, based on angle. apply falloff if necessary
+ auto lightDirection = glm::normalize(light.dir.xyz());
+ // invert the direction of the intersection to light for dot product to work correctly
+ auto cosTheta = glm::dot(-directionFromIntersectionToLight, lightDirection);
+ auto theta = glm::acos(cosTheta);
+
+ // determine intensity, based on location on spot cone
+ glm::vec4 intensity;
+ float inner = light.angle - light.penumbra;
+ if (theta <= inner)
+ {
+ intensity = light.color;
+ }
+ else if
+ (
+ theta > inner
+ && theta <= light.angle
+ )
+ {
+ // inside the penumbra, need to apply falloff
+ float falloff = -2 * std::pow(theta - inner, 3) / std::pow(light.penumbra, 3) +
+ 3 * std::pow(theta - inner, 2) / std::pow(light.penumbra, 2);
+ intensity = light.color * (1 - falloff);
+ }
+ else // theta > light.angle
+ {
+ return glm::vec4(0.f);
+ }
+
+ // if the light is within the cone, see if it's a shadow
+ auto distanceToLight = glm::distance(light.pos.xyz(), intersectionWorld);
+ bool isShadow = RayTracer::isShadowed(
+ light.pos,
+ distanceToLight,
+ glm::vec4(directionFromIntersectionToLight, 0.f),
+ glm::vec4(intersectionWorld, 1.f),
+ scene);
+ if (isShadow)
+ {
+ // if this is a shadow, then no light contribution
+ return glm::vec4(0.f);
+ }
+
+ // calculate attenuation
+ float c1 = light.function.x;
+ float c2 = light.function.y;
+ float c3 = light.function.z;
+ float attenuation = std::min(1.f, 1.f / (c1 + distance * c2 + (distance * distance) * c3));
+
+ return phong(
+ intensity,
+ attenuation,
+ directionFromIntersectionToLight,
+ directionToCamera,
+ intersectionWorld,
+ normalWorld,
+ shape,
+ scene);
+}
+
+glm::vec4 RayTracer::illuminationFromDirectionalLight(
+ const SceneLightData &light,
+ glm::vec3 intersectionWorld,
+ glm::vec3 normalWorld,
+ glm::vec3 directionToCamera,
+ const RenderShapeData &shape,
+ const RayTraceScene &scene
+)
+{
+ // define direction and distance of directional light
+ auto directionFromIntersectionToLight = - light.dir;
+ directionFromIntersectionToLight = glm::normalize(directionFromIntersectionToLight);
+ float distanceToLight = FINF; // directional light infinitely far away
+
+ // check if an object blocks ours
+ bool isShadow = RayTracer::isShadowed(
+ light.pos,
+ distanceToLight,
+ directionFromIntersectionToLight,
+ glm::vec4(intersectionWorld, 1.f),
+ scene);
+ if (isShadow)
+ {
+ // if this is a shadow, then no light contribution
+ return glm::vec4(0.f);
+ }
+
+ float attenuation = 1.f; // directional lights don't attenuate
+ return phong(
+ light.color,
+ attenuation,
+ directionFromIntersectionToLight,
+ directionToCamera,
+ intersectionWorld,
+ normalWorld,
+ shape,
+ scene);
+}
+
+
+
+// Calculates the RGBA of a pixel from intersection infomation and globally-defined coefficients
+glm::vec4 RayTracer::illuminatePixel(
+ glm::vec3 intersectionWorld,
+ glm::vec3 normalWorld,
+ glm::vec3 directionToCamera,
+ const RenderShapeData& shape,
+ const RayTraceScene &scene,
+ int depth)
+{
+ // Normalizing directions
+ normalWorld = glm::normalize(normalWorld);
+ directionToCamera = glm::normalize(directionToCamera);
+
+ // to be summed then returned
+ glm::vec4 illumination(0, 0, 0, 1.f);
+
+ // add the ambient term
+ float ka = scene.getGlobalData().ka;
+ illumination += ka*shape.primitive.material.cAmbient;
+
+ for (const SceneLightData &light : scene.getLights()) {
+ switch (light.type) {
+ case LightType::LIGHT_POINT:
+ illumination +=
+ illuminationFromPointLight(light, intersectionWorld, normalWorld, directionToCamera, shape, scene);
+ continue;
+ case LightType::LIGHT_DIRECTIONAL:
+ illumination +=
+ illuminationFromDirectionalLight(light, intersectionWorld, normalWorld, directionToCamera, shape, scene);
+ continue;
+ case LightType::LIGHT_SPOT:
+ illumination +=
+ illuminationFromSpotLight(light, intersectionWorld, normalWorld, directionToCamera, shape, scene);
+ continue;
+ case LightType::LIGHT_AREA:
+ illumination +=
+ illuminationFromAreaLight(light, intersectionWorld, normalWorld, directionToCamera, shape, scene);
+ continue;
+ default:
+ continue;
+ }
+ }
+
+ auto incidentDir = -directionToCamera;
+ // recursive raytracing for the reflection and refraction (see reflect.cpp)
+ illumination += refract(intersectionWorld, normalWorld, incidentDir, shape, scene, depth + 1);
+ illumination += reflect(intersectionWorld, normalWorld, incidentDir, shape, scene, depth + 1);
+
+ return illumination;
+}
+
+// helper function to handle the diffuse and specular terms
+// also handles the texture within that diffuse term
+glm::vec4 RayTracer::phong(
+ glm::vec4 lightColor,
+ float attenuation,
+ glm::vec3 directionFromIntersectionToLight,
+ glm::vec3 directionToCamera,
+ glm::vec3 intersectionWorld,
+ glm::vec3 normalWorld,
+ const RenderShapeData &shape,
+ const RayTraceScene &scene)
+{
+ float kd = scene.getGlobalData().kd;
+ float ks = scene.getGlobalData().ks;
+ auto material = shape.primitive.material;
+
+ glm::vec4 illumination(0.f);
+
+ // calculate diffuse term
+ auto dotDiffuse = glm::dot(normalWorld, directionFromIntersectionToLight);
+ if (dotDiffuse > 0) // ensure not facing away
+ {
+ auto diffuse = (kd * material.cDiffuse);
+ if (material.textureMap.isUsed)
+ {
+ glm::vec4 pObject = shape.inverseCTM * glm::vec4(intersectionWorld, 1.f);
+ diffuse = interpolateTexture(pObject, shape, diffuse);
+ }
+ illumination += (attenuation * lightColor) * dotDiffuse * diffuse;
+ }
+
+ // add specular term
+ auto reflectedDirOverNormal =
+ 2 * glm::dot(directionFromIntersectionToLight, normalWorld) * normalWorld -
+ directionFromIntersectionToLight;
+ auto dotSpecular = glm::dot(reflectedDirOverNormal, directionToCamera);
+ auto toPow = std::pow(dotSpecular, material.shininess);
+ if (dotSpecular > 0) {
+ illumination += (attenuation * lightColor) * toPow * (ks * material.cSpecular);
+ }
+
+ return illumination;
+}
+
+// EXTRA CREDIT -> AREA LIGHT
+glm::vec4 RayTracer::illuminationFromAreaLight(
+ const SceneLightData &light,
+ glm::vec3 intersectionWorld,
+ glm::vec3 normalWorld,
+ glm::vec3 directionToCamera,
+ const RenderShapeData &shape,
+ const RayTraceScene &scene
+) {
+ // select a random point within the light's height and width
+ float width = light.width;
+ float height = light.height;
+ float x = ((float) rand() / (float) RAND_MAX) * width - width / 2.f;
+ float y = ((float) rand() / (float) RAND_MAX) * height - height / 2.f;
+ glm::vec4 lightPosition = light.pos + glm::vec4(x, y, 0.f, 0.f);
+
+ auto directionFromIntersectionToLight = lightPosition.xyz() - intersectionWorld;
+ directionFromIntersectionToLight = glm::normalize(directionFromIntersectionToLight);
+
+ // check if this light is blocked by an object
+ auto distanceToLight = glm::distance(lightPosition.xyz(), intersectionWorld);
+ bool isShadow = RayTracer::isShadowed(
+ lightPosition,
+ distanceToLight,
+ glm::vec4(directionFromIntersectionToLight, 0.f),
+ glm::vec4(intersectionWorld, 1.f),
+ scene);
+ if (isShadow)
+ {
+ // if this is a shadow, then shoow a ray to a random point in the light
+ return glm::vec4(0.f);
+ }
+
+ // calculate attenuation
+ float c1 = light.function.x;
+ float c2 = light.function.y;
+ float c3 = light.function.z;
+ float attenuation = std::min(1.f, 1.f / (c1 + distanceToLight * c2 + (distanceToLight * distanceToLight) * c3));
+
+ return phong(
+ light.color,
+ attenuation,
+ directionFromIntersectionToLight,
+ directionToCamera,
+ intersectionWorld,
+ normalWorld,
+ shape,
+ scene);
+}