model3d.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include "vc.c"
  2. #define WIDTH 960
  3. #define HEIGHT 720
  4. #define BACKGROUND_COLOR 0xFF181818
  5. #define PI 3.14159265359
  6. float sqrtf(float x);
  7. float atan2f(float y, float x);
  8. float sinf(float x);
  9. float cosf(float x);
  10. static uint32_t pixels[WIDTH*HEIGHT];
  11. static float zbuffer[WIDTH*HEIGHT] = {0};
  12. static float angle = 0;
  13. typedef struct {
  14. float x, y;
  15. } Vector2;
  16. static Vector2 make_vector2(float x, float y)
  17. {
  18. Vector2 v2;
  19. v2.x = x;
  20. v2.y = y;
  21. return v2;
  22. }
  23. typedef struct {
  24. float x, y, z;
  25. } Vector3;
  26. static Vector3 make_vector3(float x, float y, float z)
  27. {
  28. Vector3 v3;
  29. v3.x = x;
  30. v3.y = y;
  31. v3.z = z;
  32. return v3;
  33. }
  34. #define EPSILON 1e-6
  35. static Vector2 project_3d_2d(Vector3 v3)
  36. {
  37. if (v3.z < 0) v3.z = -v3.z;
  38. if (v3.z < EPSILON) v3.z += EPSILON;
  39. return make_vector2(v3.x/v3.z, v3.y/v3.z);
  40. }
  41. static Vector2 project_2d_scr(Vector2 v2)
  42. {
  43. return make_vector2((v2.x + 1)/2*WIDTH, (1 - (v2.y + 1)/2)*HEIGHT);
  44. }
  45. static Vector3 rotate_y(Vector3 p, float delta_angle)
  46. {
  47. float angle = atan2f(p.z, p.x) + delta_angle;
  48. float mag = sqrtf(p.x*p.x + p.z*p.z);
  49. return make_vector3(cosf(angle)*mag, p.y, sinf(angle)*mag);
  50. }
  51. typedef enum {
  52. FACE_V1,
  53. FACE_V2,
  54. FACE_V3,
  55. FACE_VT1,
  56. FACE_VT2,
  57. FACE_VT3,
  58. FACE_VN1,
  59. FACE_VN2,
  60. FACE_VN3,
  61. } Face_Index;
  62. float vector3_dot(Vector3 a, Vector3 b)
  63. {
  64. return a.x*b.x + a.y*b.y + a.z*b.z;
  65. }
  66. Olivec_Canvas vc_render(float dt)
  67. {
  68. angle += 0.25*PI*dt;
  69. Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT, WIDTH);
  70. olivec_fill(oc, BACKGROUND_COLOR);
  71. for (size_t i = 0; i < WIDTH*HEIGHT; ++i) zbuffer[i] = 0;
  72. Vector3 camera = {0, 0, 1};
  73. for (size_t i = 0; i < faces_count; ++i) {
  74. int a, b, c;
  75. a = faces[i][FACE_V1];
  76. b = faces[i][FACE_V2];
  77. c = faces[i][FACE_V3];
  78. Vector3 v1 = rotate_y(make_vector3(vertices[a][0], vertices[a][1], vertices[a][2]), angle);
  79. Vector3 v2 = rotate_y(make_vector3(vertices[b][0], vertices[b][1], vertices[b][2]), angle);
  80. Vector3 v3 = rotate_y(make_vector3(vertices[c][0], vertices[c][1], vertices[c][2]), angle);
  81. v1.z += 1.5; v2.z += 1.5; v3.z += 1.5;
  82. a = faces[i][FACE_VN1];
  83. b = faces[i][FACE_VN2];
  84. c = faces[i][FACE_VN3];
  85. Vector3 vn1 = rotate_y(make_vector3(normals[a][0], normals[a][1], normals[a][2]), angle);
  86. Vector3 vn2 = rotate_y(make_vector3(normals[b][0], normals[b][1], normals[b][2]), angle);
  87. Vector3 vn3 = rotate_y(make_vector3(normals[c][0], normals[c][1], normals[c][2]), angle);
  88. if (vector3_dot(camera, vn1) > 0.0 &&
  89. vector3_dot(camera, vn2) > 0.0 &&
  90. vector3_dot(camera, vn3) > 0.0) continue;
  91. Vector2 p1 = project_2d_scr(project_3d_2d(v1));
  92. Vector2 p2 = project_2d_scr(project_3d_2d(v2));
  93. Vector2 p3 = project_2d_scr(project_3d_2d(v3));
  94. int x1 = p1.x;
  95. int x2 = p2.x;
  96. int x3 = p3.x;
  97. int y1 = p1.y;
  98. int y2 = p2.y;
  99. int y3 = p3.y;
  100. int lx, hx, ly, hy;
  101. if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
  102. for (int y = ly; y <= hy; ++y) {
  103. for (int x = lx; x <= hx; ++x) {
  104. int u1, u2, det;
  105. if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
  106. int u3 = det - u1 - u2;
  107. float z = 1/v1.z*u1/det + 1/v2.z*u2/det + 1/v3.z*u3/det;
  108. float near = 0.1f;
  109. float far = 5.0f;
  110. if (1.0f/far < z && z < 1.0f/near && z > zbuffer[y*WIDTH + x]) {
  111. zbuffer[y*WIDTH + x] = z;
  112. OLIVEC_PIXEL(oc, x, y) = mix_colors3(0xFF1818FF, 0xFF18FF18, 0xFFFF1818, u1, u2, det);
  113. z = 1.0f/z;
  114. if (z >= 1.0) {
  115. z -= 1.0;
  116. uint32_t v = z*255;
  117. if (v > 255) v = 255;
  118. olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), (v<<(3*8)));
  119. }
  120. }
  121. }
  122. }
  123. }
  124. }
  125. }
  126. return oc;
  127. }