From c65dc6eab16410deb741797918df58348d7a0d04 Mon Sep 17 00:00:00 2001 From: Mistivia Date: Sun, 8 Jun 2025 16:44:27 +0800 Subject: basic ray tracing --- main.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 12 deletions(-) diff --git a/main.c b/main.c index d5a4773..b25c212 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,10 @@ +#include +#include #include #include #include #include +#include typedef enum { kRetSucc, @@ -14,6 +17,17 @@ typedef struct { float *buffer; } Picture; +typedef struct { + float r; + float g; + float b; +} Color; + +typedef struct { + int x; + int y; +} Vec2i; + Picture new_picture(int width, int height) { Picture ret; @@ -27,11 +41,11 @@ void delete_picture(Picture pic) { free(pic.buffer); } -void set_pixel(Picture pic, int x, int y, float r, float g, float b) { - int idx = y * pic.width * 3 + x * 3; - pic.buffer[idx] = b; - pic.buffer[idx+1] = g; - pic.buffer[idx+2] = r; +void set_pixel(Picture pic, Vec2i pos, Color c) { + int idx = pos.y * pic.width * 3 + pos.x * 3; + pic.buffer[idx] = c.b; + pic.buffer[idx+1] = c.g; + pic.buffer[idx+2] = c.r; } Ret fwrite_word16le(FILE* fp, uint16_t x) { @@ -128,14 +142,127 @@ end: return ret; } +typedef struct { + float x; + float y; + float z; +} Vec3f; + +Vec3f screen_proj(int width, int height, Vec2i sp) { + Vec3f ret; + float maxlen = width > height ? width : height; + ret.z = 1; + ret.x = (sp.x - width / 2.0) / maxlen; + ret.y = (-sp.y + height / 2.0) / maxlen; + return ret; +} + +Color icolor(int r, int g, int b) { + return (Color){.r = r/255.0, .g = g/255.0, .b = b/255.0}; +} + +typedef struct { + Vec3f center; + float r; + Color color; +} Ball; + +Ball balls[] = { + { + .center = {.x = 0, .y = -1, .z = 3}, + .r = 1, + }, + { + .center = {.x = 2, .y = 0, .z = 4}, + .r = 1, + }, + { + .center = {.x = -2, .y = 0, .z = 4}, + .r = 1, + }, +}; + + +Color gBackgroupColor = {0,0,0}; + +void init_color() { + balls[0].color = icolor(0x95, 0xe1, 0xe3); + balls[1].color = icolor(0xfc, 0xe3, 0x8a); + balls[2].color = icolor(0xf3, 0x81, 0x81); + gBackgroupColor = icolor(0xea, 0xea, 0xea); +} + +Vec3f vec3f_sub(Vec3f lhs, Vec3f rhs) { + return (Vec3f){ + .x = lhs.x - rhs.x, + .y = lhs.y - rhs.y, + .z = lhs.z - rhs.z, + }; +} + +float vec3f_dot(Vec3f lhs, Vec3f rhs) { + return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; +} + +float ball_intersect(Vec3f start, Vec3f ray, Ball *ball) { + Vec3f sc = vec3f_sub(start, ball->center); + float a = vec3f_dot(ray, ray); + float b = 2 * vec3f_dot(sc, ray); + float c = vec3f_dot(sc, sc) - ball->r * ball->r; + float delta = b*b - 4*a*c; + if (delta < 0) { + return -1; + } + float t1 = (-b + sqrt(delta)) / 2*a; + float t2 = (-b - sqrt(delta)) / 2*a; + return t1 < t2 ? t1 : t2; +} + +Color calc_color(Vec3f v) { + Vec3f start = {.x = 0, .y = 0, .z = 0}; + float tmin = 0.1; + float tmax = FLT_MAX; + + int nearest_idx = -1; + float t_nearest = FLT_MAX; + for (int i = 0; i < sizeof(balls) / sizeof(Ball); i++) { + float t = ball_intersect(start, v, &balls[i]); + // printf("t:%f\n", t); + if (t < t_nearest && t < tmax && t > tmin) { + t_nearest = t; + nearest_idx = i; + } + } + if (nearest_idx >= 0) { + return balls[nearest_idx].color; + } else { + return gBackgroupColor; + } +} + +void normalize_picture(Picture pic) { + float maxval = 0; + for (size_t i = 0; i < pic.width * pic.height * 3; i++) { + float val = pic.buffer[i]; + if (val < 0) val = 0; + if (val > maxval) maxval = val; + } + if (maxval < 1.0) return; + for (size_t i = 0; i < pic.width * pic.height * 3; i++) { + pic.buffer[i] = pic.buffer[i] / maxval; + } +} + int main() { - Picture pic = new_picture(1600, 900); - for (int i = 0; i < 900; i++) { - for (int j = 0; j < 1600; j++) { - float r = (i + j) % 177 / 177.0; - float g = (i + j) % 71 / 71.0; - float b = (i + j) % 337 / 337.0; - set_pixel(pic, j, i, r, g, b); + init_color(); + int img_w = 1280; + int img_h = 720; + Picture pic = new_picture(img_w, img_h); + for (int x = 0; x < img_w; x++) { + for (int y = 0; y < img_h; y++) { + Vec2i screen_pos = {x, y}; + Vec3f v = screen_proj(img_w, img_h, screen_pos); + set_pixel(pic, screen_pos, calc_color(v)); } } writeBMP("test.bmp", pic); -- cgit v1.0