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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
#include "rasterizer.h"
#include "device.h"
#include "shader.h"
#include "../math/math.h"
#include "../util/assert.h"
void ssrR_putline(int x0, int y0, int x1, int y1, Color color) {
int steep = 0;
if (abs(x0 - x1) < abs(y0 - y1)) {
swapi(x0, y0);
swapi(x1, y1);
steep = 1;
}
if (x0 > x1) {
swapi(x0, x1);
swapi(y0, y1);
}
int dx = x1 - x0;
int dy = y1 - y0;
int derror2 = abs(dy) << 1;
int error2 = 0;
int y = y0;
for (int x = x0; x <= x1; ++x) {
if (steep) {
ssr_putpoint(y, x, color);
}
else {
ssr_putpoint(x, y, color);
}
error2 += derror2;
if (error2 > dx) {
y += (y1 > y0 ? 1 : -1);
error2 -= (dx << 1);
}
}
}
/*使用辅助梯形计算三角形面积,《3D数学基础》P245*/
float ssrR_area(Vec2* v1, Vec2* v2, Vec2* v3) {
ssr_assert(v1 && v2 && v3);
float area = 0.5f * ((v1->y - v2->y) * (v3->x - v2->x) + (v3->y - v2->y) * (v2->x - v1->x));
return area;
}
/*from https://github.com/ssloy/tinyrenderer*/
static Vec3 s[2], u;
bool ssrR_barycentric(Vec2* A, Vec2* B, Vec2* C, Vec2* p, Vec3* out) {
ssr_assert(A && B && C && p && out);
s[0].x = C->x - A->x; s[0].y = B->x - A->x; s[0].z = A->x - p->x;
s[1].x = C->y - A->y; s[1].y = B->y - A->y; s[1].z = A->y - p->y;
vec3_cross(&s[0], &s[1], &u);
if (compare(u.z, 0)) {
return 0;
} else {
float uz = 1.f / u.z;
out->x = 1 - (u.x + u.y) * uz;
out->y = u.y * uz;
out->z = u.x * uz;
return 1;
}
}
bool ssrR_ispointintriangle(Vec2* A, Vec2* B, Vec2* C, Vec2* p) {
ssr_assert(A && B && C && p);
Vec3 c; ssrR_barycentric(A, B, C, p, &c);
return c.x >= 0 && c.y >= 0 && c.z >= 0;
}
void ssrR_center(Vec2* A, Vec2* B, Vec2* C, Vec2* out) {
ssr_assert(A && B && C && out);
float k = 1 / 3.f;
out->x = k * (A->x + B->x + C->x);
out->y = k * (A->y + B->y + C->y);
}
/*
** clipc 按列排放的三角形三个顶点的齐次裁剪坐标
** program shader程序
*/
static Vec3 SA, SB, SC; // screen coords
static Vec3 bcp; // 重心坐标
void _ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, Vert* A, Vert* B, Vert* C, Program* program, UniformCollection* uniforms) {
ssr_assert(CA && CB && CC && program);
vec4_dividew(CA, &SA); ssrU_viewport(&SA, &SA);
vec4_dividew(CB, &SB); ssrU_viewport(&SB, &SB);
vec4_dividew(CC, &SC); ssrU_viewport(&SC, &SC);
/*根据屏幕空间的y值排序, A的y最小,B居中,C最大*/
Vec3 *sa = &SA, *sb = &SB, *sc = &SC, *tmp; Vec4* v4tmp; Vert* vtemp;
if (sb->y < sa->y) { sa = &SB; sb = &SA; v4tmp = CA; CA = CB; CB = v4tmp; vtemp = A; A = B; B = vtemp; }
if (sc->y < sb->y) { tmp = sc; sc = sb; sb = tmp; v4tmp = CC; CC = CB; CB = v4tmp; vtemp = B; B = C; C = vtemp; }
if (sc->y < sa->y) { tmp = sc; sc = sa; sa = tmp; v4tmp = CC; CC = CA; CA = v4tmp; vtemp = C; C = A; A = vtemp; }
float invkAC = (SC.x - SA.x) / (SC.y - SA.y + EPSILON);
float invkAB = (SB.x - SA.x) / (SB.y - SA.y + EPSILON);
float invkBC = (SC.x - SB.x) / (SC.y - SB.y + EPSILON);
int order = 1; if (((sb->y - sa->y) / (sb->x - sa->x) - invkAC) * invkAC > 0) { order = -1; }
FragmentShaderIn in = {A, B, C, 0};
Color color;
Vec2 l, r, p;
float depth; Vec3 cdepth = {SA.z, SB.z, SC.z};
float CAw = 1.f / CA->w, CBw = 1.f / CB->w, CCw = 1.f / CC->w;
for (p.y = sa->y; p.y <= sc->y; ++p.y) {
l.y = p.y;
r.y = p.y;
if (compare(SC.y, SA.y)) r.x = sc->x;
else r.x = sa->x + invkAC * (p.y - sa->y); /*AC*/
if (p.y <= sb->y) {
if (compare(SB.y, SA.y)) l.x = sb->x;
else l.x = sa->x + invkAB * (p.y - sa->y);
} else {
if (compare(SC.y, SB.y)) l.x = sc->x;
else l.x = sb->x + invkBC * (p.y - sb->y);
}
for (p.x = l.x; order * (r.x - p.x) >= 0; p.x += order) {
/*计算线性的(齐次裁剪空间)的重心坐标,分三步*/
if (!ssrR_barycentric(sa, sb, sc, &p, &bcp)) {
continue; /*discard fragment*/
}
bcp.x *= CAw; bcp.y *= CBw; bcp.z *= CCw;
vec3_scale(&bcp, 1.f / (bcp.x + bcp.y + bcp.z), &bcp);
/*depth test*/
depth = vec3_dot(&bcp, &cdepth) * 0.5f + 0.5f;
if (!ssr_testdepthf(p.x, p.y, depth)) {
continue; /*discard fragment*/
}
/*enter fragment shader*/
in.bc = &bcp;
program->fragmentshader(uniforms, &in, &color);
ssr_putpoint(p.x, p.y, color);
}
}
}
static Vec2 bboxmin, bboxmax;
void ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, Vert* A, Vert* B, Vert* C, Program* program, UniformCollection* uniforms) {
ssr_assert(CA && CB && CC && program);
vec4_dividew(CA, &SA); ssrU_viewport(&SA, &SA);
vec4_dividew(CB, &SB); ssrU_viewport(&SB, &SB);
vec4_dividew(CC, &SC); ssrU_viewport(&SC, &SC);
bboxmin.x = min(SA.x, min(SB.x, SC.x));
bboxmax.x = max(SA.x, max(SB.x, SC.x));
bboxmin.y = min(SA.y, min(SB.y, SC.y));
bboxmax.y = max(SA.y, max(SB.y, SC.y));
float CAw = 1.f / CA->w, CBw = 1.f / CB->w, CCw = 1.f / CC->w;
float depth; Vec3 cdepth = { SA.z, SB.z, SC.z };
FragmentShaderIn in = { A, B, C, 0 };
Vec2 p; Color color;
for (p.y = bboxmin.y; p.y <= bboxmax.y; ++p.y) {
for (p.x = bboxmin.x; p.x <= bboxmax.x; ++p.x) {
/*计算线性的(齐次裁剪空间)的重心坐标,分三步*/
if (!ssrR_barycentric(&SA, &SB, &SC, &p, &bcp)) {
continue; /*discard fragment*/
}
if (bcp.x < 0 || bcp.y < 0 || bcp.z < 0) {
continue; /*discard fragment*/
}
bcp.x *= CAw; bcp.y *= CBw; bcp.z *= CCw;
vec3_scale(&bcp, 1.f / (bcp.x + bcp.y + bcp.z), &bcp);
/*深度测试*/
if (ssr_isenable(ENABLEMASK_DEPTHTEST)) {
depth = vec3_dot(&bcp, &cdepth) * 0.5f + 0.5f;
if (!ssr_testdepthf(p.x, p.y, depth)) {
continue; /*discard fragment*/
}
}
/*enter fragment shader*/
in.bc = &bcp;
bool discad = program->fragmentshader(uniforms, &in, &color);
if (!discad)
ssr_putpoint(p.x, p.y, color);
}
}
//ssrR_putline(SA.x, SA.y, SB.x, SB.y, 0xffff0000);
//ssrR_putline(SA.x, SA.y, SC.x, SC.y, 0xffff0000);
//ssrR_putline(SC.x, SC.y, SB.x, SB.y, 0xffff0000);
}
|