Ver Fonte

Textured 3D triangles

rexim há 2 anos atrás
pai
commit
97b89d2031
9 ficheiros alterados com 153 adições e 11 exclusões
  1. 2 1
      build.sh
  2. 122 0
      demos/triangle3dTex.c
  3. 1 0
      demos/triangleTex.c
  4. 9 4
      index.html
  5. 19 6
      olive.c
  6. BIN
      wasm/3d.wasm
  7. BIN
      wasm/squish.wasm
  8. BIN
      wasm/triangle3dTex.wasm
  9. BIN
      wasm/triangleTex.wasm

+ 2 - 1
build.sh

@@ -32,5 +32,6 @@ build_vc_demo triangle &
 build_vc_demo 3d &
 build_vc_demo 3d &
 build_vc_demo squish &
 build_vc_demo squish &
 build_vc_demo triangle3d &
 build_vc_demo triangle3d &
-build_vc_demo triangle_tex &
+build_vc_demo triangleTex &
+build_vc_demo triangle3dTex &
 wait # TODO: the whole script must fail if one of the jobs fails
 wait # TODO: the whole script must fail if one of the jobs fails

+ 122 - 0
demos/triangle3dTex.c

@@ -0,0 +1,122 @@
+#define SCALE_DOWN_FACTOR 20
+#include "../demos/vc.c"
+#include "./assets/tsodinPog.c"
+
+#define WIDTH 800
+#define HEIGHT 600
+uint32_t pixels1[WIDTH*HEIGHT];
+float zbuffer1[WIDTH*HEIGHT];
+uint32_t pixels2[WIDTH*HEIGHT];
+float zbuffer2[WIDTH*HEIGHT];
+
+typedef struct {
+    float x, y;
+} Vector2;
+
+Vector2 make_vector2(float x, float y)
+{
+    Vector2 v2;
+    v2.x = x;
+    v2.y = y;
+    return v2;
+}
+
+typedef struct {
+    float x, y, z;
+} Vector3;
+
+Vector3 make_vector3(float x, float y, float z)
+{
+    Vector3 v3;
+    v3.x = x;
+    v3.y = y;
+    v3.z = z;
+    return v3;
+}
+
+Vector2 project_3d_2d(Vector3 v3)
+{
+    return make_vector2(v3.x / v3.z, v3.y / v3.z);
+}
+
+Vector2 project_2d_scr(Vector2 v2)
+{
+    return make_vector2((v2.x + 1)/2*WIDTH, (1 - (v2.y + 1)/2)*HEIGHT);
+}
+
+float global_time = 1.0;
+
+#define PI 3.14159265359
+
+float sinf(float);
+float cosf(float);
+
+Olivec_Canvas render(float dt)
+{
+    global_time += dt;
+
+    Olivec_Canvas oc1 = olivec_canvas(pixels1, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(oc1, 0xFF181818);
+    Olivec_Canvas zb1 = olivec_canvas((uint32_t*)zbuffer1, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(zb1, 0);
+
+    Olivec_Canvas tsodinPog = olivec_canvas(tsodinPog_pixels, tsodinPog_width, tsodinPog_height, tsodinPog_width);
+
+    float z = 1.5;
+    float t = 0.75;
+    {
+        Vector3 v1 = make_vector3(cosf(global_time)*t, -t, z + sinf(global_time)*t);
+        Vector3 v2 = make_vector3(cosf(global_time + PI)*t, -t, z + sinf(global_time + PI)*t);
+        Vector3 v3 = make_vector3(0, t, z);
+
+        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));
+
+        olivec_triangle3uv(oc1, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y,
+                           olivec_uv(0/v1.z, 1/v1.z),
+                           olivec_uv(0.5/v2.z, 0/v2.z),
+                           olivec_uv(1/v3.z, 0/v3.z),
+                           1/v1.z, 1/v2.z, 1/v3.z,
+                           tsodinPog);
+        olivec_triangle3z(zb1, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 1.0f/v1.z, 1.0f/v2.z, 1.0f/v3.z);
+    }
+
+    Olivec_Canvas oc2 = olivec_canvas(pixels2, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(oc2, 0xFF181818);
+    Olivec_Canvas zb2 = olivec_canvas((uint32_t*)zbuffer2, WIDTH, HEIGHT, WIDTH);
+    olivec_fill(zb2, 0);
+
+    {
+        Vector3 v1 = make_vector3(cosf(global_time + PI/2)*t, -t, z + sinf(global_time + PI/2)*t);
+        Vector3 v2 = make_vector3(cosf(global_time + PI + PI/2)*t, -t, z + sinf(global_time + PI + PI/2)*t);
+        Vector3 v3 = make_vector3(0, t, z);
+
+        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));
+
+        olivec_triangle3z(zb2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 1.0f/v1.z, 1.0f/v2.z, 1.0f/v3.z);
+        olivec_triangle3c(oc2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0xFF1818FF, 0xFF18FF18, 0xFFFF1818);
+    }
+
+    for (size_t y = 0; y < HEIGHT; ++y) {
+        for (size_t x = 0; x < WIDTH; ++x) {
+            float z1 = *(float*)&OLIVEC_PIXEL(zb1, x, y);
+            float z2 = *(float*)&OLIVEC_PIXEL(zb2, x, y);
+            if (z1 < z2) {
+                OLIVEC_PIXEL(oc1, x, y) = OLIVEC_PIXEL(oc2, x, y);
+                z1 = z2;
+            }
+            z1 = 1.0f/z1;
+            if (z1 >= 1.0) {
+                z1 -= 1.0;
+                uint32_t v = z1*255;
+                if (v > 255) v = 255;
+                olivec_blend_color(&OLIVEC_PIXEL(oc1, x, y), (v<<(3*8)));
+            }
+        }
+    }
+
+    return oc1;
+}

+ 1 - 0
demos/triangle_tex.c → demos/triangleTex.c

@@ -52,6 +52,7 @@ Olivec_Canvas render(float dt)
                 ps[i2][0], ps[i2][1],
                 ps[i2][0], ps[i2][1],
                 ps[i3][0], ps[i3][1],
                 ps[i3][0], ps[i3][1],
                 uvs[i1], uvs[i2], uvs[i3],
                 uvs[i1], uvs[i2], uvs[i3],
+                1, 1, 1,
                 tsodinPog
                 tsodinPog
             );
             );
        }
        }

+ 9 - 4
index.html

@@ -26,9 +26,13 @@
     Rotating rainbow triangle in 3D. Unlike <a href="#demo-3d">3D dots above</a> this is a solid shape. Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangle3d.c">demos/triangle3d.c</a></p>
     Rotating rainbow triangle in 3D. Unlike <a href="#demo-3d">3D dots above</a> this is a solid shape. Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangle3d.c">demos/triangle3d.c</a></p>
     <canvas id="app-triangle3d"></canvas>
     <canvas id="app-triangle3d"></canvas>
 
 
-    <h2 id="demo-triangle_tex"><a href="#demo-triangle_tex">Rotating Textures</a></h2>
-    Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangle_tex.c">demos/triangle_tex.c</a></p>
-    <canvas id="app-triangle_tex"></canvas>
+    <h2 id="demo-triangleTex"><a href="#demo-triangleTex">Rotating Textures</a></h2>
+    Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangleTex.c">demos/triangleTex.c</a></p>
+    <canvas id="app-triangleTex"></canvas>
+
+    <h2 id="demo-triangle3dTex"><a href="#demo-triangle3dTex">Rotating Textures</a></h2>
+    Source:&nbsp;<a href="https://github.com/tsoding/olive.c/blob/master/demos/triangle3dTex.c">demos/triangle3dTex.c</a></p>
+    <canvas id="app-triangle3dTex"></canvas>
 
 
     <script src="js/vc.js"></script>
     <script src="js/vc.js"></script>
     <script>
     <script>
@@ -36,7 +40,8 @@
       startDemo("app-3d", "./wasm/3d.wasm");
       startDemo("app-3d", "./wasm/3d.wasm");
       startDemo("app-squish", "./wasm/squish.wasm");
       startDemo("app-squish", "./wasm/squish.wasm");
       startDemo("app-triangle3d", "./wasm/triangle3d.wasm");
       startDemo("app-triangle3d", "./wasm/triangle3d.wasm");
-      startDemo("app-triangle_tex", "./wasm/triangle_tex.wasm");
+      startDemo("app-triangleTex", "./wasm/triangleTex.wasm");
+      startDemo("app-triangle3dTex", "./wasm/triangle3dTex.wasm");
     </script>
     </script>
   </body>
   </body>
 </html>
 </html>

+ 19 - 6
olive.c

@@ -320,7 +320,7 @@ OLIVECDEF void olivec_line(Olivec_Canvas oc, int x1, int y1, int x2, int y2, uin
 OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color);
 OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color);
 OLIVECDEF void olivec_triangle3c(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t c1, uint32_t c2, uint32_t c3);
 OLIVECDEF void olivec_triangle3c(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t c1, uint32_t c2, uint32_t c3);
 OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float z1, float z2, float z3);
 OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, float z1, float z2, float z3);
-OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, Uv uv1, Uv uv2, Uv uv3, Olivec_Canvas texture);
+OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, Uv uv1, Uv uv2, Uv uv3, float z1, float z2, float z3, Olivec_Canvas texture);
 OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int x, int y, Olivec_Font font, size_t size, uint32_t color);
 OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int x, int y, Olivec_Font font, size_t size, uint32_t color);
 OLIVECDEF void olivec_sprite_blend(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_blend(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
 OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h, Olivec_Canvas sprite);
@@ -733,24 +733,27 @@ OLIVECDEF void olivec_triangle3z(Olivec_Canvas oc, int x1, int y1, int x2, int y
     }
     }
 }
 }
 
 
-OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, Uv uv1, Uv uv2, Uv uv3, Olivec_Canvas texture)
+OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, Uv uv1, Uv uv2, Uv uv3, float z1, float z2, float z3, Olivec_Canvas texture)
 {
 {
     if (y1 > y2) {
     if (y1 > y2) {
         OLIVEC_SWAP(int, x1, x2);
         OLIVEC_SWAP(int, x1, x2);
         OLIVEC_SWAP(int, y1, y2);
         OLIVEC_SWAP(int, y1, y2);
         OLIVEC_SWAP(Uv, uv1, uv2);
         OLIVEC_SWAP(Uv, uv1, uv2);
+        OLIVEC_SWAP(float, z1, z2);
     }
     }
 
 
     if (y2 > y3) {
     if (y2 > y3) {
         OLIVEC_SWAP(int, x2, x3);
         OLIVEC_SWAP(int, x2, x3);
         OLIVEC_SWAP(int, y2, y3);
         OLIVEC_SWAP(int, y2, y3);
         OLIVEC_SWAP(Uv, uv2, uv3);
         OLIVEC_SWAP(Uv, uv2, uv3);
+        OLIVEC_SWAP(float, z2, z3);
     }
     }
 
 
     if (y1 > y2) {
     if (y1 > y2) {
         OLIVEC_SWAP(int, x1, x2);
         OLIVEC_SWAP(int, x1, x2);
         OLIVEC_SWAP(int, y1, y2);
         OLIVEC_SWAP(int, y1, y2);
         OLIVEC_SWAP(Uv, uv1, uv2);
         OLIVEC_SWAP(Uv, uv1, uv2);
+        OLIVEC_SWAP(float, z1, z2);
     }
     }
 
 
     int dx12 = x2 - x1;
     int dx12 = x2 - x1;
@@ -769,12 +772,17 @@ OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int
                     int u1, u2, det;
                     int u1, u2, det;
                     barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
                     barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
                     int u3 = det - u1 - u2;
                     int u3 = det - u1 - u2;
+                    float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
                     Uv uv = olivec_uv(
                     Uv uv = olivec_uv(
                         uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
                         uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
                         uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
                         uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
                     );
                     );
-                    int texture_x = uv.u*texture.width;
-                    int texture_y = uv.v*texture.height;
+                    int texture_x = uv.u/z*texture.width;
+                    if (texture_x < 0) texture_x = 0;
+                    if ((size_t) texture_x >= texture.width) texture_x = texture.width - 1;
+                    int texture_y = uv.v/z*texture.height;
+                    if (texture_y < 0) texture_y = 0;
+                    if ((size_t) texture_y >= texture.height) texture_y = texture.height - 1;
                     OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, texture_x, texture_y);
                     OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, texture_x, texture_y);
                 }
                 }
             }
             }
@@ -796,12 +804,17 @@ OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int
                     int u1, u2, det;
                     int u1, u2, det;
                     barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
                     barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
                     int u3 = det - u1 - u2;
                     int u3 = det - u1 - u2;
+                    float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
                     Uv uv = olivec_uv(
                     Uv uv = olivec_uv(
                         uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
                         uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
                         uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
                         uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
                     );
                     );
-                    int texture_x = uv.u*texture.width;
-                    int texture_y = uv.v*texture.height;
+                    int texture_x = uv.u/z*texture.width;
+                    if (texture_x < 0) texture_x = 0;
+                    if ((size_t) texture_x >= texture.width) texture_x = texture.width - 1;
+                    int texture_y = uv.v/z*texture.height;
+                    if (texture_y < 0) texture_y = 0;
+                    if ((size_t) texture_y >= texture.height) texture_y = texture.height - 1;
                     OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, texture_x, texture_y);
                     OLIVEC_PIXEL(oc, x, y) = OLIVEC_PIXEL(texture, texture_x, texture_y);
                 }
                 }
             }
             }

BIN
wasm/3d.wasm


BIN
wasm/squish.wasm


BIN
wasm/triangle3dTex.wasm


BIN
wasm/triangleTex.wasm