-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathao.cpp
More file actions
113 lines (89 loc) · 3.86 KB
/
ao.cpp
File metadata and controls
113 lines (89 loc) · 3.86 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
//
// Created by mtakagi on 2025/01/22.
//
#include "ao.h"
#include "Sphere.h"
#include "Plane.h"
#include "Isect.h"
#include <cmath>
const int NAOSamples = 8;
const aobench::Sphere spheres[3] = {
aobench::Sphere(aobench::Vector3d(-2, 0, -3.5), 0.5),
aobench::Sphere(aobench::Vector3d(-0.5, 0, -3.0), 0.5),
aobench::Sphere(aobench::Vector3d(1.0, 0, -2.2), 0.5),
};
const aobench::Plane plane(aobench::Vector3d(0.0, -0.5, 0.0), aobench::Vector3d(0.0, 1.0, 0.0));
inline uint8_t clamp(double f) {
auto i = static_cast<int>(f * 255.5);
if (i < 0) {
i = 0;
} else if (i > 255) {
i = 255;
}
return static_cast<uint8_t>(i);
}
aobench::Vector3d AmbientOcclusion(const aobench::Isect& isect) {
auto ntheta = NAOSamples;
auto nphi = NAOSamples;
auto eps = 0.0001;
auto p = isect.p() + isect.n() * eps;
auto basis = isect.n().orthoBasis();
auto occlusion = 0.0;
for (auto i = 0; i < ntheta; i++) {
for (auto j = 0; j < nphi; j++) {
auto theta = sqrt(drand48());
auto phi = 2.0 * M_PI * drand48();
auto x = cos(phi) * theta;
auto y = sin(phi) * theta;
auto z = sqrt(1.0 - theta * theta);
// local -> global
auto rx = x * basis[0].x() + y * basis[1].x() + z * basis[2].x();
auto ry = x * basis[0].y() + y * basis[1].y() + z * basis[2].y();
auto rz = x * basis[0].z() + y * basis[1].z() + z * basis[2].z();
aobench::Ray ray(p, aobench::Vector3d(rx, ry, rz));
aobench::Isect occIsect(1.0e+17, aobench::Vector3d(0, 0, 0), aobench::Vector3d(0, 0, 0), false);
occIsect = spheres[0].rayIntersect(occIsect, ray);
occIsect = spheres[1].rayIntersect(occIsect, ray);
occIsect = spheres[2].rayIntersect(occIsect, ray);
occIsect = plane.rayIntersect(occIsect, ray);
if (occIsect.hit()) {
occlusion += 1.0;
}
}
}
occlusion = ((ntheta * nphi) - occlusion) / (ntheta * nphi);
return {occlusion, occlusion, occlusion};
}
std::vector<uint8_t> Render(int w, int h, int nsubsamples) {
std::vector<uint8_t> img(w * h * 3);
std::vector<double> fimg(w * h * 3);
for (auto y = 0; y < h; y++) {
for (auto x = 0; x < w; x++) {
for (auto v = 0; v < nsubsamples; v++) {
for (auto u = 0; u < nsubsamples; u++) {
auto px = (x + (u / (double)nsubsamples) - (w / 2.0)) / (w / 2.0);
auto py = -(y + (v / (double)nsubsamples) - (h / 2.0)) / (h / 2.0);
aobench::Ray ray(aobench::Vector3d(0, 0, 0), aobench::Vector3d(px, py, -1).normalize());
aobench::Isect isect(1.0e+17, aobench::Vector3d(0, 0, 0), aobench::Vector3d(0, 0, 0), false);
isect = spheres[0].rayIntersect(isect, ray);
isect = spheres[1].rayIntersect(isect, ray);
isect = spheres[2].rayIntersect(isect, ray);
isect = plane.rayIntersect(isect, ray);
if (isect.hit()) {
auto col = AmbientOcclusion(isect);
fimg[3 * (y * w + x) + 0] += col.x();
fimg[3 * (y * w + x) + 1] += col.y();
fimg[3 * (y * w + x) + 2] += col.z();
}
}
}
fimg[3 * (y * w + x) + 0] /= (double)(nsubsamples * nsubsamples);
fimg[3 * (y * w + x) + 1] /= (double)(nsubsamples * nsubsamples);
fimg[3 * (y * w + x) + 2] /= (double)(nsubsamples * nsubsamples);
img[3 * (y * w + x) + 0] = clamp(fimg[3 *(y * w + x) + 0]);
img[3 * (y * w + x) + 1] = clamp(fimg[3 *(y * w + x) + 1]);
img[3 * (y * w + x) + 2] = clamp(fimg[3 *(y * w + x) + 2]);
}
}
return img;
}