-
Notifications
You must be signed in to change notification settings - Fork 0
/
'
146 lines (138 loc) · 4.88 KB
/
'
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "models/camera.h"
#include "models/dielectric.h"
#include "models/hitable.h"
#include "models/hitable_list.h"
#include "models/lambertian.h"
#include "models/light_source.h"
#include "models/material.h"
#include "models/metal.h"
#include "models/parallel_light.h"
#include "models/ray.h"
#include "models/sphere.h"
#include "models/spot_light.h"
#include "models/vec3.h"
#include <bits/stdc++.h>
#include <cassert>
#include <cstdlib>
#define rep(i, n) for (int i = 0; i < n; i++)
using namespace std;
hitable *random_scene() {
int n = 500;
vector<hitable *> list;
list.push_back(new sphere(point3(0, -1000, 0), 1000,
new lambertian(color(0.5, 0.5, 0.5))));
int i = 1;
for (int a = -6; a < 6; a++) {
for (int b = -6; b < 6; b++) {
double choose_mat = drand48();
point3 center(a + 0.9 * drand48(), 0.2, b + 0.9 * drand48());
if ((center - point3(4, 0.2, 0)).length() > 0.9) {
if (choose_mat < 0.8) { // difuse
list.push_back(new sphere(
center, 0.2,
new lambertian(color(drand48() * drand48(), drand48() * drand48(),
drand48() * drand48()))));
} else if (choose_mat < 0.95) { // metal
list.push_back(new sphere(
center, 0.2,
new metal(color(0.5 * (1 + drand48()), 0.5 * (1 + drand48()),
0.5 * (1 + drand48())),
0.5 * (1 + drand48()))));
} else {
list.push_back(new sphere(center, 0.2, new dielectric(1.5)));
}
}
}
}
list.push_back(new sphere(point3(0, 1, 0), 1.0, new dielectric(1.5)));
list.push_back(
new sphere(point3(-4, 1, 0), 1.0, new lambertian(color(0.4, 0.2, 0.1))));
list.push_back(
new sphere(point3(4, 1, 0), 1.0, new metal(color(0.7, 0.6, 0.5), 0.0)));
vector<light_source *> lights;
lights.push_back(
new spot_light(point3(3.0, 100.0, 25.0), color(1.0, 1.0, 1.0), 2.0));
// lights.push_back(
// new spot_light(point3(-2.0, 10.0, 1.0), color(1.0, 1.0, 1.0), 2.0));
// lights.push_back(
// new parallel_light(vec3(2.0, 1.0, 1.0), color(1.0, 1.0, 1.0), 2.0));
return new hitable_list(list, list.size(), lights);
}
inline color blinn_color(const color &ambient, const hit_record &rec,
const ray &r,
const std::vector<light_source *> &lights) {
// vec3 light_vec = unit_vector(scattered.direction());
assert(lights.size());
light_source *light = lights[0];
vec3 light_vec = unit_vector(light->get_ray(r.at(rec.t)).direction());
vec3 view_vec = -unit_vector(r.direction());
vec3 half = (view_vec + light_vec) / 2.0;
vec3 normal = unit_vector(rec.normal);
double light_intensity = fmax(0.0, dot(normal, light_vec));
double blinn = fmax(0.0, dot(normal, half));
double shininess = 10.0;
double spec_amount = pow(blinn, shininess);
color specular = light->col * spec_amount;
color diffuse = light->col * light_intensity;
cout << specular << " " << diffuse << endl;
return specular * 0.8 + diffuse * 0.8 + ambient * 0.4;
}
color getColor(const ray &r, hitable *world, int depth = 0) {
hit_record rec;
if (world->hit(r, 0.001, 1e9, rec)) {
ray scattered;
vec3 attenuation;
color ambient = attenuation;
hitable_list *_world = (hitable_list *)world;
if (depth < 50 && rec.mat_ptr->scatter(r, rec, attenuation, scattered)) {
color ambient = attenuation;
point3 hit_point = r.at(rec.t);
double light_sum = _world->get_total_light(hit_point);
assert(light_sum <= _world->light_sum);
if (_world->lights.size()) {
// ambient *= light_sum / _world->light_sum;
}
color col = getColor(scattered, world, depth + 1);
ambient = ambient * col;
return blinn_color(ambient, rec, r, _world->lights);
} else {
return color(0.0, 0.0, 0.0);
}
}
color c1(1.0, 1.0, 1.0);
color c2(0.5, 0.7, 1.0);
vec3 normal = unit_vector(r.direction());
double t = (double)(normal.y() + 1) / 2.0;
return (1 - t) * c1 + t * c2;
}
int main() {
int nx = 300;
int ny = 200;
int ns = 30;
cout << "P3" << endl << nx << " " << ny << endl << 255 << endl;
vec3 lookfrom(13.0, 2.0, 3.0);
vec3 lookat(0.0, 0.0, 0.0);
vec3 up_vector(0.0, 1.0, 0.0);
double focal_length = (lookfrom - lookat).length();
double aparture = 0.1;
camera cam(lookfrom, lookat, up_vector, 20, double(nx) / double(ny), aparture,
focal_length);
hitable *world = random_scene();
rep(i, ny) {
rep(j, nx) {
color col;
rep(_, ns) {
double u = double(j + drand48()) / double(nx);
double v = double(i + drand48()) / double(ny);
ray r = cam.get_ray(u, v);
color now = getColor(r, world);
col += now;
}
col /= (double)ns;
color icol;
rep(i, 3) icol[i] = int(255.99 * sqrt(col[i]));
cout << icol << endl;
}
}
return 0;
}