153 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <defocus/camera.h>
 | |
| 
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
| #include <malloc.h>
 | |
| #endif
 | |
| 
 | |
| /* ********************************************************
 | |
|  *
 | |
|  * Ray Packet Functions
 | |
|  *
 | |
|  * ********************************************************/
 | |
| 
 | |
| DF_API void df_release_ray_packet(df_ray_packet *rays)
 | |
| {
 | |
|     free(rays->simd_mem);
 | |
|     free(rays->ray_uvs);
 | |
| 
 | |
|     memset(rays, 0, sizeof(*rays));
 | |
| }
 | |
| 
 | |
| /* ********************************************************
 | |
|  *
 | |
|  * Perspective Camrea
 | |
|  *
 | |
|  * ********************************************************/
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|     float focal_dist;
 | |
|     float lens_radius;
 | |
|     
 | |
|     /* Raster space, i.e. the space for which we generate rays */
 | |
|     float raster_width;
 | |
|     float raster_height;
 | |
| 
 | |
|     /* Image(=screen) space, i.e. the space in which we store pixels */
 | |
|     float image_width;
 | |
|     float image_height;
 | |
| 
 | |
|     df_m4 screen_to_raster;
 | |
|     df_m4 raster_to_screen;
 | |
|     df_m4 raster_to_camera;
 | |
| } df_perspective_camera;
 | |
| 
 | |
| static void pc_release(void *o) { df_perspective_camera *camera = o; }
 | |
| 
 | |
| static df_ray_packet pc_build_ray_packet(void *o)
 | |
| {
 | |
|     df_perspective_camera *camera = o;
 | |
|     df_ray_packet packet;
 | |
|     memset(&packet, 0, sizeof(packet));
 | |
| 
 | |
|     /* Generate 1 ray per pixel (ignore lens for now) */
 | |
|     size_t count = (size_t)camera->raster_width * (size_t)camera->raster_height;
 | |
| 
 | |
|     size_t alloc_count = count;
 | |
|     /* Round up to nearest multiple of 4, for SSE.
 | |
|      * Also satisfies 16 byte alignment (assuming simd_mem is 16 byte aligned)
 | |
|      * because 4 * sizeof(float) = 16.
 | |
|      */
 | |
|     if ((alloc_count % 4) != 0) {
 | |
|         alloc_count = ((alloc_count + 3) / 4) * 4;
 | |
|     }
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
|     packet.simd_mem = _aligned_malloc(sizeof(float) * alloc_count * 6, 16);
 | |
| #elif defined(_ISOC11_SOURCE) /* Feature test macro for GCC */
 | |
|     packet.simd_mem = aligned_alloc(16, sizeof(float) * alloc_count * 6);
 | |
| #else
 | |
|     /* Fall back to regular malloc and hope for the best */
 | |
|     packet.simd_mem = malloc(sizeof(float) * alloc_count * 6);
 | |
| #endif
 | |
| 
 | |
|     packet.base_x = packet.simd_mem;
 | |
|     packet.base_y = packet.base_x + alloc_count;
 | |
|     packet.base_z = packet.base_y + alloc_count;
 | |
|     packet.dir_x = packet.base_z + alloc_count;
 | |
|     packet.dir_y = packet.dir_x + alloc_count;
 | |
|     packet.dir_z = packet.dir_y + alloc_count;
 | |
| 
 | |
|     packet.ray_uvs = malloc(sizeof(df_v2) * count);
 | |
| 
 | |
|     packet.ray_count = count;
 | |
| 
 | |
|     size_t i = 0;
 | |
|     for (float y = 0; y < camera->raster_height; y += 1.f) {
 | |
|         for (float x = 0; x < camera->raster_width; x += 1.f) {
 | |
|             packet.base_x[i] = 0.f;
 | |
|             packet.base_y[i] = 0.f;
 | |
|             packet.base_z[i] = 0.f;
 | |
| 
 | |
|             df_v3 raster_p = {x, y, 0.f};
 | |
|             df_v3 camera_p = df_transform_v3(camera->raster_to_camera, raster_p);
 | |
|             df_v3 dir = df_normalize_v3(camera_p);
 | |
| 
 | |
|             packet.dir_x[i] = dir.x;
 | |
|             packet.dir_y[i] = dir.y;
 | |
|             packet.dir_z[i] = dir.z;
 | |
| 
 | |
|             df_v3 img_p = df_transform_v3(camera->raster_to_screen, raster_p);
 | |
|             packet.ray_uvs[i].u = img_p.x / camera->image_width;
 | |
|             packet.ray_uvs[i].v = img_p.y / camera->image_height;
 | |
| 
 | |
|             ++i;
 | |
|             assert(i <= count);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return packet;
 | |
| }
 | |
| 
 | |
| DF_API df_camera_i df_create_perspective_camera(float image_width,
 | |
|                                                 float image_height,
 | |
|                                                 float raster_width,
 | |
|                                                 float raster_height,
 | |
|                                                 float far_dist,
 | |
|                                                 float near_dist,
 | |
|                                                 float focal_dist,
 | |
|                                                 float lens_radius)
 | |
| {
 | |
|     df_perspective_camera *camera = malloc(sizeof(*camera));
 | |
| 
 | |
|     camera->screen_to_raster = df_scale(raster_width, raster_height, 1.f);
 | |
|     camera->screen_to_raster =
 | |
|         df_mul_m4(camera->screen_to_raster, df_scale(1.f / image_width, -1.f / image_height, 1.f));
 | |
|     camera->screen_to_raster = df_mul_m4(camera->screen_to_raster, df_translate(0.f, -image_height, 0.f));
 | |
|     camera->raster_to_screen = df_inverse_transform(camera->screen_to_raster);
 | |
| 
 | |
|     /* Perspective projection matrix */
 | |
|     df_m4 persp = {0.f};
 | |
|     DF_M4_AT(persp, 0, 0) = 1.f;
 | |
|     DF_M4_AT(persp, 1, 1) = 1.f;
 | |
|     DF_M4_AT(persp, 2, 2) = far_dist / (far_dist - near_dist);
 | |
|     DF_M4_AT(persp, 2, 3) = -1.f * far_dist * near_dist / (far_dist - near_dist);
 | |
|     DF_M4_AT(persp, 3, 2) = 1.f;
 | |
| 
 | |
|     camera->raster_to_camera = df_mul_m4(df_inverse(persp), camera->raster_to_screen);
 | |
| 
 | |
|     camera->focal_dist = focal_dist;
 | |
|     camera->lens_radius = lens_radius;
 | |
|     camera->raster_width = raster_width;
 | |
|     camera->raster_height = raster_height;
 | |
|     camera->image_width = image_width;
 | |
|     camera->image_height = image_height;
 | |
| 
 | |
|     df_camera_i iface = {.release = pc_release, .build_ray_packet = pc_build_ray_packet, .o = camera};
 | |
|     return iface;
 | |
| }
 |