-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEngine.cpp
121 lines (96 loc) · 4.17 KB
/
Engine.cpp
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
116
117
118
119
120
121
#include "Engine.hpp"
Image Engine::render(const Scene& scene, bool shaded)
{
this->shaded = shaded;
int width = scene.width;
int height = scene.height;
double aspectRatio = static_cast<double>(width) / height;
double x0 = -1.0;
double x1 = 1.0;
double xdelta = (x1 - x0) / (width - 1);
double y0 = -1.0 / aspectRatio;
double y1 = 1.0 / aspectRatio;
double ydelta = (y1 - y0) / (height - 1);
Vector3D camera = scene.camera;
Image canvas = Image(width, height);
for (int j = 0; j < height; ++j)
{
float y = y0 + j * ydelta;
for (int i = 0; i < width; ++i)
{
float x = x0 + i * xdelta;
Ray ray = Ray(camera, Vector3D(x, y) - camera);
canvas.setPixel(i, j, raytrace(ray, scene));
}
double progress = (double)(j) / height * 100;
cout << "Rendering: In Progress (" << (int) progress << "%)";
cout.flush();
cout << "\r";
}
cout << "Rendering: Completed Successfully (100%)" << endl;
return canvas;
}
Color Engine::raytrace(const Ray& ray, const Scene& scene, int depth)
{
Color color = Color(0, 0, 0);
double distanceHit;
Object3D* objectHit;
tie(objectHit, distanceHit) = rayCollision(ray, scene);
if(objectHit == nullptr)
return color;
Vector3D hitPosition = ray.origin + ray.direction * distanceHit;
Vector3D hitNormal = objectHit->object3DNormal(hitPosition);
color = color + colorBlending(objectHit, hitPosition, hitNormal, scene);
if(depth < this->maxDepth)
{
Vector3D newRayOrigin = hitPosition + hitNormal * this->minDisplacement;
Vector3D newRayDirection = ray.direction - 2 * ray.direction.dot(hitNormal) * hitNormal;
Ray reflectedRay = Ray(newRayOrigin, newRayDirection, false);
color = color + raytrace(reflectedRay, scene, depth + 1) * objectHit->material->reflection;
}
return color;
}
pair<Object3D*, float> Engine::rayCollision(const Ray& ray, const Scene& scene)
{
double distanceMin = DBL_MAX;
Object3D* objectHit = nullptr;
for (Object3D* object : scene.objects)
{
float distance = object->object3DIntersects(ray);
if((distance != -1) && (objectHit == nullptr || distance < distanceMin))
{
distanceMin = distance;
objectHit = object;
}
}
return make_pair(objectHit, distanceMin);
}
Color Engine::colorBlending(Object3D* objectHit, const Vector3D& hitPosition, const Vector3D& hitNormal, const Scene& scene)
{
if(!this->shaded)
return objectHit->material->colorA;
Material* objectHitMaterial = objectHit->material;
Color objectHitColor = objectHitMaterial->colorBlendingProperties(hitPosition);
Ray rayToCamera = Ray(hitPosition, scene.camera - hitPosition, false);
Color newColor = objectHitMaterial->ambient * newColor.HexToRgb("#FFFFFF");
double shadowDetectDistanceHit;
Object3D* shadowDetectObjectHit;
for (Light* light : scene.lights)
{
Ray rayToLight = Ray(hitPosition, light->position - hitPosition);
// tie(shadowDetectObjectHit, shadowDetectDistanceHit) = rayCollision(rayToLight, scene);
// if(shadowDetectObjectHit == nullptr || shadowDetectDistanceHit > (light->position - hitPosition).magnitude())
newColor = newColor + lambertianShading(objectHitMaterial, objectHitColor, hitNormal, rayToLight);
newColor = newColor + blingPhongShading(objectHitMaterial, *light, hitNormal, rayToLight, rayToCamera, 50);
}
return newColor;
}
Color Engine::lambertianShading(const Material* objectHitMaterial, const Color& objectHitColor, const Vector3D& hitNormal, const Ray& rayToLight)
{
return objectHitColor * objectHitMaterial->diffuse * max(hitNormal.dot(rayToLight.direction), 0.0);
}
Color Engine::blingPhongShading(const Material* objectHitMaterial, const Light& light, const Vector3D& hitNormal, const Ray& rayToLight, const Ray& rayToCamera, double specularExponent)
{
Vector3D halfVector = (rayToLight.direction + rayToCamera.direction).normalize();
return light.color * objectHitMaterial->specular * pow(max(hitNormal.dot(halfVector), 0.0), specularExponent);
}