Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- typedef struct doge_sphere
- {
- struct doge_sphere *next;
- doge_vec3_t pos;
- float radius;
- doge_vec3_t color;
- }doge_sphere_t;
- typedef struct doge_ray
- {
- doge_vec3_t start;
- doge_vec3_t dir;
- }doge_ray_t;
- typedef struct doge_point_light
- {
- doge_vec3_t pos;
- struct doge_point_light *next;
- }doge_point_light_t;
- typedef struct doge_world
- {
- doge_point_light_t *light_head;
- doge_sphere_t *sphere_head;
- }doge_world_t;
- typedef struct doge_camera
- {
- doge_vec3_t pos;
- }doge_camera_t;
- typedef struct doge_hit_point
- {
- doge_vec3_t pos;
- doge_vec3_t normal;
- doge_vec3_t color;
- float dist;
- }doge_hit_point_t;
- int doge_sphere_hit_by_ray(doge_sphere_t sphere, doge_ray_t ray, doge_hit_point_t *hit)
- {
- hit->color = doge_vec3_create(0, 0, 0);
- hit->dist = 1e8;
- hit->normal = doge_vec3_create(0, 0, 0);
- hit->pos = doge_vec3_create(0, 0, 0);
- doge_vec3_t l = doge_vec3_sub(sphere.pos, ray.start);
- float tca = doge_vec3_dot(l, ray.dir);
- if(tca < 0)
- {
- return 0;
- }
- float d = (float)sqrt(doge_vec3_len_sq(l) - tca * tca);
- if(d > sphere.radius)
- {
- return 0;
- }
- float thc = (float)sqrt(sphere.radius * sphere.radius - d * d);
- float t0 = tca - thc;
- float t1 = tca + thc;
- if (t1 < t0)
- hit->dist = t1;
- else
- hit->dist = t0;
- hit->pos = doge_vec3_add(ray.start, doge_vec3_scaled(ray.dir, hit->dist));
- hit->color = sphere.color;
- hit->normal = doge_vec3_normalized(doge_vec3_sub(hit->pos, sphere.pos));
- return 1;
- }
- doge_vec3_t doge_ray_trace(doge_ray_t ray, doge_world_t *world)
- {
- doge_hit_point_t hit_point;
- doge_hit_point_t best_hit;
- doge_sphere_t *spheres = world->sphere_head;
- doge_sphere_t *sphere_hit = NULL;
- best_hit.color = doge_vec3_create(1,1,1);
- best_hit.dist = 1e8;
- while(spheres)
- {
- if(doge_sphere_hit_by_ray(*spheres, ray, &hit_point))
- {
- if(hit_point.dist < best_hit.dist)
- {
- best_hit = hit_point;
- sphere_hit = spheres;
- }
- }
- spheres = spheres->next;
- }
- if(!sphere_hit)
- return best_hit.color;
- int inside = 0;
- if(doge_vec3_dot(ray.dir, best_hit.normal) > 0)
- inside = 1;
- float bias = 1e-4;
- // lambert diffuse
- doge_point_light_t *light = world->light_head;
- spheres = world->sphere_head;
- float lambert = 0;
- while (light)
- {
- doge_vec3_t direction = doge_vec3_normalized(doge_vec3_sub(light->pos, best_hit.pos));
- doge_ray_t shadow_ray = doge_ray_create(best_hit.pos, direction);
- int is_in_shadow = 0;
- while (spheres)
- {
- if(doge_sphere_hit_by_ray(*spheres, shadow_ray, &hit_point))
- {
- is_in_shadow = 1;
- break;
- }
- spheres = spheres->next;
- }
- if (!is_in_shadow)
- {
- float max = 0;
- float dot = doge_vec3_dot(direction, best_hit.normal);
- if(dot >= 0)
- {
- max = dot;
- }
- lambert += max;
- }
- light = light->next;
- }
- best_hit.color = doge_vec3_scaled(best_hit.color, lambert);
- return best_hit.color;
- }
- // in main loop
- float fov_y = 60.0f;
- float vertical_size = (float)tan(3.1415296 / 180 * fov_y / 2);
- float horizontal_size = current_window.aspect_ratio * vertical_size;
- for(int y = 0; y < current_window.height; y++)
- {
- for(int x = 0; x < current_window.width; x++)
- {
- float cam_space_x = (2 * (x / (float)current_window.width) - 1) * horizontal_size;
- float cam_space_y = (-2 * (y / (float)current_window.height) + 1) * vertical_size;
- doge_vec3_t point = doge_vec3_create(cam_space_x, cam_space_y, 1);
- doge_vec3_t direction = doge_vec3_normalized(point);
- doge_ray_t ray = doge_ray_create(cam.pos, direction);
- doge_vec3_t color = doge_ray_trace(ray, &world);
- //clamp colors
- if(color.x > 1)
- color.x = 1;
- if(color.y > 1)
- color.y = 1;
- if(color.z > 1)
- color.z = 1;
- doge_window_put_pixel(¤t_window, x, y, (unsigned char)(color.x * 255), (unsigned char)(color.y * 255), (unsigned char)(color.z * 255));
- }
- }
Add Comment
Please, Sign In to add comment