| 12
 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
 
 | #include "../3rdParty/svpng/svpng.inc"#include "../Chapter5/Sphere.h"
 #include "../Chapter5/CollisibleList.h"
 #include "../Chapter6/Camera.h"
 #include <cstdio>
 #include <limits>
 #include <random>
 #include <functional>
 
 const int WIDTH = 640;
 const int HEIGHT = 480;
 
 using byte = unsigned char;
 
 void paint(byte *d, int x, int y, Color3f color, float alpha) {
 d += 4 * ((HEIGHT - y - 1) * WIDTH + x);
 d[0] = 255 * color.r;
 d[1] = 255 * color.g;
 d[2] = 255 * color.b;
 d[3] = 255 * alpha;
 }
 
 Color3f mix(const Color3f &a, const Color3f &b, float t) { return a * (1.0f - t) + b * t; }
 
 std::uniform_real_distribution<float> dis;
 std::mt19937 engine;
 auto gen = std::bind(dis, engine);
 
 Vector3f getRandomUnit() {
 Vector3f p;
 do {
 p = 2.0f * Vector3f(gen(), gen(), gen()) - Vector3f(1, 1, 1);
 } while (p.length2() >= 1.0);
 return p;
 }
 
 Color3f paint(const Ray &r, const Collisible &obj) {
 CollideRecord rec;
 if (obj.collide(r, 0.001f, std::numeric_limits<float>::max(), rec))
 return 0.5f * paint({rec.p, rec.normal + getRandomUnit()}, obj);
 
 Vector3f dir = r.getDir();
 float t = 0.5f * (dir.y + 1.0f);
 return mix({1.0f, 1.0f, 1.0f}, {0.5f, 0.7f, 1.0f}, t);
 }
 
 int main() {
 byte d[4 * WIDTH * HEIGHT];
 FILE *f = fopen("ch7.png", "wb");
 
 Camera camera({0.0f, 0.0f, 0.0f}, {-2.0f, -1.5f, -1.0f}, {4.0f, 0.0f, 0.0f},
 {0.0f, 3.0f, 0.0f});
 
 CollisibleList list;
 Collisible *obj[2];
 obj[0] = new Sphere({0, 0, -1}, 0.5);
 obj[1] = new Sphere({0, -100.5, -1}, 100);
 
 list.add(obj[0]);
 list.add(obj[1]);
 
 const int SAMPLE_TIMES = 100;
 for (int x = 0; x < WIDTH; x++) {
 for (int y = 0; y < HEIGHT; y++) {
 Color3f col;
 for (int i = 0; i < SAMPLE_TIMES; i++) {
 float u = (float)(x + gen()) / WIDTH;
 float v = (float)(y + gen()) / HEIGHT;
 col += paint(camera.getRay(u, v), list);
 }
 col /= SAMPLE_TIMES;
 col = {sqrtf(col[0]), sqrtf(col[1]), sqrtf(col[2])};
 paint(d, x, y, col, 1.0f);
 }
 }
 
 delete obj[0];
 delete obj[1];
 svpng(f, WIDTH, HEIGHT, d, 1);
 fclose(f);
 }
 
 |