sysy-data/hidden_functional/sy/38_light2d.sy

118 lines
2.3 KiB
Plaintext
Executable File

// reference: https://zhuanlan.zhihu.com/p/30748318
const int W = 192, H = 192, N = 24;
const float PI = 3.14159265359, TWO_PI = 6.28318530718;
const int MAX_STEP = 10;
const float MAX_DISTANCE = 2.0;
const float EPSILON = 1e-6;
const int RAND_MAX = 100000007 - 1;
int seed = 0;
int rand() {
seed = (seed * 19980130 + 23333) % 100000007;
if (seed < 0) seed = seed + 100000007;
return seed;
}
float my_fabs(float x) {
if (x > 0) return x;
return -x;
}
float my_sqrt(float x) {
float t = x / 8 + 0.5 + 2 * x / (4 + x);
int c = 10;
while (c) {
t = (t + x / t) / 2;
c = c - 1;
}
return t;
}
float p(float x) { return 3 * x - 4 * x * x * x; }
float my_sin_impl(float x) {
if (my_fabs(x) <= EPSILON) return x;
return p(my_sin_impl(x / 3.0));
}
float my_sin(float x) {
if (x > TWO_PI || x < -TWO_PI) {
int xx = x / TWO_PI;
x = x - xx * TWO_PI;
}
if (x > PI) x = x - TWO_PI;
if (x < -PI) x = x + TWO_PI;
return my_sin_impl(x);
}
float my_cos(float x) { return my_sin(x + PI / 2); }
float circle_sdf(float x, float y, float cx, float cy, float r) {
float ux = x - cx, uy = y - cy;
return my_sqrt(ux * ux + uy * uy) - r;
}
void scene(float x, float y, float ret[]) {
float sd0 = circle_sdf(x, y, 0.4, 0.4, 0.10),
sd1 = circle_sdf(x, y, 0.6, 0.6, 0.05);
if (sd0 < sd1) {
ret[0] = sd0;
ret[1] = 3.0;
} else {
ret[0] = sd1;
ret[1] = 0.0;
}
}
float trace(float ox, float oy, float dx, float dy) {
float t = 0.0;
int i = 0;
while (i < MAX_STEP && t < MAX_DISTANCE) {
float ret[2];
scene(ox + dx * t, oy + dy * t, ret);
if (ret[0] < EPSILON) return ret[1];
t = t + ret[0];
i = i + 1;
}
return 0.0;
}
float sample(float x, float y) {
float sum = 0.0;
int i = 0;
while (i < N) {
float rnd = rand();
float a = TWO_PI * (i + rnd / RAND_MAX) / N;
sum = sum + trace(x, y, my_cos(a), my_sin(a));
i = i + 1;
}
return sum / N;
}
void write_pgm() {
putch(80); putch(50); putch(10); // P2
putint(W); putch(32); putint(H); putch(32); putint(255); putch(10); // W H 255
int y = 0;
while (y < H) {
int x = 0;
while (x < W) {
float xx = x, yy = y;
int p = sample(xx / W, yy / H) * 255.0;
if (p > 255) p = 255;
putint(p);
putch(32);
x = x + 1;
}
putch(10);
y = y + 1;
}
}
int main() {
write_pgm();
return 0;
}