Skip to content

Commit d1a18b2

Browse files
committed
Initial commit
1 parent 18f89ba commit d1a18b2

File tree

272 files changed

+53285
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

272 files changed

+53285
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build/*
2+
3+
*.ppm

README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Albedo
2+
===
3+
4+
A community spectral CPU path tracer, made by the Graphics Programming Discord.
5+
6+
To-do List
7+
---
8+
9+
- Ray tracer
10+
- Embree or some sort of custom ray tracing kernel
11+
- BDPT, MIS, and much much more!
12+
- More and better sampling strategies
13+
- Simple lenses and film
14+
- Tonemapper
15+
- Post-process denoiser
16+
- Models and materials
17+
- Add support for loading 3D models
18+
- Use a better material system than the obj material system
19+
- Microfacet importance sampling
20+
- System
21+
- Some UI showing current render/progress
22+
- Output to .png instead of ppm

code/CIE.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
// begins at 390 nm, with step size of 5, up to 830
4+
float x_bar[] = { 3.77e-03, 9.38e-03, 2.21e-02, 4.74e-02, 8.95e-02, 1.45e-01, 2.04e-01, 2.49e-01, 2.92e-01, 3.23e-01, 3.48e-01, 3.42e-01, 3.22e-01, 2.83e-01, 2.49e-01, 2.22e-01, 1.81e-01, 1.29e-01, 8.18e-02, 4.60e-02, 2.08e-02, 7.10e-03, 2.46e-03, 3.65e-03, 1.56e-02, 4.32e-02, 7.96e-02, 1.27e-01, 1.82e-01, 2.41e-01, 3.10e-01, 3.80e-01, 4.49e-01, 5.28e-01, 6.13e-01, 7.02e-01, 7.97e-01, 8.85e-01, 9.64e-01, 1.05e00, 1.11e00, 1.14e00, 1.15e00, 1.13e00, 1.08e00, 1.01e00, 9.14e-01, 8.14e-01, 6.92e-01, 5.76e-01, 4.73e-01, 3.84e-01, 3.00e-01, 2.28e-01, 1.71e-01, 1.26e-01, 9.22e-02, 6.64e-02, 4.71e-02, 3.29e-02, 2.26e-02, 1.58e-02, 1.10e-02, 7.61e-03, 5.21e-03, 3.57e-03, 2.46e-03, 1.70e-03, 1.19e-03, 8.27e-04, 5.76e-04, 4.06e-04, 2.86e-04, 2.02e-04, 1.44e-04, 1.02e-04, 7.35e-05, 5.26e-05, 3.81e-05, 2.76e-05, 2.00e-05, 1.46e-05, 1.07e-05, 7.86e-06, 5.77e-06, 4.26e-06, 3.17e-06, 2.36e-06, 1.76e-06 };
5+
float y_bar[] = { 4.15e-04, 1.06e-03, 2.45e-03, 4.97e-03, 9.08e-03, 1.43e-02, 2.03e-02, 2.61e-02, 3.32e-02, 4.16e-02, 5.03e-02, 5.74e-02, 6.47e-02, 7.24e-02, 8.51e-02, 1.06e-01, 1.30e-01, 1.54e-01, 1.79e-01, 2.06e-01, 2.38e-01, 2.85e-01, 3.48e-01, 4.28e-01, 5.20e-01, 6.21e-01, 7.18e-01, 7.95e-01, 8.58e-01, 9.07e-01, 9.54e-01, 9.81e-01, 9.89e-01, 9.99e-01, 9.97e-01, 9.90e-01, 9.73e-01, 9.42e-01, 8.96e-01, 8.59e-01, 8.12e-01, 7.54e-01, 6.92e-01, 6.27e-01, 5.58e-01, 4.90e-01, 4.23e-01, 3.61e-01, 2.98e-01, 2.42e-01, 1.94e-01, 1.55e-01, 1.19e-01, 8.98e-02, 6.67e-02, 4.90e-02, 3.56e-02, 2.55e-02, 1.81e-02, 1.26e-02, 8.66e-03, 6.03e-03, 4.20e-03, 2.91e-03, 2.00e-03, 1.37e-03, 9.45e-04, 6.54e-04, 4.56e-04, 3.18e-04, 2.22e-04, 1.57e-04, 1.10e-04, 7.83e-05, 5.58e-05, 3.98e-05, 2.86e-05, 2.05e-05, 1.49e-05, 1.08e-05, 7.86e-06, 5.74e-06, 4.21e-06, 3.11e-06, 2.29e-06, 1.69e-06, 1.26e-06, 9.42e-07, 7.05e-07 };
6+
float z_bar[] = { 1.85e-02, 4.61e-02, 1.10e-01, 2.37e-01, 4.51e-01, 7.38e-01, 1.05e00, 1.31e00, 1.55e00, 1.75e00, 1.92e00, 1.92e00, 1.85e00, 1.66e00, 1.52e00, 1.43e00, 1.25e00, 9.99e-01, 7.55e-01, 5.62e-01, 4.10e-01, 3.11e-01, 2.38e-01, 1.72e-01, 1.18e-01, 8.28e-02, 5.65e-02, 3.75e-02, 2.44e-02, 1.57e-02, 9.85e-03, 6.13e-03, 3.79e-03, 2.33e-03, 1.43e-03, 8.82e-04, 5.45e-04, 3.39e-04, 2.12e-04, 1.34e-04, 8.49e-05, 5.46e-05, 3.55e-05, 2.33e-05, 1.55e-05, 1.05e-05, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00, 0.00e00 };
7+
8+
vec3 wavelength_to_xyz(float power, float lambda)
9+
{
10+
int i = (lambda - 390.f) / 5.f;
11+
return power * vec3(x_bar[i], y_bar[i], z_bar[i]);
12+
}
13+
14+
vec3 xyz_to_rgb(vec3 xyz)
15+
{
16+
vec3 rgb = mat3(
17+
3.2406, -0.9689, 0.0557,
18+
-1.5372, 1.8758, -0.2040,
19+
-0.4986, 0.0415, 1.0570) * xyz;
20+
21+
float correct = min(min(rgb.x, rgb.y), rgb.z);
22+
if (correct > 0.f)
23+
correct = 0;
24+
rgb = rgb - vec3(correct, correct, correct);
25+
return rgb;
26+
}

code/main.cpp

+285
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
#include <stdlib.h>
2+
#include <fstream>
3+
#include <vector>
4+
5+
#include "glm\glm.hpp"
6+
using glm::vec3;
7+
using namespace glm;
8+
9+
using namespace std;
10+
11+
#include "CIE.h"
12+
13+
const int IMAGE_WIDTH = 400;
14+
const int IMAGE_HEIGHT = 400;
15+
16+
const int NUM_SAMPLES = 50;
17+
18+
const float MAX_DIST = 8000;
19+
const float PI = 3.14159;
20+
21+
vec3 buffer[IMAGE_WIDTH][IMAGE_HEIGHT];
22+
23+
float nrand()
24+
{
25+
return (float)rand() / RAND_MAX;
26+
}
27+
28+
struct material
29+
{
30+
float mean = 500;
31+
float std = 100;
32+
33+
material(float m, float s)
34+
: mean(m), std(s)
35+
{}
36+
37+
material()
38+
: material(0, 0)
39+
{}
40+
};
41+
42+
struct light_path_node
43+
{
44+
vec3 normal;
45+
vec3 ray;
46+
material m;
47+
float weight;
48+
49+
light_path_node() {}
50+
};
51+
52+
// non-normalized bell curve
53+
float bell(float x, float m, float s)
54+
{
55+
return exp(-(x - m)*(x - m) / (2 * s*s));
56+
}
57+
58+
//-----------------------------------------------------------------------------
59+
// Intersection stuff
60+
//-----------------------------------------------------------------------------
61+
float rPlane(vec3 p, vec3 n, vec3 ray)
62+
{
63+
if (abs(dot(ray, n)) < 0.001)
64+
return MAX_DIST;
65+
float d = dot(p, n) / dot(ray, n);
66+
if (d < 0)
67+
return MAX_DIST;
68+
return d;
69+
}
70+
float rSphere(vec3 p, float rad, vec3 ray)
71+
{
72+
if (dot(p, ray) < 0)
73+
return MAX_DIST;
74+
vec3 q = dot(p, ray) * ray;
75+
float l = length(p - q);
76+
if (l > rad)
77+
return MAX_DIST;
78+
79+
float m = length(q);
80+
float ret = m - sqrt(rad*rad - l*l);
81+
if (ret < 0)
82+
return MAX_DIST;
83+
return ret;
84+
}
85+
86+
float BRDF(float lambda, vec3 p, vec3 inDir, vec3 outDir)
87+
{
88+
float ret;
89+
if (abs(p.x + 5) < 0.1)
90+
ret = 0.8 * bell(lambda, 600, 20);
91+
else if (abs(p.x - 5) < 0.1)
92+
ret = 0.8 * bell(lambda, 550, 20);
93+
else
94+
ret = 0.8;
95+
96+
return ret / PI;
97+
}
98+
float emmision(vec3 p)
99+
{
100+
if (abs(p.y - 5) < 0.1 && length(vec2(p.x, p.z + 15)) < 1.414)
101+
{
102+
return 50.f;
103+
}
104+
return 0.f;
105+
}
106+
107+
float intersect(vec3 o, vec3 r, vec3& normal)
108+
{
109+
float ret = MAX_DIST;
110+
float q;
111+
112+
q = rPlane(vec3(0, -5, 0) - o, vec3(0, 1, 0), r);
113+
if (q < ret)
114+
{
115+
ret = q;
116+
normal = vec3(0, 1, 0);
117+
}
118+
q = rPlane(vec3(0, 5, 0) - o, vec3(0, -1, 0), r);
119+
if (q < ret)
120+
{
121+
ret = q;
122+
normal = vec3(0, -1, 0);
123+
}
124+
125+
126+
q = rPlane(vec3(5, 0, 0) - o, vec3(-1, 0, 0), r);
127+
if (q < ret)
128+
{
129+
ret = q;
130+
normal = vec3(-1, 0, 0);
131+
}
132+
q = rPlane(vec3(-5, 0, 0) - o, vec3(1, 0, 0), r);
133+
if (q < ret)
134+
{
135+
ret = q;
136+
normal = vec3(1, 0, 0);
137+
}
138+
139+
140+
q = rPlane(vec3(0, 0, -20) - o, vec3(0, 0, 1), r);
141+
if (q < ret)
142+
{
143+
ret = q;
144+
normal = vec3(0, 0, 1);
145+
}
146+
q = rPlane(vec3(0, 0, 1) - o, vec3(0, 0, -1), r);
147+
if (q < ret)
148+
{
149+
ret = q;
150+
normal = vec3(0, 0, -1);
151+
}
152+
153+
154+
q = rSphere(vec3(-2, -3, -17) - o, 2, r);
155+
if (q < ret)
156+
{
157+
ret = q;
158+
normal = normalize(r * q + o - vec3(-2, -3, -17));
159+
}
160+
161+
return ret;
162+
}
163+
164+
//-----------------------------------------------------------------------------
165+
// Coloring and ray tracing stuff
166+
//-----------------------------------------------------------------------------
167+
vec3 getTangent(vec3 norm)
168+
{
169+
vec3 tangent;
170+
vec3 c1 = cross(norm, vec3(0, 0, 1));
171+
vec3 c2 = cross(norm, vec3(0, 1, 0));
172+
if (dot(c1, c1) > dot(c2, c2))
173+
tangent = c1;
174+
else
175+
tangent = c2;
176+
return tangent;
177+
}
178+
vec3 randCosineWeightedRay(vec3 norm)
179+
{
180+
float rx = 1, rz = 1;
181+
while (rx*rx + rz*rz >= 1)
182+
{
183+
rx = 2 * nrand() - 1.0f;
184+
rz = 2 * nrand() - 1.0f;
185+
}
186+
float ry = sqrt(1 - rx*rx - rz*rz);
187+
188+
vec3 tangent = getTangent(norm);
189+
vec3 bitangent = cross(norm, tangent);
190+
191+
vec3 castRay = normalize(tangent*rx + bitangent*rz + norm*ry);
192+
return castRay;
193+
}
194+
195+
vec3 radiance(vec3 o, vec3 ray)
196+
{
197+
// Decide a-priori what the wavelength of this sample will be
198+
// Note: this only works if all lights output the exact same spectrums
199+
float lambda = nrand() * 225 + 425;
200+
201+
float accum = 1;
202+
while(true)
203+
{
204+
// Russian Roulette
205+
float r = nrand();
206+
float russian = min(1.f, accum);
207+
if (russian < r)
208+
break;
209+
210+
vec3 normal;
211+
float dist = intersect(o, ray, normal) - 0.001;
212+
vec3 p = o + ray * dist;
213+
214+
if (dist > 100)
215+
return vec3(0, 0, 0);
216+
217+
vec3 emm = emmision(p) * xyz_to_rgb(wavelength_to_xyz(1.f, lambda));
218+
if (dot(emm, emm) > 0.001)
219+
return accum * emm / russian;
220+
221+
vec3 nextRay = randCosineWeightedRay(normal);
222+
float pdf = dot(nextRay, normal) / PI;
223+
224+
accum *= BRDF(lambda, p, nextRay, -ray) * max(0.f, dot(normal, nextRay)) / (pdf * russian);
225+
226+
o = p;
227+
ray = nextRay;
228+
}
229+
230+
return vec3();
231+
}
232+
233+
int main()
234+
{
235+
for (int i = 0; i < NUM_SAMPLES; ++i)
236+
{
237+
printf("Iteration %d\n", i);
238+
for (int x = 0; x < IMAGE_WIDTH; ++x)
239+
{
240+
for (int y = 0; y < IMAGE_HEIGHT; ++y)
241+
{
242+
vec3 ray = vec3((float)(x - IMAGE_WIDTH / 2) / IMAGE_WIDTH, (float)(y - IMAGE_HEIGHT / 2) / IMAGE_HEIGHT, -1.0);
243+
ray = normalize(ray);
244+
245+
//buffer[x][y] = vec3((float)x / IMAGE_WIDTH, (float)y / IMAGE_HEIGHT, 0);
246+
buffer[x][y] += radiance(vec3(0, -1, 0), ray) / (float)NUM_SAMPLES;
247+
}
248+
}
249+
}
250+
251+
// World's worst tonemapping
252+
for (int x = 0; x < IMAGE_WIDTH; ++x)
253+
{
254+
for (int y = 0; y < IMAGE_HEIGHT; ++y)
255+
{
256+
buffer[x][y] /= buffer[x][y] + vec3(1, 1, 1);
257+
}
258+
}
259+
260+
ofstream file("image.ppm");
261+
file << "P3 " << IMAGE_WIDTH << " " << IMAGE_HEIGHT << " 255" << endl;
262+
263+
for (int y = IMAGE_HEIGHT - 1; y >= 0; --y)
264+
{
265+
for (int x = 0; x < IMAGE_WIDTH; ++x)
266+
{
267+
if ((int)(buffer[x][y].x * 255) == 0x80000000 ||
268+
(int)(buffer[x][y].y * 255) == 0x80000000 ||
269+
(int)(buffer[x][y].z * 255) == 0x80000000)
270+
{
271+
//cout << "a divide by zero happened" << endl;
272+
/*for (int i = 0; i < 50; ++i)
273+
file << "\n";*/
274+
file << 0 << " " << 0 << " " << 0 << " ";
275+
}
276+
else
277+
file << (int)(buffer[x][y].x * 255) << " " << (int)(buffer[x][y].y * 255) << " " << (int)(buffer[x][y].z * 255) << " ";
278+
}
279+
}
280+
281+
file.close();
282+
283+
printf("Finished\n");
284+
//getchar();
285+
}

compile.bat

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@echo off
2+
3+
set FLAGS="/EHsc" "/O2"
4+
set LIBRARIES=
5+
6+
mkdir build
7+
pushd build
8+
cl -Zi ../code/main.cpp %FLAGS% /I ../include %LIBRARIES% /link /LIBPATH:../lib
9+
popd

compile_and_run.bat

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@echo off
2+
3+
echo ===== CLEANING =====
4+
rmdir build /s /q
5+
6+
echo ===== COMPILING =====
7+
call compile.bat
8+
9+
echo ===== RUNNING =====
10+
call run.bat

0 commit comments

Comments
 (0)