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;
}
|