diff options
author | chai <chaifix@163.com> | 2019-12-04 00:07:32 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-12-04 00:07:32 +0800 |
commit | 2e82e2ddd0852b8063a3d6645366f53ee844e273 (patch) | |
tree | 41ec10760f2d2c9f1f782a918f48e1287da2a4b4 /src/core/rasterizer.c |
+init
Diffstat (limited to 'src/core/rasterizer.c')
-rw-r--r-- | src/core/rasterizer.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/core/rasterizer.c b/src/core/rasterizer.c new file mode 100644 index 0000000..0c8c6eb --- /dev/null +++ b/src/core/rasterizer.c @@ -0,0 +1,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); +}
\ No newline at end of file |