Compare commits
No commits in common. "95895750e836028a63ec5375dd06742a8d901df5" and "c7398644890c3fe3e8f796cd0dba567759d7ac6f" have entirely different histories.
95895750e8
...
c739864489
@ -1,7 +1,6 @@
|
|||||||
#ifndef CONSTANTS_H
|
#ifndef CONSTANTS_H
|
||||||
#define CONSTANTS_H
|
#define CONSTANTS_H
|
||||||
|
|
||||||
#define DEPTH_MAX 255
|
|
||||||
#define TRIANGLE_VERTICES 3
|
#define TRIANGLE_VERTICES 3
|
||||||
|
|
||||||
#endif // CONSTANTS_H
|
#endif // CONSTANTS_H
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
TYPE *buf; \
|
TYPE *buf; \
|
||||||
} NAME
|
} NAME
|
||||||
|
|
||||||
#define BUF_SIZE(BUF) sizeof(*((BUF)->buf))
|
|
||||||
|
|
||||||
typedef struct colour Colour;
|
typedef struct colour Colour;
|
||||||
struct colour {
|
struct colour {
|
||||||
u8 r;
|
u8 r;
|
||||||
@ -26,10 +24,14 @@ BUF_TYPE(void, Buffer);
|
|||||||
BUF_TYPE(Colour, Image);
|
BUF_TYPE(Colour, Image);
|
||||||
BUF_TYPE(f32, Depth);
|
BUF_TYPE(f32, Depth);
|
||||||
|
|
||||||
#define init_buffer(ARENA, BUF) (_init_buffer(ARENA, (Buffer *)BUF, BUF_SIZE(BUF)))
|
#define init_buffer(ARENA, BUF) \
|
||||||
#define get_pixel(TYPE, BUF, X, Y) (*((TYPE *)(_get_pixel((Buffer *)BUF, X, Y, BUF_SIZE(BUF)))))
|
_init_buffer(ARENA, (Buffer *)BUF, sizeof(*((BUF)->buf)))
|
||||||
#define set_pixel(BUF, X, Y, VAL_PTR) (_set_pixel((Buffer *)BUF, X, Y, VAL_PTR, BUF_SIZE(BUF)))
|
#define get_pixel(TYPE, BUF, X, Y) \
|
||||||
#define clear_buffer(BUF, VAL_PTR) (_clear_buffer((Buffer *)BUF, VAL_PTR, BUF_SIZE(BUF)))
|
(*((TYPE *)(_get_pixel((Buffer *)BUF, X, Y, sizeof(*((BUF)->buf))))))
|
||||||
|
#define set_pixel(BUF, X, Y, VAL_PTR) \
|
||||||
|
_set_pixel((Buffer *)BUF, X, Y, VAL_PTR, sizeof(*((BUF)->buf)))
|
||||||
|
#define clear_buffer(BUF, VAL_PTR) \
|
||||||
|
_clear_buffer((Buffer *)BUF, VAL_PTR, sizeof(*((BUF)->buf)))
|
||||||
|
|
||||||
bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size);
|
bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size);
|
||||||
u8 *_get_pixel(Buffer *buffer, u64 x, u64 y, u64 base_size);
|
u8 *_get_pixel(Buffer *buffer, u64 x, u64 y, u64 base_size);
|
||||||
|
14
src/main.c
14
src/main.c
@ -5,7 +5,6 @@
|
|||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "shaders.h"
|
#include "shaders.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
#include "vec.h"
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -42,7 +41,7 @@ i32 main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TinyArgs args = parse_args(arena, argc, argv);
|
TinyArgs args = parse_args(arena, argc, argv);
|
||||||
i32 output = tinyrenderer(arena, args);
|
i32 output = tinyrenderer(arena, args);
|
||||||
|
|
||||||
wapp_mem_arena_destroy(&arena);
|
wapp_mem_arena_destroy(&arena);
|
||||||
|
|
||||||
@ -80,9 +79,8 @@ internal TinyArgs parse_args(Arena *arena, int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal i32 tinyrenderer(Arena *arena, TinyArgs args) {
|
internal i32 tinyrenderer(Arena *arena, TinyArgs args) {
|
||||||
Colour bg = {.r = 42, .g = 45, .b = 52, .a = 255};
|
Colour bg = {.r = 42, .g = 45, .b = 52, .a = 255};
|
||||||
Colour main_colour = {.r = 14, .g = 156, .b = 208, .a = 255};
|
Colour main_colour = {.r = 14, .g = 156, .b = 208, .a = 255};
|
||||||
|
|
||||||
Render render;
|
Render render;
|
||||||
if (!init_render(arena, &render, IMAGE_DIMENSION, IMAGE_DIMENSION)) {
|
if (!init_render(arena, &render, IMAGE_DIMENSION, IMAGE_DIMENSION)) {
|
||||||
return TINY_EXIT_RENDER_INIT_FAILED;
|
return TINY_EXIT_RENDER_INIT_FAILED;
|
||||||
@ -90,18 +88,16 @@ internal i32 tinyrenderer(Arena *arena, TinyArgs args) {
|
|||||||
|
|
||||||
const char *diffuse = args.diffuse.length > 0 ? args.diffuse.str : NULL;
|
const char *diffuse = args.diffuse.length > 0 ? args.diffuse.str : NULL;
|
||||||
const char *tangent = args.tangent.length > 0 ? args.tangent.str : NULL;
|
const char *tangent = args.tangent.length > 0 ? args.tangent.str : NULL;
|
||||||
|
|
||||||
Model obj = load_obj_file(arena, args.obj.str, diffuse, tangent);
|
Model obj = load_obj_file(arena, args.obj.str, diffuse, tangent);
|
||||||
if (IS_INVALID_MODEL(obj)) {
|
if (IS_INVALID_MODEL(obj)) {
|
||||||
return TINY_EXIT_MODEL_LOAD_FAILED;
|
return TINY_EXIT_MODEL_LOAD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
load_shaders(viewport(0, 0, IMAGE_DIMENSION, IMAGE_DIMENSION));
|
load_shaders();
|
||||||
|
|
||||||
clear_buffer(&(render.img), &bg);
|
clear_buffer(&(render.img), &bg);
|
||||||
|
render_model(&obj, &render, perspective_diffuse, RENDER_TYPE_SHADED,
|
||||||
// render_model(&obj, &render, depth, RENDER_TYPE_SHADED, main_colour);
|
main_colour);
|
||||||
render_model(&obj, &render, perspective_diffuse, RENDER_TYPE_SHADED, main_colour);
|
|
||||||
save_image(&(render.img), "result.pam");
|
save_image(&(render.img), "result.pam");
|
||||||
|
|
||||||
return TINY_EXIT_SUCCESS;
|
return TINY_EXIT_SUCCESS;
|
||||||
|
@ -17,10 +17,10 @@ Model load_obj_file(Arena *arena, const char *filename, const char *diffuse,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Model model = (Model){
|
Model model = (Model){
|
||||||
.vertices = list_create(V3f, arena),
|
.vertices = list_create(V3f, arena),
|
||||||
.normals = list_create(V3f, arena),
|
.normals = list_create(V3f, arena),
|
||||||
.texture_coordinates = list_create(V2f, arena),
|
.texture_coordinates = list_create(V2f, arena),
|
||||||
.triangles = list_create(Triangle, arena),
|
.triangles = list_create(Triangle, arena),
|
||||||
};
|
};
|
||||||
if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) ||
|
if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) ||
|
||||||
!(model.triangles)) {
|
!(model.triangles)) {
|
||||||
@ -59,20 +59,18 @@ Model load_obj_file(Arena *arena, const char *filename, const char *diffuse,
|
|||||||
coord.v = 1.0f - v;
|
coord.v = 1.0f - v;
|
||||||
list_append(V2f, arena, model.texture_coordinates, coord);
|
list_append(V2f, arena, model.texture_coordinates, coord);
|
||||||
} else if (strncmp(identifier, "f", 8) == 0) {
|
} else if (strncmp(identifier, "f", 8) == 0) {
|
||||||
sscanf(line + 2, "%lu/%lu/%lu %lu/%lu/%lu %lu/%lu/%lu",
|
sscanf(line + 2, "%lu/%lu/%lu %lu/%lu/%lu %lu/%lu/%lu", &fp0, &tx0, &vn0,
|
||||||
&fp0, &tx0, &vn0,
|
&fp1, &tx1, &vn1, &fp2, &tx2, &vn2);
|
||||||
&fp1, &tx1, &vn1,
|
|
||||||
&fp2, &tx2, &vn2);
|
|
||||||
// OBJ indices start from 1
|
// OBJ indices start from 1
|
||||||
triangle.p0 = fp0 - 1;
|
triangle.p0 = fp0 - 1;
|
||||||
triangle.p1 = fp1 - 1;
|
triangle.p1 = fp1 - 1;
|
||||||
triangle.p2 = fp2 - 1;
|
triangle.p2 = fp2 - 1;
|
||||||
triangle.tx0 = tx0 - 1;
|
triangle.tx0 = tx0 - 1;
|
||||||
triangle.tx1 = tx1 - 1;
|
triangle.tx1 = tx1 - 1;
|
||||||
triangle.tx2 = tx2 - 1;
|
triangle.tx2 = tx2 - 1;
|
||||||
triangle.n0 = vn0 - 1;
|
triangle.n0 = vn0 - 1;
|
||||||
triangle.n1 = vn1 - 1;
|
triangle.n1 = vn1 - 1;
|
||||||
triangle.n2 = vn2 - 1;
|
triangle.n2 = vn2 - 1;
|
||||||
list_append(Triangle, arena, model.triangles, triangle);
|
list_append(Triangle, arena, model.triangles, triangle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
internal M4x4f g_viewport;
|
||||||
|
|
||||||
typedef struct triangle_bbox TriangleBBox;
|
typedef struct triangle_bbox TriangleBBox;
|
||||||
struct triangle_bbox {
|
struct triangle_bbox {
|
||||||
u64 x0;
|
u64 x0;
|
||||||
@ -41,6 +43,8 @@ bool init_render(Arena *arena, Render *render, u64 width, u64 height) {
|
|||||||
f32 inf = -INFINITY;
|
f32 inf = -INFINITY;
|
||||||
clear_buffer(&(render->depth), &inf);
|
clear_buffer(&(render->depth), &inf);
|
||||||
|
|
||||||
|
g_viewport = viewport(0, 0, width, height);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,11 +63,13 @@ internal void render_triangle(const Triangle *triangle, const Model *model,
|
|||||||
Image *img = &(render->img);
|
Image *img = &(render->img);
|
||||||
VertexData vertices[TRIANGLE_VERTICES];
|
VertexData vertices[TRIANGLE_VERTICES];
|
||||||
for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
|
for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
|
||||||
|
// clang-format off
|
||||||
vertices[i].position = list_get(model->vertices, triangle->positions[i]);
|
vertices[i].position = list_get(model->vertices, triangle->positions[i]);
|
||||||
vertices[i].normal = list_get(model->normals, triangle->normals[i]);
|
vertices[i].normal = list_get(model->normals, triangle->normals[i]);
|
||||||
vertices[i].uv = list_get(model->texture_coordinates, triangle->coordinates[i]);
|
vertices[i].uv = list_get(model->texture_coordinates, triangle->coordinates[i]);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
vertices[i] = run_vertex_shader(shader, &vertices[i], i, model);
|
vertices[i] = run_vertex_shader(shader, &vertices[i], i, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (render_type == RENDER_TYPE_WIREFRAME) {
|
if (render_type == RENDER_TYPE_WIREFRAME) {
|
||||||
@ -75,7 +81,8 @@ internal void render_triangle(const Triangle *triangle, const Model *model,
|
|||||||
//
|
//
|
||||||
// draw_line(img, (u64)v0.x, (u64)v0.y, (u64)v1.x, (u64)v1.y, colour);
|
// draw_line(img, (u64)v0.x, (u64)v0.y, (u64)v1.x, (u64)v1.y, colour);
|
||||||
// }
|
// }
|
||||||
} else if (render_type == RENDER_TYPE_FILLED || render_type == RENDER_TYPE_SHADED) {
|
} else if (render_type == RENDER_TYPE_FILLED ||
|
||||||
|
render_type == RENDER_TYPE_SHADED) {
|
||||||
fill_triangle(render, shader, vertices, colour, model, render_type);
|
fill_triangle(render, shader, vertices, colour, model, render_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,13 +112,14 @@ internal void fill_triangle(Render *render, ShaderID shader,
|
|||||||
for (u64 y = bbox.y0; y <= bbox.y1; ++y) {
|
for (u64 y = bbox.y0; y <= bbox.y1; ++y) {
|
||||||
for (u64 x = bbox.x0; x <= bbox.x1; ++x) {
|
for (u64 x = bbox.x0; x <= bbox.x1; ++x) {
|
||||||
point = (V2f){x, y};
|
point = (V2f){x, y};
|
||||||
coords = get_barycentric_coords(vp_verts[0], vp_verts[1], vp_verts[2], point);
|
coords =
|
||||||
|
get_barycentric_coords(vp_verts[0], vp_verts[1], vp_verts[2], point);
|
||||||
if (coords.x < 0.0f || coords.y < 0.0f || coords.z < 0.0f) {
|
if (coords.x < 0.0f || coords.y < 0.0f || coords.z < 0.0f) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
z = 0.0f;
|
z = 0.0f;
|
||||||
z += vertices[0].position.z * coords.x +
|
z += vertices[0].position.z * coords.x +
|
||||||
vertices[1].position.z * coords.y +
|
vertices[1].position.z * coords.y +
|
||||||
vertices[2].position.z * coords.z;
|
vertices[2].position.z * coords.z;
|
||||||
zbuf = get_pixel(f32, &(render->depth), x, y);
|
zbuf = get_pixel(f32, &(render->depth), x, y);
|
||||||
@ -159,7 +167,10 @@ internal V3f get_barycentric_coords(V2f a, V2f b, V2f c, V2f p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal V2f get_viewport_vertex(const V3f *vertex, const Image *img) {
|
internal V2f get_viewport_vertex(const V3f *vertex, const Image *img) {
|
||||||
V3f output = *vertex;
|
V4f vh = {.x = vertex->x, .y = 0.0f - vertex->y, .z = vertex->z, .w = 1.0f};
|
||||||
|
vh = mat4x4_mul_vec4(g_viewport, vh);
|
||||||
|
|
||||||
|
V3f output = project_vec4(vh);
|
||||||
output.x = clamp(output.x, 0.0f, img->width);
|
output.x = clamp(output.x, 0.0f, img->width);
|
||||||
output.y = clamp(output.y, 0.0f, img->height);
|
output.y = clamp(output.y, 0.0f, img->height);
|
||||||
|
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
#include "main_shader.h"
|
|
||||||
#include "obj.h"
|
|
||||||
#include "shader.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index,
|
|
||||||
const Model *model) {
|
|
||||||
Shader *shdr = (Shader *)shader;
|
|
||||||
|
|
||||||
V4f vh = V3_to_V4(vert->position);
|
|
||||||
vh.y = 0.0 - vh.y;
|
|
||||||
vh = mat4x4_mul_vec4(shdr->final, vh);
|
|
||||||
|
|
||||||
shdr->vertices[index].position = project_vec4(vh);
|
|
||||||
shdr->vertices[index].uv = vert->uv;
|
|
||||||
|
|
||||||
M4x4f inv_transpose = mat4x4_inv(mat4x4_transpose(shdr->proj_mv));
|
|
||||||
V4f hnorm = V3_to_V4(vert->normal);
|
|
||||||
hnorm = mat4x4_mul_vec4(inv_transpose, hnorm);
|
|
||||||
shdr->vertices[index].normal = project_vec4(hnorm);
|
|
||||||
normalise_v3(shdr->vertices[index].normal);
|
|
||||||
|
|
||||||
return shdr->vertices[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric,
|
|
||||||
const Colour *colour,
|
|
||||||
const Model *model) {
|
|
||||||
Shader *shdr = (Shader *)shader;
|
|
||||||
|
|
||||||
M3x3f pos_mat = {.rows = {shdr->vertices[0].position, shdr->vertices[1].position, shdr->vertices[2].position}};
|
|
||||||
pos_mat = mat3x3_transpose(pos_mat);
|
|
||||||
M3x3f normal_mat = {.rows = {shdr->vertices[0].normal, shdr->vertices[1].normal, shdr->vertices[2].normal}};
|
|
||||||
normal_mat = mat3x3_transpose(normal_mat);
|
|
||||||
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
|
|
||||||
M2x3f uv_mat = mat3x2_transpose(uvs);
|
|
||||||
|
|
||||||
V3f position = mat3x3_mul_vec3(pos_mat, (*barycentric));
|
|
||||||
V3f normal = mat3x3_mul_vec3(normal_mat, (*barycentric));
|
|
||||||
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
|
|
||||||
|
|
||||||
#pragma region darboux_frame_tangent_normals
|
|
||||||
/**
|
|
||||||
* Based on the following section of the tinyrenderer tutorial
|
|
||||||
* https://github.com/ssloy/tinyrenderer/wiki/Lesson-6bis:-tangent-space-normal-mapping#starting-point-phong-shading
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (model->normal) {
|
|
||||||
u64 nm_x = uv.u * model->normal->width;
|
|
||||||
u64 nm_y = uv.v * model->normal->height;
|
|
||||||
|
|
||||||
Colour pixel = get_pixel(Colour, model->normal, nm_x, nm_y);
|
|
||||||
V3f tangent = (V3f){
|
|
||||||
.x = pixel.r / 255.f * 2.f - 1.f,
|
|
||||||
.y = pixel.g / 255.f * 2.f - 1.f,
|
|
||||||
.z = pixel.b / 255.f * 2.f - 1.f,
|
|
||||||
};
|
|
||||||
|
|
||||||
V3f p0p1 = sub_v3(shdr->vertices[1].position, shdr->vertices[0].position);
|
|
||||||
V3f p0p2 = sub_v3(shdr->vertices[2].position, shdr->vertices[0].position);
|
|
||||||
|
|
||||||
M3x3f A = {.rows = {p0p1, p0p2, normal}};
|
|
||||||
M3x3f A_inv = mat3x3_inv(A);
|
|
||||||
|
|
||||||
V2f uv0 = shdr->vertices[0].uv;
|
|
||||||
V2f uv1 = shdr->vertices[1].uv;
|
|
||||||
V2f uv2 = shdr->vertices[2].uv;
|
|
||||||
|
|
||||||
V3f u_vec = {uv1.u - uv0.u, uv2.u - uv0.u, 0};
|
|
||||||
V3f v_vec = {uv1.v - uv0.v, uv2.v - uv0.v, 0};
|
|
||||||
|
|
||||||
V3f i = mat3x3_mul_vec3(A_inv, u_vec);
|
|
||||||
normalise_v3(i);
|
|
||||||
V3f j = mat3x3_mul_vec3(A_inv, v_vec);
|
|
||||||
normalise_v3(j);
|
|
||||||
|
|
||||||
M3x3f B = {.rows = {i, j, normal}};
|
|
||||||
B = mat3x3_transpose(B);
|
|
||||||
|
|
||||||
normal = mat3x3_mul_vec3(B, tangent);
|
|
||||||
normalise_v3(normal);
|
|
||||||
}
|
|
||||||
#pragma endregion darboux_frame_tangent_normals
|
|
||||||
|
|
||||||
Colour output;
|
|
||||||
if (model->texture) {
|
|
||||||
u64 tx_x = uv.u * model->texture->width;
|
|
||||||
u64 tx_y = uv.v * model->texture->height;
|
|
||||||
output = get_pixel(Colour, model->texture, tx_x, tx_y);
|
|
||||||
} else {
|
|
||||||
output = *colour;
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 intensity = max(0.001f, dot_v3(normal, shdr->light_dir));
|
|
||||||
f32 r = clamp(intensity + shdr->ambient.r, 0.0f, 1.0f);
|
|
||||||
f32 g = clamp(intensity + shdr->ambient.g, 0.0f, 1.0f);
|
|
||||||
f32 b = clamp(intensity + shdr->ambient.b, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
output.r *= r;
|
|
||||||
output.g *= g;
|
|
||||||
output.b *= b;
|
|
||||||
|
|
||||||
return (FragmentResult){.colour = output};
|
|
||||||
}
|
|
||||||
|
|
||||||
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric,
|
|
||||||
const Colour *colour,
|
|
||||||
const Model *model) {
|
|
||||||
Shader *shdr = (Shader *)shader;
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
|
|
||||||
M2x3f uv_mat = mat3x2_transpose(uvs);
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
|
|
||||||
|
|
||||||
Colour output;
|
|
||||||
if (model->texture) {
|
|
||||||
u64 tx_x = uv.u * model->texture->width;
|
|
||||||
u64 tx_y = uv.v * model->texture->height;
|
|
||||||
output = get_pixel(Colour, model->texture, tx_x, tx_y);
|
|
||||||
} else {
|
|
||||||
output = *colour;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (FragmentResult){.colour = output};
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#ifndef MAIN_SHADER_H
|
|
||||||
#define MAIN_SHADER_H
|
|
||||||
|
|
||||||
#include "shader.h"
|
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
typedef struct shader Shader;
|
|
||||||
struct shader {
|
|
||||||
#include "shader_base.inc"
|
|
||||||
};
|
|
||||||
|
|
||||||
VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index,
|
|
||||||
const Model *model);
|
|
||||||
FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric,
|
|
||||||
const Colour *colour,
|
|
||||||
const Model *model);
|
|
||||||
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric,
|
|
||||||
const Colour *colour, const Model *model);
|
|
||||||
#endif // !MAIN_SHADER_H
|
|
@ -1,7 +0,0 @@
|
|||||||
V3f light_dir;
|
|
||||||
V3f ambient;
|
|
||||||
M4x4f proj_mv;
|
|
||||||
M4x4f proj_mv_inv_t;
|
|
||||||
M4x4f viewport;
|
|
||||||
M4x4f final;
|
|
||||||
VertexData vertices[TRIANGLE_VERTICES];
|
|
@ -1,78 +1,203 @@
|
|||||||
#include "shaders.h"
|
|
||||||
#include "aliases.h"
|
#include "aliases.h"
|
||||||
#include "depth_shader.h"
|
#include "img.h"
|
||||||
#include "main_shader.h"
|
#include "obj.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
#include "utils.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
ShaderID perspective_diffuse = {0};
|
typedef struct shader Shader;
|
||||||
ShaderID perspective_albedo = {0};
|
struct shader {
|
||||||
ShaderID orthographic_diffuse = {0};
|
V3f light_dir;
|
||||||
ShaderID orthographic_albedo = {0};
|
M4x4f mv_proj;
|
||||||
ShaderID depth = {0};
|
VertexData vertices[TRIANGLE_VERTICES];
|
||||||
|
};
|
||||||
|
|
||||||
internal Shader perspective = {0};
|
ShaderID perspective_diffuse = {0};
|
||||||
internal Shader orthographic = {0};
|
ShaderID perspective_albedo = {0};
|
||||||
internal DepthShader depth_shader = {0};
|
ShaderID orthographic_diffuse = {0};
|
||||||
|
ShaderID orthographic_albedo = {0};
|
||||||
|
|
||||||
|
internal Shader perspective = {0};
|
||||||
|
internal Shader orthographic = {0};
|
||||||
|
|
||||||
internal V3f g_ambient_light = {0.1f, 0.1f, 0.1f};
|
internal V3f g_ambient_light = {0.1f, 0.1f, 0.1f};
|
||||||
internal V3f g_eye = {0.2f, -0.1f, 0.5f};
|
internal V3f g_eye = {0.2f, 0.1f, 0.75f};
|
||||||
internal V3f g_target = {0};
|
internal V3f g_target = {0};
|
||||||
internal V3f g_up = {0.0f, 1.0f, 0.0f};
|
internal V3f g_up = {0.0f, 1.0f, 0.0f};
|
||||||
internal V3f g_light_dir = {1.0f, -1.0f, 1.0f};
|
internal V3f g_light_dir = {1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
|
internal VertexData general_shader_vertex(void *shader, const VertexData *vert,
|
||||||
|
u8 index, const Model *model);
|
||||||
|
internal FragmentResult diffuse_shader_fragment(void *shader,
|
||||||
|
const V3f *barycentric,
|
||||||
|
const Colour *colour,
|
||||||
|
const Model *model);
|
||||||
|
internal FragmentResult albedo_shader_fragment(void *shader,
|
||||||
|
const V3f *barycentric,
|
||||||
|
const Colour *colour,
|
||||||
|
const Model *model);
|
||||||
internal M4x4f get_projection_matrix(ProjectionType projection_type);
|
internal M4x4f get_projection_matrix(ProjectionType projection_type);
|
||||||
|
|
||||||
void load_shaders(M4x4f vp) {
|
void load_shaders(void) {
|
||||||
M4x4f model_view = lookat(g_eye, g_target, g_up);
|
M4x4f model_view = lookat(g_eye, g_target, g_up);
|
||||||
M4x4f orthographic_projection = get_projection_matrix(PROJECTION_TYPE_ORTHOGRAPHIC);
|
M4x4f orthographic_projection =
|
||||||
M4x4f perspective_projection = get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE);
|
get_projection_matrix(PROJECTION_TYPE_ORTHOGRAPHIC);
|
||||||
|
M4x4f perspective_projection =
|
||||||
|
get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE);
|
||||||
|
|
||||||
// Set up perspective shader
|
perspective.mv_proj = mat4x4_mul(perspective_projection, model_view);
|
||||||
perspective.proj_mv = mat4x4_mul(perspective_projection, model_view);
|
orthographic.mv_proj = mat4x4_mul(orthographic_projection, model_view);
|
||||||
perspective.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(perspective.proj_mv));
|
|
||||||
perspective.viewport = vp;
|
perspective.light_dir = mat3x3_mul_vec3(perspective.mv_proj, g_light_dir);
|
||||||
perspective.final = mat4x4_mul(perspective.viewport, perspective.proj_mv);
|
|
||||||
perspective.light_dir = mat3x3_mul_vec3(perspective.proj_mv, g_light_dir);
|
|
||||||
normalise_v3(perspective.light_dir);
|
normalise_v3(perspective.light_dir);
|
||||||
perspective.ambient = g_ambient_light;
|
orthographic.light_dir = mat3x3_mul_vec3(orthographic.mv_proj, g_light_dir);
|
||||||
|
|
||||||
// Set up orthographic shader
|
|
||||||
orthographic.proj_mv = mat4x4_mul(orthographic_projection, model_view);
|
|
||||||
orthographic.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(orthographic.proj_mv));
|
|
||||||
orthographic.viewport = vp;
|
|
||||||
orthographic.final = mat4x4_mul(orthographic.viewport, orthographic.proj_mv);
|
|
||||||
orthographic.light_dir = mat3x3_mul_vec3(orthographic.proj_mv, g_light_dir);
|
|
||||||
normalise_v3(orthographic.light_dir);
|
normalise_v3(orthographic.light_dir);
|
||||||
orthographic.ambient = g_ambient_light;
|
|
||||||
|
|
||||||
// Set up depth shader
|
perspective_diffuse = register_shader(&perspective, general_shader_vertex,
|
||||||
M4x4f depth_model_view = lookat(g_light_dir, g_target, g_up);
|
diffuse_shader_fragment);
|
||||||
M4x4f depth_projection = projection(0.0f);
|
perspective_albedo = register_shader(&perspective, general_shader_vertex,
|
||||||
|
albedo_shader_fragment);
|
||||||
|
orthographic_diffuse = register_shader(&orthographic, general_shader_vertex,
|
||||||
|
diffuse_shader_fragment);
|
||||||
|
orthographic_albedo = register_shader(&orthographic, general_shader_vertex,
|
||||||
|
albedo_shader_fragment);
|
||||||
|
}
|
||||||
|
|
||||||
depth_shader.proj_mv = mat4x4_mul(depth_projection, depth_model_view);
|
internal VertexData general_shader_vertex(void *shader, const VertexData *vert,
|
||||||
depth_shader.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(depth_shader.proj_mv));
|
u8 index, const Model *model) {
|
||||||
depth_shader.viewport = vp;
|
Shader *shdr = (Shader *)shader;
|
||||||
depth_shader.final = mat4x4_mul(depth_shader.viewport, depth_shader.proj_mv);
|
|
||||||
depth_shader.light_dir = mat3x3_mul_vec3(depth_shader.proj_mv, g_light_dir);
|
|
||||||
normalise_v3(depth_shader.light_dir);
|
|
||||||
|
|
||||||
// Register shaders
|
V4f vh = V3_to_V4(vert->position);
|
||||||
perspective_diffuse = register_shader(&perspective, general_shader_vertex, diffuse_shader_fragment);
|
vh = mat4x4_mul_vec4(shdr->mv_proj, vh);
|
||||||
perspective_albedo = register_shader(&perspective, general_shader_vertex, albedo_shader_fragment);
|
|
||||||
orthographic_diffuse = register_shader(&orthographic, general_shader_vertex, diffuse_shader_fragment);
|
shdr->vertices[index].position = project_vec4(vh);
|
||||||
orthographic_albedo = register_shader(&orthographic, general_shader_vertex, albedo_shader_fragment);
|
shdr->vertices[index].uv = vert->uv;
|
||||||
depth = register_shader(&depth_shader, depth_shader_vertex, depth_shader_fragment);
|
|
||||||
|
V4f hnorm = V3_to_V4(vert->normal);
|
||||||
|
M4x4f inv_transpose = mat4x4_inv(mat4x4_transpose(shdr->mv_proj));
|
||||||
|
hnorm = mat4x4_mul_vec4(inv_transpose, hnorm);
|
||||||
|
shdr->vertices[index].normal = project_vec4(hnorm);
|
||||||
|
normalise_v3(shdr->vertices[index].normal);
|
||||||
|
|
||||||
|
return shdr->vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FragmentResult diffuse_shader_fragment(void *shader,
|
||||||
|
const V3f *barycentric,
|
||||||
|
const Colour *colour,
|
||||||
|
const Model *model) {
|
||||||
|
Shader *shdr = (Shader *)shader;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
M3x3f pos_mat = {.rows = {shdr->vertices[0].position, shdr->vertices[1].position, shdr->vertices[2].position}};
|
||||||
|
pos_mat = mat3x3_transpose(pos_mat);
|
||||||
|
M3x3f normal_mat = {.rows = {shdr->vertices[0].normal, shdr->vertices[1].normal, shdr->vertices[2].normal}};
|
||||||
|
normal_mat = mat3x3_transpose(normal_mat);
|
||||||
|
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
|
||||||
|
M2x3f uv_mat = mat3x2_transpose(uvs);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
V3f position = mat3x3_mul_vec3(pos_mat, (*barycentric));
|
||||||
|
V3f normal = mat3x3_mul_vec3(normal_mat, (*barycentric));
|
||||||
|
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
|
||||||
|
|
||||||
|
#pragma region darboux_frame_tangent_normals
|
||||||
|
/**
|
||||||
|
* Based on the following section of the tinyrenderer tutorial
|
||||||
|
* https://github.com/ssloy/tinyrenderer/wiki/Lesson-6bis:-tangent-space-normal-mapping#starting-point-phong-shading
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (model->normal) {
|
||||||
|
u64 nm_x = uv.u * model->normal->width;
|
||||||
|
u64 nm_y = uv.v * model->normal->height;
|
||||||
|
|
||||||
|
Colour pixel = get_pixel(Colour, model->normal, nm_x, nm_y);
|
||||||
|
V3f tangent = (V3f){
|
||||||
|
.x = pixel.r / 255.f * 2.f - 1.f,
|
||||||
|
.y = pixel.g / 255.f * 2.f - 1.f,
|
||||||
|
.z = pixel.b / 255.f * 2.f - 1.f,
|
||||||
|
};
|
||||||
|
|
||||||
|
V3f p0p1 = sub_v3(shdr->vertices[1].position, shdr->vertices[0].position);
|
||||||
|
V3f p0p2 = sub_v3(shdr->vertices[2].position, shdr->vertices[0].position);
|
||||||
|
|
||||||
|
M3x3f A = {.rows = {p0p1, p0p2, normal}};
|
||||||
|
M3x3f A_inv = mat3x3_inv(A);
|
||||||
|
|
||||||
|
V2f uv0 = shdr->vertices[0].uv;
|
||||||
|
V2f uv1 = shdr->vertices[1].uv;
|
||||||
|
V2f uv2 = shdr->vertices[2].uv;
|
||||||
|
|
||||||
|
V3f u_vec = {uv1.u - uv0.u, uv2.u - uv0.u, 0};
|
||||||
|
V3f v_vec = {uv1.v - uv0.v, uv2.v - uv0.v, 0};
|
||||||
|
|
||||||
|
V3f i = mat3x3_mul_vec3(A_inv, u_vec);
|
||||||
|
normalise_v3(i);
|
||||||
|
V3f j = mat3x3_mul_vec3(A_inv, v_vec);
|
||||||
|
normalise_v3(j);
|
||||||
|
|
||||||
|
M3x3f B = {.rows = {i, j, normal}};
|
||||||
|
B = mat3x3_transpose(B);
|
||||||
|
|
||||||
|
normal = mat3x3_mul_vec3(B, tangent);
|
||||||
|
normalise_v3(normal);
|
||||||
|
}
|
||||||
|
#pragma endregion darboux_frame_tangent_normals
|
||||||
|
|
||||||
|
Colour output;
|
||||||
|
if (model->texture) {
|
||||||
|
u64 tx_x = uv.u * model->texture->width;
|
||||||
|
u64 tx_y = uv.v * model->texture->height;
|
||||||
|
output = get_pixel(Colour, model->texture, tx_x, tx_y);
|
||||||
|
} else {
|
||||||
|
output = *colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 intensity = max(0.001f, dot_v3(normal, shdr->light_dir));
|
||||||
|
f32 r = clamp(intensity + g_ambient_light.r, 0.0f, 1.0f);
|
||||||
|
f32 g = clamp(intensity + g_ambient_light.g, 0.0f, 1.0f);
|
||||||
|
f32 b = clamp(intensity + g_ambient_light.b, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
output.r *= r;
|
||||||
|
output.g *= g;
|
||||||
|
output.b *= b;
|
||||||
|
|
||||||
|
return (FragmentResult){.colour = output};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FragmentResult albedo_shader_fragment(void *shader,
|
||||||
|
const V3f *barycentric,
|
||||||
|
const Colour *colour,
|
||||||
|
const Model *model) {
|
||||||
|
Shader *shdr = (Shader *)shader;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
|
||||||
|
M2x3f uv_mat = mat3x2_transpose(uvs);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
|
||||||
|
|
||||||
|
Colour output;
|
||||||
|
if (model->texture) {
|
||||||
|
u64 tx_x = uv.u * model->texture->width;
|
||||||
|
u64 tx_y = uv.v * model->texture->height;
|
||||||
|
output = get_pixel(Colour, model->texture, tx_x, tx_y);
|
||||||
|
} else {
|
||||||
|
output = *colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (FragmentResult){.colour = output};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal M4x4f get_projection_matrix(ProjectionType projection_type) {
|
internal M4x4f get_projection_matrix(ProjectionType projection_type) {
|
||||||
if (projection_type == PROJECTION_TYPE_PERSPECTIVE) {
|
if (projection_type == PROJECTION_TYPE_PERSPECTIVE) {
|
||||||
V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y, g_eye.z);
|
// Calculate projection matrix
|
||||||
|
V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y,
|
||||||
|
g_eye.z);
|
||||||
normalise_v3(cam);
|
normalise_v3(cam);
|
||||||
|
|
||||||
f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f;
|
f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f;
|
||||||
|
|
||||||
return projection(coeff);
|
return projection(coeff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,7 @@ extern ShaderID perspective_diffuse;
|
|||||||
extern ShaderID perspective_albedo;
|
extern ShaderID perspective_albedo;
|
||||||
extern ShaderID orthographic_diffuse;
|
extern ShaderID orthographic_diffuse;
|
||||||
extern ShaderID orthographic_albedo;
|
extern ShaderID orthographic_albedo;
|
||||||
extern ShaderID depth;
|
|
||||||
|
|
||||||
void load_shaders(M4x4f vp);
|
void load_shaders(void);
|
||||||
|
|
||||||
#endif // SHADERS_H
|
#endif // SHADERS_H
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define CAPACITY_SCALAR 4
|
#define CAPACITY_SCALAR 8
|
||||||
|
|
||||||
internal Arena *get_temp_arena(void);
|
internal Arena *get_temp_arena(void);
|
||||||
internal void destroy_temp_arena(Arena *arena);
|
internal void destroy_temp_arena(Arena *arena);
|
||||||
@ -16,8 +16,8 @@ Str8 str8(Arena *arena, char *str) {
|
|||||||
|
|
||||||
u64 length = strlen(str);
|
u64 length = strlen(str);
|
||||||
Str8 output = {
|
Str8 output = {
|
||||||
.str = str,
|
.str = str,
|
||||||
.length = length,
|
.length = length,
|
||||||
.capacity = length,
|
.capacity = length,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,8 +48,8 @@ Str8 str8_copy(Arena *arena, const Str8 *str) {
|
|||||||
strncpy(tmp, str->str, str->length);
|
strncpy(tmp, str->str, str->length);
|
||||||
|
|
||||||
return (Str8){
|
return (Str8){
|
||||||
.str = tmp,
|
.str = tmp,
|
||||||
.length = str->length,
|
.length = str->length,
|
||||||
.capacity = str->capacity,
|
.capacity = str->capacity,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -74,8 +74,8 @@ i32 str8_concat(Arena *arena, Str8 *dst, char *src) {
|
|||||||
strncpy(str, dst->str, dst->length);
|
strncpy(str, dst->str, dst->length);
|
||||||
strncpy(str + dst->length, src, src_length);
|
strncpy(str + dst->length, src, src_length);
|
||||||
|
|
||||||
dst->str = str;
|
dst->str = str;
|
||||||
dst->length = dst->length + src_length;
|
dst->length = dst->length + src_length;
|
||||||
dst->capacity = capacity;
|
dst->capacity = capacity;
|
||||||
|
|
||||||
return STR_OP_SUCEEDED;
|
return STR_OP_SUCEEDED;
|
||||||
@ -91,8 +91,8 @@ Str8 str8_substr(Arena *arena, const Str8 *str, u64 start, u64 count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Str8 tmp = {
|
Str8 tmp = {
|
||||||
.str = str->str + start,
|
.str = str->str + start,
|
||||||
.length = count,
|
.length = count,
|
||||||
.capacity = count,
|
.capacity = count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include "constants.h"
|
|
||||||
|
#define DEPTH_MAX 255
|
||||||
|
|
||||||
M4x4f lookat(V3f eye, V3f target, V3f up) {
|
M4x4f lookat(V3f eye, V3f target, V3f up) {
|
||||||
V3f z = V3(V3f, f32, target.x, target.y, target.z, eye.x, eye.y, eye.z);
|
V3f z = V3(V3f, f32, target.x, target.y, target.z, eye.x, eye.y, eye.z);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user