Add support for loading normals from a map
This commit is contained in:
parent
1adac24148
commit
2e39780272
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 SIZE 1200
|
||||||
#define RESOURCE(NAME) "resources/" NAME
|
#define RESOURCE(NAME) "resources/" NAME
|
||||||
|
|
||||||
extern ShaderID perspective_lit_textured_id;
|
extern ShaderID phong;
|
||||||
extern ShaderID perspective_lit_coloured_id;
|
extern ShaderID perspective_lit_textured;
|
||||||
extern ShaderID perspective_albedo_id;
|
extern ShaderID perspective_lit_coloured;
|
||||||
extern ShaderID orthographic_lit_textured_id;
|
extern ShaderID perspective_albedo;
|
||||||
extern ShaderID orthographic_lit_coloured_id;
|
extern ShaderID orthographic_lit_textured;
|
||||||
extern ShaderID orthographic_albedo_id;
|
extern ShaderID orthographic_lit_coloured;
|
||||||
|
extern ShaderID orthographic_albedo;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TINY_EXIT_SUCCESS,
|
TINY_EXIT_SUCCESS,
|
||||||
@ -40,7 +41,8 @@ int main(void) {
|
|||||||
return TINY_EXIT_RENDER_INIT_FAILED;
|
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)) {
|
if (IS_INVALID_MODEL(obj)) {
|
||||||
return TINY_EXIT_MODEL_LOAD_FAILED;
|
return TINY_EXIT_MODEL_LOAD_FAILED;
|
||||||
}
|
}
|
||||||
@ -48,8 +50,7 @@ int main(void) {
|
|||||||
load_shaders();
|
load_shaders();
|
||||||
|
|
||||||
clear_buffer(&(render.img), &bg);
|
clear_buffer(&(render.img), &bg);
|
||||||
render_model(&obj, &render, perspective_lit_textured_id, RENDER_TYPE_SHADED,
|
render_model(&obj, &render, phong, RENDER_TYPE_SHADED, teal);
|
||||||
teal);
|
|
||||||
save_image(&(render.img), "result.pam");
|
save_image(&(render.img), "result.pam");
|
||||||
|
|
||||||
wapp_mem_arena_destroy(&arena);
|
wapp_mem_arena_destroy(&arena);
|
||||||
|
@ -30,7 +30,7 @@ internal void fill_triangle(Render *render, ShaderID shader,
|
|||||||
V3f vertices[TRIANGLE_VERTICES],
|
V3f vertices[TRIANGLE_VERTICES],
|
||||||
V3f normals[TRIANGLE_VERTICES],
|
V3f normals[TRIANGLE_VERTICES],
|
||||||
V2f coordinates[TRIANGLE_VERTICES], Colour colour,
|
V2f coordinates[TRIANGLE_VERTICES], Colour colour,
|
||||||
Image *texture, RenderType type);
|
const Model *model, RenderType type);
|
||||||
internal TriangleBBox get_triangle_bbox(const Image *img,
|
internal TriangleBBox get_triangle_bbox(const Image *img,
|
||||||
V3f vertices[TRIANGLE_VERTICES]);
|
V3f vertices[TRIANGLE_VERTICES]);
|
||||||
internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom,
|
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);
|
const V2i *ap);
|
||||||
internal V3f get_viewport_vertex(const V3f *vertex, const Image *img);
|
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) {
|
if (!arena) {
|
||||||
return INVALID_MODEL;
|
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);
|
model.texture = load_p6_image(arena, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (normal_map) {
|
||||||
|
model.normal = load_p6_image(arena, normal_map);
|
||||||
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,8 +181,8 @@ internal void render_triangle(const Triangle *triangle, const Model *model,
|
|||||||
}
|
}
|
||||||
} else if (render_type == RENDER_TYPE_FILLED ||
|
} else if (render_type == RENDER_TYPE_FILLED ||
|
||||||
render_type == RENDER_TYPE_SHADED) {
|
render_type == RENDER_TYPE_SHADED) {
|
||||||
fill_triangle(render, shader, vertices, normals, coordinates, colour,
|
fill_triangle(render, shader, vertices, normals, coordinates, colour, model,
|
||||||
model->texture, render_type);
|
render_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +190,7 @@ internal void fill_triangle(Render *render, ShaderID shader,
|
|||||||
V3f vertices[TRIANGLE_VERTICES],
|
V3f vertices[TRIANGLE_VERTICES],
|
||||||
V3f normals[TRIANGLE_VERTICES],
|
V3f normals[TRIANGLE_VERTICES],
|
||||||
V2f coordinates[TRIANGLE_VERTICES], Colour colour,
|
V2f coordinates[TRIANGLE_VERTICES], Colour colour,
|
||||||
Image *texture, RenderType type) {
|
const Model *model, RenderType type) {
|
||||||
Image *img = &(render->img);
|
Image *img = &(render->img);
|
||||||
Depth *depth = &(render->depth);
|
Depth *depth = &(render->depth);
|
||||||
TriangleBBox bbox = get_triangle_bbox(img, vertices);
|
TriangleBBox bbox = get_triangle_bbox(img, vertices);
|
||||||
@ -243,8 +248,8 @@ internal void fill_triangle(Render *render, ShaderID shader,
|
|||||||
coordinates[2].v * coords.z;
|
coordinates[2].v * coords.z;
|
||||||
tex_coords = (V2f){tx_u, tx_v};
|
tex_coords = (V2f){tx_u, tx_v};
|
||||||
|
|
||||||
result =
|
result = run_fragment_shader(shader, normal, tex_coords, &colour,
|
||||||
run_fragment_shader(shader, normal, tex_coords, &colour, texture);
|
model->texture, model->normal);
|
||||||
if (DISCARD_FRAGMENT(result)) {
|
if (DISCARD_FRAGMENT(result)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ struct model {
|
|||||||
LIST_TYPE(V2f) * texture_coordinates;
|
LIST_TYPE(V2f) * texture_coordinates;
|
||||||
LIST_TYPE(Triangle) * triangles;
|
LIST_TYPE(Triangle) * triangles;
|
||||||
Image *texture;
|
Image *texture;
|
||||||
|
Image *normal;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct render Render;
|
typedef struct render Render;
|
||||||
@ -55,7 +56,8 @@ struct render {
|
|||||||
Depth depth;
|
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);
|
bool init_render(Arena *arena, Render *render, u64 width, u64 height);
|
||||||
void render_model(const Model *model, Render *render, ShaderID shader,
|
void render_model(const Model *model, Render *render, ShaderID shader,
|
||||||
RenderType render_type, Colour colour);
|
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,
|
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) {
|
if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) {
|
||||||
return DISCARDED_FRAGMENT;
|
return DISCARDED_FRAGMENT;
|
||||||
}
|
}
|
||||||
@ -58,5 +59,6 @@ FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords,
|
|||||||
return DISCARDED_FRAGMENT;
|
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);
|
const Buffer *out_buf);
|
||||||
typedef FragmentResult(FragmentShader)(void *shader, V3f normal, V2f tex_coords,
|
typedef FragmentResult(FragmentShader)(void *shader, V3f normal, V2f tex_coords,
|
||||||
const Colour *colour,
|
const Colour *colour,
|
||||||
const Image *texture);
|
const Image *texture,
|
||||||
|
const Image *normal_map);
|
||||||
|
|
||||||
ShaderID create_shader(void *shader, VertexShader *vertex,
|
ShaderID create_shader(void *shader, VertexShader *vertex,
|
||||||
FragmentShader *fragment);
|
FragmentShader *fragment);
|
||||||
V3f run_vertex_shader(ShaderID shader, const V3f *vertex,
|
V3f run_vertex_shader(ShaderID shader, const V3f *vertex,
|
||||||
const Buffer *out_buf);
|
const Buffer *out_buf);
|
||||||
FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords,
|
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
|
#endif // SHADER_H
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "img.h"
|
#include "img.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
typedef struct shader Shader;
|
typedef struct shader Shader;
|
||||||
@ -13,12 +12,13 @@ struct shader {
|
|||||||
Shader perspective = {0};
|
Shader perspective = {0};
|
||||||
Shader orthographic = {0};
|
Shader orthographic = {0};
|
||||||
|
|
||||||
ShaderID perspective_lit_textured_id = {0};
|
ShaderID phong = {0};
|
||||||
ShaderID perspective_lit_coloured_id = {0};
|
ShaderID perspective_lit_textured = {0};
|
||||||
ShaderID perspective_albedo_id = {0};
|
ShaderID perspective_lit_coloured = {0};
|
||||||
ShaderID orthographic_lit_textured_id = {0};
|
ShaderID perspective_albedo = {0};
|
||||||
ShaderID orthographic_lit_coloured_id = {0};
|
ShaderID orthographic_lit_textured = {0};
|
||||||
ShaderID orthographic_albedo_id = {0};
|
ShaderID orthographic_lit_coloured = {0};
|
||||||
|
ShaderID orthographic_albedo = {0};
|
||||||
|
|
||||||
V3f g_light_dir = {0.0f, 0.0f, 1.0f};
|
V3f g_light_dir = {0.0f, 0.0f, 1.0f};
|
||||||
V3f g_eye = {0.2f, 0.1f, 0.75f};
|
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,
|
internal V3f general_shader_vertex(void *shader, const V3f *vertex,
|
||||||
const Buffer *out_buf);
|
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,
|
internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal,
|
||||||
V2f tex_coords,
|
V2f tex_coords,
|
||||||
const Colour *colour,
|
const Colour *colour,
|
||||||
const Image *texture);
|
const Image *texture,
|
||||||
|
const Image *normal_map);
|
||||||
internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal,
|
internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal,
|
||||||
V2f tex_coords,
|
V2f tex_coords,
|
||||||
const Colour *colour,
|
const Colour *colour,
|
||||||
const Image *texture);
|
const Image *texture,
|
||||||
|
const Image *normal_map);
|
||||||
internal FragmentResult albedo_shader_fragment(void *shader, V3f normal,
|
internal FragmentResult albedo_shader_fragment(void *shader, V3f normal,
|
||||||
V2f tex_coords,
|
V2f tex_coords,
|
||||||
const Colour *colour,
|
const Colour *colour,
|
||||||
const Image *texture);
|
const Image *texture,
|
||||||
|
const Image *normal_map);
|
||||||
internal M4x4f get_projection_matrix(ProjectionType projection_type);
|
internal M4x4f get_projection_matrix(ProjectionType projection_type);
|
||||||
internal f32 get_intensity(const V3f *normal);
|
internal f32 get_intensity(const V3f *normal);
|
||||||
|
|
||||||
@ -54,18 +62,20 @@ void load_shaders(void) {
|
|||||||
perspective.projection = perspective_projection;
|
perspective.projection = perspective_projection;
|
||||||
orthographic.projection = orthographic_projection;
|
orthographic.projection = orthographic_projection;
|
||||||
|
|
||||||
perspective_lit_textured_id = create_shader(
|
phong =
|
||||||
&perspective, general_shader_vertex, lit_textured_shader_fragment);
|
create_shader(&perspective, general_shader_vertex, phong_shader_fragment);
|
||||||
perspective_lit_coloured_id = create_shader(
|
perspective_lit_textured = create_shader(&perspective, general_shader_vertex,
|
||||||
&perspective, general_shader_vertex, lit_coloured_shader_fragment);
|
lit_textured_shader_fragment);
|
||||||
perspective_albedo_id = create_shader(&perspective, general_shader_vertex,
|
perspective_lit_coloured = create_shader(&perspective, general_shader_vertex,
|
||||||
albedo_shader_fragment);
|
lit_coloured_shader_fragment);
|
||||||
orthographic_lit_textured_id = create_shader(
|
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, 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, general_shader_vertex, lit_coloured_shader_fragment);
|
||||||
orthographic_albedo_id = create_shader(&orthographic, general_shader_vertex,
|
orthographic_albedo = create_shader(&orthographic, general_shader_vertex,
|
||||||
albedo_shader_fragment);
|
albedo_shader_fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal V3f general_shader_vertex(void *shader, const V3f *vertex,
|
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);
|
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,
|
internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal,
|
||||||
V2f tex_coords,
|
V2f tex_coords,
|
||||||
const Colour *colour,
|
const Colour *colour,
|
||||||
const Image *texture) {
|
const Image *texture,
|
||||||
|
const Image *normal_map) {
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
return DISCARDED_FRAGMENT;
|
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,
|
internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal,
|
||||||
V2f tex_coords,
|
V2f tex_coords,
|
||||||
const Colour *colour,
|
const Colour *colour,
|
||||||
const Image *texture) {
|
const Image *texture,
|
||||||
|
const Image *normal_map) {
|
||||||
f32 intensity = get_intensity(&normal);
|
f32 intensity = get_intensity(&normal);
|
||||||
Colour output = *colour;
|
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,
|
internal FragmentResult albedo_shader_fragment(void *shader, V3f normal,
|
||||||
V2f tex_coords,
|
V2f tex_coords,
|
||||||
const Colour *colour,
|
const Colour *colour,
|
||||||
const Image *texture) {
|
const Image *texture,
|
||||||
|
const Image *normal_map) {
|
||||||
return (FragmentResult){.colour = *colour};
|
return (FragmentResult){.colour = *colour};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +189,7 @@ internal M4x4f get_projection_matrix(ProjectionType projection_type) {
|
|||||||
internal f32 get_intensity(const V3f *normal) {
|
internal f32 get_intensity(const V3f *normal) {
|
||||||
f32 intensity = dot_v3((*normal), g_light_dir);
|
f32 intensity = dot_v3((*normal), g_light_dir);
|
||||||
if (intensity < 0.0f) {
|
if (intensity < 0.0f) {
|
||||||
intensity = 0.01f;
|
intensity = 0.001f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return intensity;
|
return intensity;
|
||||||
|
Loading…
Reference in New Issue
Block a user