-
Notifications
You must be signed in to change notification settings - Fork 130
Expand file tree
/
Copy pathmodel3d.c
More file actions
151 lines (127 loc) · 4.23 KB
/
model3d.c
File metadata and controls
151 lines (127 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "vc.c"
#define WIDTH 960
#define HEIGHT 720
#define BACKGROUND_COLOR 0xFF181818
#define PI 3.14159265359
float sqrtf(float x);
float atan2f(float y, float x);
float sinf(float x);
float cosf(float x);
static uint32_t pixels[WIDTH*HEIGHT];
static float zbuffer[WIDTH*HEIGHT] = {0};
static float angle = 0;
typedef struct {
float x, y;
} Vector2;
static Vector2 make_vector2(float x, float y)
{
Vector2 v2;
v2.x = x;
v2.y = y;
return v2;
}
typedef struct {
float x, y, z;
} Vector3;
static Vector3 make_vector3(float x, float y, float z)
{
Vector3 v3;
v3.x = x;
v3.y = y;
v3.z = z;
return v3;
}
#define EPSILON 1e-6
static Vector2 project_3d_2d(Vector3 v3)
{
if (v3.z < 0) v3.z = -v3.z;
if (v3.z < EPSILON) v3.z += EPSILON;
return make_vector2(v3.x/v3.z, v3.y/v3.z);
}
static Vector2 project_2d_scr(Vector2 v2)
{
return make_vector2((v2.x + 1)/2*WIDTH, (1 - (v2.y + 1)/2)*HEIGHT);
}
static Vector3 rotate_y(Vector3 p, float delta_angle)
{
float angle = atan2f(p.z, p.x) + delta_angle;
float mag = sqrtf(p.x*p.x + p.z*p.z);
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;
Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT, WIDTH);
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, 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));
int x1 = p1.x;
int x2 = p2.x;
int x3 = p3.x;
int y1 = p1.y;
int y2 = p2.y;
int y3 = p3.y;
int lx, hx, ly, hy;
if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) {
for (int y = ly; y <= hy; ++y) {
for (int x = lx; x <= hx; ++x) {
int u1, u2, det;
if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) {
int u3 = det - u1 - u2;
float z = 1/v1.z*u1/det + 1/v2.z*u2/det + 1/v3.z*u3/det;
float near = 0.1f;
float far = 5.0f;
if (1.0f/far < z && z < 1.0f/near && z > zbuffer[y*WIDTH + x]) {
zbuffer[y*WIDTH + x] = z;
OLIVEC_PIXEL(oc, x, y) = mix_colors3(0xFF1818FF, 0xFF18FF18, 0xFFFF1818, u1, u2, det);
z = 1.0f/z;
if (z >= 1.0) {
z -= 1.0;
uint32_t v = z*255;
if (v > 255) v = 255;
olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), (v<<(3*8)));
}
}
}
}
}
}
}
return oc;
}