-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.c
More file actions
168 lines (130 loc) · 5.52 KB
/
main.c
File metadata and controls
168 lines (130 loc) · 5.52 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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <time.h>
#include <string.h>
#include "sphere.h"
#include "hitable_list.h"
#include "camera.h"
#include "material.h"
#include "metal.h"
#include "dielectric.h"
#include "lambertian.h"
Vector color(const Ray r, Hitable_List *world_list, int depth)
{
Hit_Record rec;
if (world_list->hitable.hit((const void *) world_list, r, 0.001, FLT_MAX, &rec)) {
Ray scattered;
Vector attenuation;
if (depth < 50 && rec.mat_ptr.scatter((const void *) rec.mat_ptr.inst, r, rec, &attenuation, &scattered)) {
return attenuation.mul(attenuation, color(scattered, world_list, depth + 1));
} else {
return new_vector(new_point(0, 0, 0));
}
} else {
Vector unit_direction = unit_vector(r.direction(r));
float t = 0.5 * (unit_direction.point.y + 1.0);
Vector v1 = new_vector(new_point(1.0, 1.0, 1.0));
Vector v2 = new_vector(new_point(0.5, 0.7, 1.0));
return v1.add(v1.mul_scalar(v1, 1.0 - t), v1.mul_scalar(v2, t));
}
}
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "%d\n", argc);
fprintf(stderr, "%s [input file] [output file]\n", argv[0]);
exit(-1);
}
const char *infile = argv[1];
const char *outfile = argv[2];
FILE *fin = fopen(infile, "r");
FILE *fout = fopen(outfile, "wb");
int nx; // length
int ny; // width
int ns = 10; // sampling times
int sphere_count;
float R = cos(M_PI / 4);
fscanf(fin, "%d %d", &nx, &ny);
fscanf(fin, "%d", &sphere_count);
fprintf(fout, "P3\n%d %d \n255\n", nx, ny);
Hitable *list[sphere_count];
Sphere *sphere;
Lambertian *lam;
Dielectric *diel;
Metal *metal;
for (int i = 0; i < sphere_count; i++) {
float radius;
char material_str[11];
Vector sphere_v = new_vector(new_point(0, 0, 0));
Vector material_v = new_vector(new_point(0, 0, 0));
fscanf(fin, "%f %f %f", &sphere_v.point.x, &sphere_v.point.y, &sphere_v.point.z);
fscanf(fin, "%f", &radius);
fscanf(fin, "%s", material_str);
if (!strcmp(material_str, "metal")) {
fscanf(fin, "%f %f %f", &material_v.point.x, &material_v.point.y, &material_v.point.z);
sphere = (Sphere *) malloc(sizeof(Sphere));
metal = (Metal *) malloc(sizeof(Metal));
*metal = new_metal(material_v, 0.0);
*sphere = new_sphere(sphere_v, radius, (void *) metal, metal->mat.scatter);
} else if (!strcmp(material_str, "lambertian")) {
fscanf(fin, "%f %f %f", &material_v.point.x, &material_v.point.y, &material_v.point.z);
sphere = (Sphere *) malloc(sizeof(Sphere));
lam = (Lambertian *) malloc(sizeof(Lambertian));
*lam = new_lambertian(material_v);
*sphere = new_sphere(sphere_v, radius, (void *) lam, lam->mat.scatter);
} else if (!strcmp(material_str, "dielectric")) {
float ref_idx;
fscanf(fin, "%f", &ref_idx);
sphere = (Sphere *) malloc(sizeof(Sphere));
diel = (Dielectric *) malloc(sizeof(Dielectric));
*diel = new_dielectric(ref_idx);
*sphere = new_sphere(sphere_v, radius, (void *) diel, diel->mat.scatter);
} else {
fprintf(stderr, "Unkown Material\n");
exit(-1);
}
list[i] = &sphere->hitable;
list[i]->inst = (void *) sphere;
}
Hitable_List world = new_hitable_list(list, sphere_count);
Vector lookfrom = new_vector(new_point(13, 2, 3));
Vector lookat = new_vector(new_point(0, 0, 0));
float dist_to_focus = 10.0;
float aperture = 0.1;
clock_t start_time = clock();
Camera cam = new_camera(lookfrom, lookat, new_vector(new_point(0, 1, 0)), 20, (float) nx / (float) ny, aperture, dist_to_focus);
for (int j = ny - 1; j >= 0; j--) {
for (int i = 0; i < nx; i++) {
Vector col = new_vector(new_point(0, 0, 0));
/* Sampling ns times per pixel area */
for (int s = 0; s < ns; s++) {
/* Centered at the center point of the pixel, the pixel outward distance is (0.0, 1.0] */
float u = (float) (i + drand48()) / (float) nx;
float v = (float) (j + drand48()) / (float) ny;
/* Obtain the color value of the random sampling point in this pixel area */
Ray r = cam.get_ray(cam, u, v);
Vector p = r.point_at_parameter(r, 2.0);
/* Accumulate the color values of all ns random sample points of this point area */
col = col.add(col, color(r, &world, 0));
}
/* Divide the color accumulated value of all ns random sampling points of this pixel area by ns to obtain the average value */
col = col.div_scalar(col, (float) ns);
col = new_vector(new_point(sqrt(col.point.x), sqrt(col.point.y), sqrt(col.point.z)));
int ir = (int) (255.99 * col.point.x);
int ig = (int) (255.99 * col.point.y);
int ib = (int) (255.99 * col.point.z);
fprintf(fout, "%d %d %d\n", ir, ig, ib);
}
}
clock_t end_time = clock();
printf("Elapsed: %f seconds\n", (double) (end_time - start_time) / CLOCKS_PER_SEC);
fclose(fin);
fclose(fout);
for (int i = 0; i < sphere_count; i++) {
Sphere *sphere = (Sphere *) list[i]->inst;
free(sphere->mat_ptr.inst);
free(sphere);
}
return 0;
}