-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
162 lines (135 loc) · 4.91 KB
/
main.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
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <cmath>
#include <algorithm>
#include <vector>
#include <cassert>
#include <png.h>
#include "vec.h"
#include "fcolor.h"
#include "ray.h"
#include "shape.h"
#include "light.h"
#include "scene.h"
#include "image.h"
using namespace std;
const int WIDTH = 512;
const int HEIGHT = 512;
const char* PNG_FILE_NAME = "out.png";
const float C_EPSILON = 1.0f / 512;
int ray_trace(png_bytepp&);
int main()
{
auto image = new png_bytep[HEIGHT];
for (auto j = 0; j < HEIGHT; j++) {
image[j] = new png_byte[WIDTH * 4];
for (auto i = 0; i < WIDTH * 4; i++) {
image[j][i] = 0xff;
}
}
if (ray_trace(image)) goto heaven;
if (write_png(image, PNG_FILE_NAME, WIDTH, HEIGHT)) goto heaven;
heaven:
for (auto j = 0; j < HEIGHT; j++) delete[] image[j];
delete[] image;
return 0;
}
FColor shading(const Scene scene, const InterSectionTestResult result, const Ray eye)
{
// 放射輝度
FColor col;
// Phongの反射モデル
// 環境光
col += result.shape->material.ambientFactor * scene.ambientIntensity;
for (LightSource* light : scene.lightSources) {
// 光源情報
Lighting lighting = light->lightingAt(result.intersectionPoint.position);
// 入射ベクトル
Vec l = -lighting.direction.normalize();
// 影判定
// C_EPSILON だけ光源側にずらして計算する(重なり防止)
Vec eps = -lighting.direction * C_EPSILON;
Ray shadowRay;
shadowRay.start = result.intersectionPoint.position + eps;
shadowRay.direction = l;
auto shadowRes = scene.testIntersectionWithAll(shadowRay, lighting.distance - C_EPSILON);
if (shadowRes.intersectionPoint.exist) {
// 物体の交点と光源の間に他の物体が在る場合
continue;
}
// (直接光)拡散反射光
float nl = max(min(result.intersectionPoint.normal.dot(l), 1.0f), 0.0f);
if (nl > 0) {
col += (result.shape->material.diffuseFactor * lighting.intensity).mult<float>(nl);
}
// (直接光)鏡面反射光
Vec r = result.intersectionPoint.normal * 2 * nl - l;
Vec v = -eye.direction.normalize();
float vr = max(min(v.dot(r), 1.0f), 0.0f);
if (nl > 0 && vr > 0) {
col += (result.shape->material.specularFactor * lighting.intensity).mult<float>(powf(vr, result.shape->material.shininess));
}
}
return col.normalize();
}
int ray_trace(png_bytepp& image)
{
// カメラ位置
Ray eye(Vec(0, 0, -5.0f));
// 環境光反射係数
FColor kAmb = FColor(0.01f, 0.01f, 0.01f);
// 拡散光反射係数
FColor kDif = FColor(0.69f, 0.70f, 0.00f);
// 鏡面反射係数
FColor kSpe = FColor(0.30f, 0.30f, 0.30f);
float shininess = 8.0f; // 光沢度
Sphere s3(Vec(1, 0, 15.0f), 1.0f);
Sphere s4(Vec(0, 0, 10.0f), 1.0f);
Sphere s5(Vec(-1, 0, 5.0f), 1.0f);
Plane p1(Vec(0, 1, 0), Vec(0, -1, 0));
s3.setMaterial(kAmb, FColor(0.69f, 0, 0), kSpe, shininess);
s4.setMaterial(kAmb, FColor(0, 0.69f, 0), kSpe, shininess);
s5.setMaterial(kAmb, FColor(0, 0, 0.69f), kSpe, shininess);
p1.setMaterial(kAmb, FColor(0.69f, 0.69f, 0.69f), kSpe, shininess);
vector<Shape*> shapes;
shapes.push_back(&s3);
shapes.push_back(&s4);
shapes.push_back(&s5);
shapes.push_back(&p1);
// 光源
PointLightSource light1(FColor(0.5f, 0.5f, 0.5f), Vec(-5.0f, 5.0f, -5.0f));
PointLightSource light2(FColor(0.5f, 0.5f, 0.5f), Vec(5.0f, 0.0f, -5.0f));
PointLightSource light3(FColor(0.5f, 0.5f, 0.5f), Vec(5.0f, 20.0f, -5.0f));
vector<LightSource*> lights;
lights.push_back(&light1);
lights.push_back(&light2);
lights.push_back(&light3);
Scene scene;
scene.shapes = shapes;
scene.lightSources = lights;
// 環境光
scene.ambientIntensity = FColor(0.1f, 0.1f, 0.1f);
for (auto y = 0; y < HEIGHT; y++) {
png_bytep row = image[y];
for (auto x = 0; x < WIDTH; x++) {
png_bytep rgba = &(row[x*4]);
//rgba[3] = 0xff; // alpha
eye.setDirection(x, y, WIDTH, HEIGHT);
// 半直線が物体と交差する場合
// 全ての物体に対して交差判定を行う
// 視点位置から(x, y)に向かう半直線と物体との交差判定
auto result = scene.testIntersectionWithAll(eye);
if (result.intersectionPoint.exist) {
// シェーディングの処理を行う
auto col = shading(scene, result, eye);
rgba[0] *= col.red;
rgba[1] *= col.green;
rgba[2] *= col.blue;
} else {
// 次の点を処理する(背景色として扱う)
rgba[0] = 0x64; // red
rgba[1] = 0x95; // green
rgba[2] = 0xED; // blue
}
}
}
return 0;
}