Skip to content

Commit

Permalink
Implement backface culling for 3d model demos
Browse files Browse the repository at this point in the history
  • Loading branch information
rexim committed Oct 2, 2024
1 parent 0a50aa7 commit 3c6e841
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 25 deletions.
38 changes: 35 additions & 3 deletions demos/model3d.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ static Vector3 rotate_y(Vector3 p, float delta_angle)
return make_vector3(cosf(angle)*mag, p.y, sinf(angle)*mag);
}

typedef enum {
FACE_V1,
FACE_V2,
FACE_V3,
FACE_VT1,
FACE_VT2,
FACE_VT3,
FACE_VN1,
FACE_VN2,
FACE_VN3,
} Face_Index;

float vector3_dot(Vector3 a, Vector3 b)
{
return a.x*b.x + a.y*b.y + a.z*b.z;
}

Olivec_Canvas vc_render(float dt)
{
angle += 0.25*PI*dt;
Expand All @@ -69,14 +86,29 @@ Olivec_Canvas vc_render(float dt)
olivec_fill(oc, BACKGROUND_COLOR);
for (size_t i = 0; i < WIDTH*HEIGHT; ++i) zbuffer[i] = 0;

Vector3 camera = {0, 0, 1};
for (size_t i = 0; i < faces_count; ++i) {
int a = faces[i][0];
int b = faces[i][1];
int c = faces[i][2];
int a, b, c;

a = faces[i][FACE_V1];
b = faces[i][FACE_V2];
c = faces[i][FACE_V3];
Vector3 v1 = rotate_y(make_vector3(vertices[a][0], vertices[a][1], vertices[a][2]), angle);
Vector3 v2 = rotate_y(make_vector3(vertices[b][0], vertices[b][1], vertices[b][2]), angle);
Vector3 v3 = rotate_y(make_vector3(vertices[c][0], vertices[c][1], vertices[c][2]), angle);
v1.z += 1.5; v2.z += 1.5; v3.z += 1.5;

a = faces[i][FACE_VN1];
b = faces[i][FACE_VN2];
c = faces[i][FACE_VN3];
Vector3 vn1 = rotate_y(make_vector3(normals[a][0], normals[a][1], normals[a][2]), angle);
Vector3 vn2 = rotate_y(make_vector3(normals[b][0], normals[b][1], normals[b][2]), angle);
Vector3 vn3 = rotate_y(make_vector3(normals[c][0], normals[c][1], normals[c][2]), angle);
if (vector3_dot(camera, vn1) > 0.0 &&
vector3_dot(camera, vn2) > 0.0 &&
vector3_dot(camera, vn3) > 0.0) continue;


Vector2 p1 = project_2d_scr(project_3d_2d(v1));
Vector2 p2 = project_2d_scr(project_3d_2d(v2));
Vector2 p3 = project_2d_scr(project_3d_2d(v3));
Expand Down
112 changes: 90 additions & 22 deletions tools/obj2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,18 @@ typedef struct {
size_t count;
} Faces;

typedef struct {
Vector3 *items;
size_t capacity;
size_t count;
} Normals;

typedef struct {
Vector2 *items;
size_t capacity;
size_t count;
} TexCoords;

#define DA_INIT_CAPACITY 8192
#define DA_REALLOC context_realloc
#define da_append(da, item) \
Expand Down Expand Up @@ -184,17 +196,45 @@ bool is_deleted_face(Vertices vertices, Face face, Component_Indices delete_comp
return false;
}

void generate_code(FILE *out, Vertices vertices, Faces faces, Component_Indices delete_components)
void generate_code(FILE *out, Vertices vertices, TexCoords texcoords, Normals normals, Faces faces, Component_Indices delete_components)
{
fprintf(out, "#ifndef OBJ_H_\n");
fprintf(out, "#define OBJ_H_\n");
fprintf(out, "#define vertices_count %zu\n", vertices.count);
fprintf(out, "static const float vertices[][3] = {\n");
for (size_t i = 0; i < vertices.count; ++i) {
Vector3 v = vertices.items[i].position;
fprintf(out, " {%f, %f, %f},\n", v.x, v.y, v.z);
if (vertices.count == 0) {
fprintf(out, "static const float vertices[1][3];\n");
} else {
fprintf(out, "static const float vertices[][3] = {\n");
for (size_t i = 0; i < vertices.count; ++i) {
Vector3 v = vertices.items[i].position;
fprintf(out, " {%f, %f, %f},\n", v.x, v.y, v.z);
}
fprintf(out, "};\n");
}

fprintf(out, "#define texcoords_count %zu\n", texcoords.count);
if (texcoords.count == 0) {
fprintf(out, "static const float texcoords[1][3];\n");

This comment has been minimized.

Copy link
@br-olf

br-olf Oct 18, 2024

I think this line should be
fprintf(out, "static const float texcoords[1][2];\n");

} else {
fprintf(out, "static const float texcoords[][3] = {\n");

This comment has been minimized.

Copy link
@br-olf

br-olf Oct 18, 2024

same here

for (size_t i = 0; i < texcoords.count; ++i) {
Vector2 vt = texcoords.items[i];
fprintf(out, " {%f, %f},\n", vt.x, vt.y);
}
fprintf(out, "};\n");
}

fprintf(out, "#define normals_count %zu\n", normals.count);
if (normals.count == 0) {
fprintf(out, "static const float normals[1][3];\n");
} else {
fprintf(out, "static const float normals[][3] = {\n");
for (size_t i = 0; i < normals.count; ++i) {
Vector3 vn = normals.items[i];
fprintf(out, " {%f, %f, %f},\n", vn.x, vn.y, vn.z);
}
fprintf(out, "};\n");
}
fprintf(out, "};\n");

size_t visible_faces_count = 0;
for (size_t i = 0; i < faces.count; ++i) {
Expand All @@ -203,15 +243,19 @@ void generate_code(FILE *out, Vertices vertices, Faces faces, Component_Indices
}
}

fprintf(out, "static const int faces[%zu][3] = {\n", visible_faces_count);
for (size_t i = 0; i < faces.count; ++i) {
if (!is_deleted_face(vertices, faces.items[i], delete_components)) {
Face f = faces.items[i];
fprintf(out, " {%d, %d, %d},\n", f.v[0], f.v[1], f.v[2]);
fprintf(out, "#define faces_count %zu\n", visible_faces_count);
if (visible_faces_count == 0) {
fprintf(out, "static const int faces[1][9];\n");
} else {
fprintf(out, "static const int faces[%zu][9] = {\n", visible_faces_count);
for (size_t i = 0; i < faces.count; ++i) {
if (!is_deleted_face(vertices, faces.items[i], delete_components)) {
Face f = faces.items[i];
fprintf(out, " {%d, %d, %d, %d, %d, %d, %d, %d, %d},\n", f.v[0], f.v[1], f.v[2], f.vt[0], f.vt[1], f.vt[2], f.vn[0], f.vn[1], f.vn[2]);
}
}
fprintf(out, "};\n");
}
fprintf(out, "};\n");
fprintf(out, "#define faces_count %zu\n", visible_faces_count);
fprintf(out, "#endif // OBJ_H_\n");
}

Expand Down Expand Up @@ -246,13 +290,13 @@ void parse_face_triple(String_View *line, int *lf, int *hf, int *v, int *vt, int
*vt = 0;
if (line->count > 0 && line->data[0] == '/') {
sv_chop_left(line, 1);
*vt = strtol(line->data, &endptr, 10);
*vt = strtol(line->data, &endptr, 10) - 1; // NOTE: -1 is to account for 1-based indexing.
sv_chop_left(line, endptr - line->data);
}
*vn = 0;
if (line->count > 0 && line->data[0] == '/') {
sv_chop_left(line, 1);
*vn = strtol(line->data, &endptr, 10);
*vn = strtol(line->data, &endptr, 10) - 1; // NOTE: -1 is to account for 1-based indexing.
sv_chop_left(line, endptr - line->data);
}
while (line->count > 0 && !isspace(*line->data)) sv_chop_left(line, 1);
Expand Down Expand Up @@ -346,9 +390,9 @@ int main(int argc, char **argv)

String_View content = sv_from_parts(buffer, buffer_size);
Vertices vertices = {0};
TexCoords texcoords = {0};
Normals normals = {0};
Faces faces = {0};
size_t normals_counts = 0;
size_t texture_coords_count = 0;
float lx = FLT_MAX, hx = FLT_MIN;
float ly = FLT_MAX, hy = FLT_MIN;
float lz = FLT_MAX, hz = FLT_MIN;
Expand Down Expand Up @@ -419,9 +463,33 @@ int main(int argc, char **argv)
} else if (sv_eq(kind, SV("s"))) {
fprintf(stderr, "%s:%zu: WARNING: smooth groups are not supported right now. Ignoring them...\n", input_file_path, line_number);
} else if (sv_eq(kind, SV("vn"))) {
normals_counts += 1;
char *endptr;

line = sv_trim_left(line);
float x = strtof(line.data, &endptr);
sv_chop_left(&line, endptr - line.data);

line = sv_trim_left(line);
float y = strtof(line.data, &endptr);
sv_chop_left(&line, endptr - line.data);

line = sv_trim_left(line);
float z = strtof(line.data, &endptr);
sv_chop_left(&line, endptr - line.data);

da_append(&normals, make_vector3(x, y, z));
} else if (sv_eq(kind, SV("vt"))) {
texture_coords_count += 1;
char *endptr;

line = sv_trim_left(line);
float x = strtof(line.data, &endptr);
sv_chop_left(&line, endptr - line.data);

line = sv_trim_left(line);
float y = strtof(line.data, &endptr);
sv_chop_left(&line, endptr - line.data);

da_append(&texcoords, make_vector2(x, y));
} else {
fprintf(stderr, "%s:%zu: ERROR: unknown kind of entry `"SV_Fmt"`\n", input_file_path, line_number, SV_Arg(kind));
return_defer(1);
Expand Down Expand Up @@ -474,8 +542,8 @@ int main(int argc, char **argv)
printf("Input: %s\n", input_file_path);
printf("Output: %s\n", output_file_path);
printf("Vertices: %zu (x: %f..%f, y: %f..%f, z: %f..%f)\n", vertices.count, lx, hx, ly, hy, lz, hz);
printf("Normals: %zu\n", normals_counts);
printf("Texture Coordinates: %zu\n", texture_coords_count);
printf("Normals: %zu\n", normals.count);
printf("Texture Coordinates: %zu\n", texcoords.count);
printf("Faces: %zu (index: %d..%d)\n", faces.count, lf, hf);
printf("Faces per vertex: %d..%d\n", min_faces, max_faces);
printf("Components Count: %zu\n", comp_count);
Expand All @@ -494,7 +562,7 @@ int main(int argc, char **argv)
fprintf(stderr, "ERROR: Could not write file %s: %s\n", output_file_path, strerror(errno));
return_defer(1);
}
generate_code(out, vertices, faces, delete_components);
generate_code(out, vertices, texcoords, normals, faces, delete_components);

defer:
return result;
Expand Down
Binary file modified wasm/cup3d.wasm
Binary file not shown.
Binary file modified wasm/dots3d.wasm
Binary file not shown.
Binary file modified wasm/penger3d.wasm
Binary file not shown.
Binary file modified wasm/squish.wasm
Binary file not shown.
Binary file modified wasm/teapot3d.wasm
Binary file not shown.
Binary file modified wasm/triangle.wasm
Binary file not shown.
Binary file modified wasm/triangle3d.wasm
Binary file not shown.
Binary file modified wasm/triangle3dTex.wasm
Binary file not shown.
Binary file modified wasm/triangleTex.wasm
Binary file not shown.

0 comments on commit 3c6e841

Please sign in to comment.