ソースを参照

Implement backface culling for 3d model demos

rexim 1 年間 前
コミット
3c6e841054

+ 35 - 3
demos/model3d.c

@@ -61,6 +61,23 @@ static Vector3 rotate_y(Vector3 p, float delta_angle)
     return make_vector3(cosf(angle)*mag, p.y, sinf(angle)*mag);
     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)
 Olivec_Canvas vc_render(float dt)
 {
 {
     angle += 0.25*PI*dt;
     angle += 0.25*PI*dt;
@@ -69,14 +86,29 @@ Olivec_Canvas vc_render(float dt)
     olivec_fill(oc, BACKGROUND_COLOR);
     olivec_fill(oc, BACKGROUND_COLOR);
     for (size_t i = 0; i < WIDTH*HEIGHT; ++i) zbuffer[i] = 0;
     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) {
     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 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 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);
         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;
         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 p1 = project_2d_scr(project_3d_2d(v1));
         Vector2 p2 = project_2d_scr(project_3d_2d(v2));
         Vector2 p2 = project_2d_scr(project_3d_2d(v2));
         Vector2 p3 = project_2d_scr(project_3d_2d(v3));
         Vector2 p3 = project_2d_scr(project_3d_2d(v3));

+ 90 - 22
tools/obj2c.c

@@ -146,6 +146,18 @@ typedef struct {
     size_t count;
     size_t count;
 } Faces;
 } 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_INIT_CAPACITY 8192
 #define DA_REALLOC context_realloc
 #define DA_REALLOC context_realloc
 #define da_append(da, item)                                                 \
 #define da_append(da, item)                                                 \
@@ -184,17 +196,45 @@ bool is_deleted_face(Vertices vertices, Face face, Component_Indices delete_comp
     return false;
     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, "#ifndef OBJ_H_\n");
     fprintf(out, "#define OBJ_H_\n");
     fprintf(out, "#define OBJ_H_\n");
     fprintf(out, "#define vertices_count %zu\n", vertices.count);
     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");
+    } else {
+        fprintf(out, "static const float texcoords[][3] = {\n");
+        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;
     size_t visible_faces_count = 0;
     for (size_t i = 0; i < faces.count; ++i) {
     for (size_t i = 0; i < faces.count; ++i) {
@@ -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");
     fprintf(out, "#endif // OBJ_H_\n");
 }
 }
 
 
@@ -246,13 +290,13 @@ void parse_face_triple(String_View *line, int *lf, int *hf, int *v, int *vt, int
     *vt = 0;
     *vt = 0;
     if (line->count > 0 && line->data[0] == '/') {
     if (line->count > 0 && line->data[0] == '/') {
         sv_chop_left(line, 1);
         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);
         sv_chop_left(line, endptr - line->data);
     }
     }
     *vn = 0;
     *vn = 0;
     if (line->count > 0 && line->data[0] == '/') {
     if (line->count > 0 && line->data[0] == '/') {
         sv_chop_left(line, 1);
         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);
         sv_chop_left(line, endptr - line->data);
     }
     }
     while (line->count > 0 && !isspace(*line->data)) sv_chop_left(line, 1);
     while (line->count > 0 && !isspace(*line->data)) sv_chop_left(line, 1);
@@ -346,9 +390,9 @@ int main(int argc, char **argv)
 
 
     String_View content = sv_from_parts(buffer, buffer_size);
     String_View content = sv_from_parts(buffer, buffer_size);
     Vertices vertices = {0};
     Vertices vertices = {0};
+    TexCoords texcoords = {0};
+    Normals normals = {0};
     Faces faces = {0};
     Faces faces = {0};
-    size_t normals_counts = 0;
-    size_t texture_coords_count = 0;
     float lx = FLT_MAX, hx = FLT_MIN;
     float lx = FLT_MAX, hx = FLT_MIN;
     float ly = FLT_MAX, hy = FLT_MIN;
     float ly = FLT_MAX, hy = FLT_MIN;
     float lz = FLT_MAX, hz = FLT_MIN;
     float lz = FLT_MAX, hz = FLT_MIN;
@@ -419,9 +463,33 @@ int main(int argc, char **argv)
             } else if (sv_eq(kind, SV("s"))) {
             } 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);
                 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"))) {
             } 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"))) {
             } 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 {
             } else {
                 fprintf(stderr, "%s:%zu: ERROR: unknown kind of entry `"SV_Fmt"`\n", input_file_path, line_number, SV_Arg(kind));
                 fprintf(stderr, "%s:%zu: ERROR: unknown kind of entry `"SV_Fmt"`\n", input_file_path, line_number, SV_Arg(kind));
                 return_defer(1);
                 return_defer(1);
@@ -474,8 +542,8 @@ int main(int argc, char **argv)
     printf("Input:               %s\n", input_file_path);
     printf("Input:               %s\n", input_file_path);
     printf("Output:              %s\n", output_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("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:               %zu (index: %d..%d)\n", faces.count, lf, hf);
     printf("Faces per vertex:    %d..%d\n", min_faces, max_faces);
     printf("Faces per vertex:    %d..%d\n", min_faces, max_faces);
     printf("Components Count:    %zu\n", comp_count);
     printf("Components Count:    %zu\n", comp_count);
@@ -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));
         fprintf(stderr, "ERROR: Could not write file %s: %s\n", output_file_path, strerror(errno));
         return_defer(1);
         return_defer(1);
     }
     }
-    generate_code(out, vertices, faces, delete_components);
+    generate_code(out, vertices, texcoords, normals, faces, delete_components);
 
 
 defer:
 defer:
     return result;
     return result;

BIN
wasm/cup3d.wasm


BIN
wasm/dots3d.wasm


BIN
wasm/penger3d.wasm


BIN
wasm/squish.wasm


BIN
wasm/teapot3d.wasm


BIN
wasm/triangle.wasm


BIN
wasm/triangle3d.wasm


BIN
wasm/triangle3dTex.wasm


BIN
wasm/triangleTex.wasm