Add support for loading normals from a map
This commit is contained in:
		
							
								
								
									
										13010
									
								
								resources/head_nm.pnm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13010
									
								
								resources/head_nm.pnm
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										66
									
								
								resources/head_nm_tangent.pnm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								resources/head_nm_tangent.pnm
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										19
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -12,12 +12,13 @@ | ||||
| #define SIZE 1200 | ||||
| #define RESOURCE(NAME) "resources/" NAME | ||||
|  | ||||
| extern ShaderID perspective_lit_textured_id; | ||||
| extern ShaderID perspective_lit_coloured_id; | ||||
| extern ShaderID perspective_albedo_id; | ||||
| extern ShaderID orthographic_lit_textured_id; | ||||
| extern ShaderID orthographic_lit_coloured_id; | ||||
| extern ShaderID orthographic_albedo_id; | ||||
| extern ShaderID phong; | ||||
| extern ShaderID perspective_lit_textured; | ||||
| extern ShaderID perspective_lit_coloured; | ||||
| extern ShaderID perspective_albedo; | ||||
| extern ShaderID orthographic_lit_textured; | ||||
| extern ShaderID orthographic_lit_coloured; | ||||
| extern ShaderID orthographic_albedo; | ||||
|  | ||||
| enum { | ||||
|   TINY_EXIT_SUCCESS, | ||||
| @@ -40,7 +41,8 @@ int main(void) { | ||||
|     return TINY_EXIT_RENDER_INIT_FAILED; | ||||
|   } | ||||
|  | ||||
|   Model obj = load_obj_file(arena, RESOURCE("head.obj"), RESOURCE("head.pnm")); | ||||
|   Model obj = load_obj_file(arena, RESOURCE("head.obj"), RESOURCE("head.pnm"), | ||||
|                             RESOURCE("head_nm.pnm")); | ||||
|   if (IS_INVALID_MODEL(obj)) { | ||||
|     return TINY_EXIT_MODEL_LOAD_FAILED; | ||||
|   } | ||||
| @@ -48,8 +50,7 @@ int main(void) { | ||||
|   load_shaders(); | ||||
|  | ||||
|   clear_buffer(&(render.img), &bg); | ||||
|   render_model(&obj, &render, perspective_lit_textured_id, RENDER_TYPE_SHADED, | ||||
|                teal); | ||||
|   render_model(&obj, &render, phong, RENDER_TYPE_SHADED, teal); | ||||
|   save_image(&(render.img), "result.pam"); | ||||
|  | ||||
|   wapp_mem_arena_destroy(&arena); | ||||
|   | ||||
| @@ -30,7 +30,7 @@ internal void fill_triangle(Render *render, ShaderID shader, | ||||
|                             V3f vertices[TRIANGLE_VERTICES], | ||||
|                             V3f normals[TRIANGLE_VERTICES], | ||||
|                             V2f coordinates[TRIANGLE_VERTICES], Colour colour, | ||||
|                             Image *texture, RenderType type); | ||||
|                             const Model *model, RenderType type); | ||||
| internal TriangleBBox get_triangle_bbox(const Image *img, | ||||
|                                         V3f vertices[TRIANGLE_VERTICES]); | ||||
| internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, | ||||
| @@ -38,7 +38,8 @@ internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, | ||||
|                                     const V2i *ap); | ||||
| internal V3f get_viewport_vertex(const V3f *vertex, const Image *img); | ||||
|  | ||||
| Model load_obj_file(Arena *arena, const char *filename, const char *texture) { | ||||
| Model load_obj_file(Arena *arena, const char *filename, const char *texture, | ||||
|                     const char *normal_map) { | ||||
|   if (!arena) { | ||||
|     return INVALID_MODEL; | ||||
|   } | ||||
| @@ -111,6 +112,10 @@ Model load_obj_file(Arena *arena, const char *filename, const char *texture) { | ||||
|     model.texture = load_p6_image(arena, texture); | ||||
|   } | ||||
|  | ||||
|   if (normal_map) { | ||||
|     model.normal = load_p6_image(arena, normal_map); | ||||
|   } | ||||
|  | ||||
|   return model; | ||||
| } | ||||
|  | ||||
| @@ -176,8 +181,8 @@ internal void render_triangle(const Triangle *triangle, const Model *model, | ||||
|     } | ||||
|   } else if (render_type == RENDER_TYPE_FILLED || | ||||
|              render_type == RENDER_TYPE_SHADED) { | ||||
|     fill_triangle(render, shader, vertices, normals, coordinates, colour, | ||||
|                   model->texture, render_type); | ||||
|     fill_triangle(render, shader, vertices, normals, coordinates, colour, model, | ||||
|                   render_type); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -185,7 +190,7 @@ internal void fill_triangle(Render *render, ShaderID shader, | ||||
|                             V3f vertices[TRIANGLE_VERTICES], | ||||
|                             V3f normals[TRIANGLE_VERTICES], | ||||
|                             V2f coordinates[TRIANGLE_VERTICES], Colour colour, | ||||
|                             Image *texture, RenderType type) { | ||||
|                             const Model *model, RenderType type) { | ||||
|   Image *img = &(render->img); | ||||
|   Depth *depth = &(render->depth); | ||||
|   TriangleBBox bbox = get_triangle_bbox(img, vertices); | ||||
| @@ -243,8 +248,8 @@ internal void fill_triangle(Render *render, ShaderID shader, | ||||
|              coordinates[2].v * coords.z; | ||||
|       tex_coords = (V2f){tx_u, tx_v}; | ||||
|  | ||||
|       result = | ||||
|           run_fragment_shader(shader, normal, tex_coords, &colour, texture); | ||||
|       result = run_fragment_shader(shader, normal, tex_coords, &colour, | ||||
|                                    model->texture, model->normal); | ||||
|       if (DISCARD_FRAGMENT(result)) { | ||||
|         continue; | ||||
|       } | ||||
|   | ||||
| @@ -47,6 +47,7 @@ struct model { | ||||
|   LIST_TYPE(V2f) * texture_coordinates; | ||||
|   LIST_TYPE(Triangle) * triangles; | ||||
|   Image *texture; | ||||
|   Image *normal; | ||||
| }; | ||||
|  | ||||
| typedef struct render Render; | ||||
| @@ -55,7 +56,8 @@ struct render { | ||||
|   Depth depth; | ||||
| }; | ||||
|  | ||||
| Model load_obj_file(Arena *arena, const char *filename, const char *texture); | ||||
| Model load_obj_file(Arena *arena, const char *filename, const char *texture, | ||||
|                     const char *normal_map); | ||||
| bool init_render(Arena *arena, Render *render, u64 width, u64 height); | ||||
| void render_model(const Model *model, Render *render, ShaderID shader, | ||||
|                   RenderType render_type, Colour colour); | ||||
|   | ||||
| @@ -46,7 +46,8 @@ V3f run_vertex_shader(ShaderID shader, const V3f *vertex, | ||||
| } | ||||
|  | ||||
| FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, | ||||
|                                    const Colour *colour, const Image *texture) { | ||||
|                                    const Colour *colour, const Image *texture, | ||||
|                                    const Image *normal_map) { | ||||
|   if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) { | ||||
|     return DISCARDED_FRAGMENT; | ||||
|   } | ||||
| @@ -58,5 +59,6 @@ FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, | ||||
|     return DISCARDED_FRAGMENT; | ||||
|   } | ||||
|  | ||||
|   return fragment_func(shader_obj, normal, tex_coords, colour, texture); | ||||
|   return fragment_func(shader_obj, normal, tex_coords, colour, texture, | ||||
|                        normal_map); | ||||
| } | ||||
|   | ||||
| @@ -25,13 +25,15 @@ typedef V3f(VertexShader)(void *shader, const V3f *vertex, | ||||
|                           const Buffer *out_buf); | ||||
| typedef FragmentResult(FragmentShader)(void *shader, V3f normal, V2f tex_coords, | ||||
|                                        const Colour *colour, | ||||
|                                        const Image *texture); | ||||
|                                        const Image *texture, | ||||
|                                        const Image *normal_map); | ||||
|  | ||||
| ShaderID create_shader(void *shader, VertexShader *vertex, | ||||
|                        FragmentShader *fragment); | ||||
| V3f run_vertex_shader(ShaderID shader, const V3f *vertex, | ||||
|                       const Buffer *out_buf); | ||||
| FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, | ||||
|                                    const Colour *colour, const Image *texture); | ||||
|                                    const Colour *colour, const Image *texture, | ||||
|                                    const Image *normal_map); | ||||
|  | ||||
| #endif // SHADER_H | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| #include "img.h" | ||||
| #include "obj.h" | ||||
| #include "shader.h" | ||||
| #include "utils.h" | ||||
| #include "vec.h" | ||||
|  | ||||
| typedef struct shader Shader; | ||||
| @@ -13,12 +12,13 @@ struct shader { | ||||
| Shader perspective = {0}; | ||||
| Shader orthographic = {0}; | ||||
|  | ||||
| ShaderID perspective_lit_textured_id = {0}; | ||||
| ShaderID perspective_lit_coloured_id = {0}; | ||||
| ShaderID perspective_albedo_id = {0}; | ||||
| ShaderID orthographic_lit_textured_id = {0}; | ||||
| ShaderID orthographic_lit_coloured_id = {0}; | ||||
| ShaderID orthographic_albedo_id = {0}; | ||||
| ShaderID phong = {0}; | ||||
| ShaderID perspective_lit_textured = {0}; | ||||
| ShaderID perspective_lit_coloured = {0}; | ||||
| ShaderID perspective_albedo = {0}; | ||||
| ShaderID orthographic_lit_textured = {0}; | ||||
| ShaderID orthographic_lit_coloured = {0}; | ||||
| ShaderID orthographic_albedo = {0}; | ||||
|  | ||||
| V3f g_light_dir = {0.0f, 0.0f, 1.0f}; | ||||
| V3f g_eye = {0.2f, 0.1f, 0.75f}; | ||||
| @@ -28,18 +28,26 @@ M4x4f g_cam_matrix = mat4x4_identity; | ||||
|  | ||||
| internal V3f general_shader_vertex(void *shader, const V3f *vertex, | ||||
|                                    const Buffer *out_buf); | ||||
| internal FragmentResult phong_shader_fragment(void *shader, V3f normal, | ||||
|                                               V2f tex_coords, | ||||
|                                               const Colour *colour, | ||||
|                                               const Image *texture, | ||||
|                                               const Image *normal_map); | ||||
| internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, | ||||
|                                                      V2f tex_coords, | ||||
|                                                      const Colour *colour, | ||||
|                                                      const Image *texture); | ||||
|                                                      const Image *texture, | ||||
|                                                      const Image *normal_map); | ||||
| internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, | ||||
|                                                      V2f tex_coords, | ||||
|                                                      const Colour *colour, | ||||
|                                                      const Image *texture); | ||||
|                                                      const Image *texture, | ||||
|                                                      const Image *normal_map); | ||||
| internal FragmentResult albedo_shader_fragment(void *shader, V3f normal, | ||||
|                                                V2f tex_coords, | ||||
|                                                const Colour *colour, | ||||
|                                                const Image *texture); | ||||
|                                                const Image *texture, | ||||
|                                                const Image *normal_map); | ||||
| internal M4x4f get_projection_matrix(ProjectionType projection_type); | ||||
| internal f32 get_intensity(const V3f *normal); | ||||
|  | ||||
| @@ -54,18 +62,20 @@ void load_shaders(void) { | ||||
|   perspective.projection = perspective_projection; | ||||
|   orthographic.projection = orthographic_projection; | ||||
|  | ||||
|   perspective_lit_textured_id = create_shader( | ||||
|       &perspective, general_shader_vertex, lit_textured_shader_fragment); | ||||
|   perspective_lit_coloured_id = create_shader( | ||||
|       &perspective, general_shader_vertex, lit_coloured_shader_fragment); | ||||
|   perspective_albedo_id = create_shader(&perspective, general_shader_vertex, | ||||
|                                         albedo_shader_fragment); | ||||
|   orthographic_lit_textured_id = create_shader( | ||||
|   phong = | ||||
|       create_shader(&perspective, general_shader_vertex, phong_shader_fragment); | ||||
|   perspective_lit_textured = create_shader(&perspective, general_shader_vertex, | ||||
|                                            lit_textured_shader_fragment); | ||||
|   perspective_lit_coloured = create_shader(&perspective, general_shader_vertex, | ||||
|                                            lit_coloured_shader_fragment); | ||||
|   perspective_albedo = create_shader(&perspective, general_shader_vertex, | ||||
|                                      albedo_shader_fragment); | ||||
|   orthographic_lit_textured = create_shader( | ||||
|       &orthographic, general_shader_vertex, lit_textured_shader_fragment); | ||||
|   orthographic_lit_coloured_id = create_shader( | ||||
|   orthographic_lit_coloured = create_shader( | ||||
|       &orthographic, general_shader_vertex, lit_coloured_shader_fragment); | ||||
|   orthographic_albedo_id = create_shader(&orthographic, general_shader_vertex, | ||||
|                                          albedo_shader_fragment); | ||||
|   orthographic_albedo = create_shader(&orthographic, general_shader_vertex, | ||||
|                                       albedo_shader_fragment); | ||||
| } | ||||
|  | ||||
| internal V3f general_shader_vertex(void *shader, const V3f *vertex, | ||||
| @@ -82,10 +92,46 @@ internal V3f general_shader_vertex(void *shader, const V3f *vertex, | ||||
|   return project_vec4(vh); | ||||
| } | ||||
|  | ||||
| internal FragmentResult phong_shader_fragment(void *shader, V3f normal, | ||||
|                                               V2f tex_coords, | ||||
|                                               const Colour *colour, | ||||
|                                               const Image *texture, | ||||
|                                               const Image *normal_map) { | ||||
|   f32 intensity = get_intensity(&normal); | ||||
|   if (normal_map) { | ||||
|     u64 nm_x = tex_coords.u * normal_map->width; | ||||
|     u64 nm_y = (1.0f - tex_coords.v) * normal_map->height; | ||||
|  | ||||
|     Colour pixel = get_pixel(Colour, normal_map, nm_x, nm_y); | ||||
|     V3f norm = {.x = pixel.r, .y = pixel.g, .z = pixel.b}; | ||||
|     normalise_v3(norm); | ||||
|  | ||||
|     intensity = get_intensity(&norm); | ||||
|   } else { | ||||
|     intensity = get_intensity(&normal); | ||||
|   } | ||||
|  | ||||
|   Colour output; | ||||
|   if (texture) { | ||||
|     u64 tx_x = tex_coords.u * texture->width; | ||||
|     u64 tx_y = (1.0f - tex_coords.v) * texture->height; | ||||
|     output = get_pixel(Colour, texture, tx_x, tx_y); | ||||
|   } else { | ||||
|     output = *colour; | ||||
|   } | ||||
|  | ||||
|   output.r *= intensity; | ||||
|   output.g *= intensity; | ||||
|   output.b *= intensity; | ||||
|  | ||||
|   return (FragmentResult){.colour = output}; | ||||
| } | ||||
|  | ||||
| internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, | ||||
|                                                      V2f tex_coords, | ||||
|                                                      const Colour *colour, | ||||
|                                                      const Image *texture) { | ||||
|                                                      const Image *texture, | ||||
|                                                      const Image *normal_map) { | ||||
|   if (!texture) { | ||||
|     return DISCARDED_FRAGMENT; | ||||
|   } | ||||
| @@ -107,7 +153,8 @@ internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, | ||||
| internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, | ||||
|                                                      V2f tex_coords, | ||||
|                                                      const Colour *colour, | ||||
|                                                      const Image *texture) { | ||||
|                                                      const Image *texture, | ||||
|                                                      const Image *normal_map) { | ||||
|   f32 intensity = get_intensity(&normal); | ||||
|   Colour output = *colour; | ||||
|  | ||||
| @@ -121,7 +168,8 @@ internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, | ||||
| internal FragmentResult albedo_shader_fragment(void *shader, V3f normal, | ||||
|                                                V2f tex_coords, | ||||
|                                                const Colour *colour, | ||||
|                                                const Image *texture) { | ||||
|                                                const Image *texture, | ||||
|                                                const Image *normal_map) { | ||||
|   return (FragmentResult){.colour = *colour}; | ||||
| } | ||||
|  | ||||
| @@ -141,7 +189,7 @@ internal M4x4f get_projection_matrix(ProjectionType projection_type) { | ||||
| internal f32 get_intensity(const V3f *normal) { | ||||
|   f32 intensity = dot_v3((*normal), g_light_dir); | ||||
|   if (intensity < 0.0f) { | ||||
|     intensity = 0.01f; | ||||
|     intensity = 0.001f; | ||||
|   } | ||||
|  | ||||
|   return intensity; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user