aboutsummaryrefslogtreecommitdiff
path: root/src/illuminate/reflect.cpp
blob: c7fea98072656aa7312383de557d0f3c299808b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//
// Created by Michael Foiani on 11/4/23.
//

#include "raytracer/raytracer.h"

// helper that reflects vectors
glm::vec3 reflectVector(
        glm::vec3 incidentDir,
        glm::vec3 normal)
{
    return incidentDir - 2.f * glm::dot(incidentDir, normal) * normal;
}

glm::vec4 RayTracer::reflect(
        glm::vec3 intersectionWorld,
        glm::vec3 normalWorld,
        glm::vec3 incidentDir,
        const RenderShapeData &shape,
        const RayTraceScene &scene,
        int depth)
{
    auto material = shape.primitive.material;
    // check if the material is reflective
    if (material.cReflective == glm::vec4(0.f))
    {
        return glm::vec4(0.f);
    }
    auto reflectedDir = reflectVector(incidentDir, normalWorld);

    // shoot a ray from the intersection point in the reflected direction
    auto reflectColors = getPixelFromRay(glm::vec4(intersectionWorld + .001f * reflectedDir, 1.f), glm::vec4(reflectedDir, 0.f), scene, depth + 1);
    return scene.getGlobalData().ks * material.cReflective * reflectColors;
}

// EXTRA CREDIT -> refracting

// TRUE REFRACTING
// get the reflection coefficient from fresnel's equations
bool REAL_REFRACTING = false;
float fresnels(
        float currentMediumIor,
        float otherMediumIor,
        float cosAngleIncident,
        float cosAngleTransmitted)
{
    float rPerp = (currentMediumIor * cosAngleIncident - otherMediumIor * cosAngleTransmitted) /
                  (currentMediumIor * cosAngleIncident + otherMediumIor * cosAngleTransmitted);
    rPerp *= rPerp;
    float rPara = (otherMediumIor * cosAngleIncident - currentMediumIor * cosAngleTransmitted) /
                  (otherMediumIor * cosAngleIncident + currentMediumIor * cosAngleTransmitted);
    rPara *= rPara;
    return (rPerp + rPara) / 2.f;
}

// Your refracting
glm::vec4 RayTracer::refract(
        glm::vec3  intersectionWorld,
        glm::vec3  normalWorld,
        glm::vec3  incidentDir,
        const RenderShapeData& shape,
        const RayTraceScene &scene,
        int depth
)
{
    auto material = shape.primitive.material;
    // check if the material is transparent
    if (material.cTransparent == glm::vec4(0.f))
    {
        return glm::vec4(0.f);
    }

    // apply snells law to find the sin of refracted angle (squared)
    incidentDir = glm::normalize(incidentDir);
    float cosAngleIncident = glm::dot(incidentDir, normalWorld);
    float currentMediumIor = mediumIor;
    float otherMediumIor = material.ior;

    if (cosAngleIncident < 0)
    {
        // outside the object
        cosAngleIncident = -cosAngleIncident;
    }
    else
    {
        // inside the object, invert the normal and swap the Iors
        normalWorld = -normalWorld;
        std::swap(currentMediumIor, otherMediumIor);
    }

    float iorRatio = currentMediumIor / otherMediumIor;
    float sinAngleTransmittedSquared = iorRatio * iorRatio * (1 - cosAngleIncident * cosAngleIncident);
    if (sinAngleTransmittedSquared > 1.f) // total internal reflection, not considered
    {
        return glm::vec4(0.f);
    }

    auto cosAngleTransmitted = glm::sqrt(1 - sinAngleTransmittedSquared);

    // compute refracted ray according to snell's law
    auto refractedDir = glm::normalize(
            incidentDir * iorRatio
            + (iorRatio * cosAngleIncident - cosAngleTransmitted) * normalWorld);

    // send a ray in the refracted direction to get the colors
    auto refractedColors = getPixelFromRay(
            glm::vec4(intersectionWorld + .001f * refractedDir, 1.f),
            glm::vec4(refractedDir, 0.f),
            scene,
            depth + 1);

    float fresnel = fresnels(currentMediumIor, otherMediumIor, cosAngleIncident, cosAngleTransmitted);
    auto color = scene.getGlobalData().kt * material.cTransparent * refractedColors * (1 - fresnel);
    return color;
}