1.实现画三角形
void triangle(Vec2i t0, Vec2i t1, Vec2i t2, TGAImage &image, TGAColor color) { line(t0, t1, image, color); line(t1, t2, image, color); line(t2, t0, image, color); } // ... Vec2i t0[3] = {Vec2i(10, 70), Vec2i(50, 160), Vec2i(70, 80)}; Vec2i t1[3] = {Vec2i(180, 50), Vec2i(150, 1), Vec2i(70, 180)}; Vec2i t2[3] = {Vec2i(180, 150), Vec2i(120, 160), Vec2i(130, 180)}; triangle(t0[0], t0[1], t0[2], image, red); triangle(t1[0], t1[1], t1[2], image, white); triangle(t2[0], t2[1], t2[2], image, green);
2.排序
void triangle(Vec2i t0, Vec2i t1, Vec2i t2, TGAImage &image, TGAColor color) { // sort the vertices, t0, t1, t2 lower−to−upper (bubblesort yay!) if (t0.y>t1.y) std::swap(t0, t1); if (t0.y>t2.y) std::swap(t0, t2); if (t1.y>t2.y) std::swap(t1, t2); line(t0, t1, image, green); line(t1, t2, image, green); line(t2, t0, image, red); }
3.将三角形垂直分为两半
void triangle(Vec2i t0, Vec2i t1, Vec2i t2, TGAImage &image, TGAColor color) { // sort the vertices, t0, t1, t2 lower−to−upper (bubblesort yay!) if (t0.y>t1.y) std::swap(t0, t1); if (t0.y>t2.y) std::swap(t0, t2); if (t1.y>t2.y) std::swap(t1, t2); int total_height = t2.y-t0.y; for (int y=t0.y; y<=t1.y; y++) { int segment_height = t1.y-t0.y+1; float alpha = (float)(y-t0.y)/total_height; float beta = (float)(y-t0.y)/segment_height; // be careful with divisions by zero Vec2i A = t0 + (t2-t0)*alpha; Vec2i B = t0 + (t1-t0)*beta; image.set(A.x, y, red); image.set(B.x, y, green); } }
4.填充三角形
void triangle(Vec2i t0, Vec2i t1, Vec2i t2, TGAImage &image, TGAColor color) { // sort the vertices, t0, t1, t2 lower−to−upper (bubblesort yay!) if (t0.y>t1.y) std::swap(t0, t1); if (t0.y>t2.y) std::swap(t0, t2); if (t1.y>t2.y) std::swap(t1, t2); int total_height = t2.y-t0.y; for (int y=t0.y; y<=t1.y; y++) { int segment_height = t1.y-t0.y+1; float alpha = (float)(y-t0.y)/total_height; float beta = (float)(y-t0.y)/segment_height; // be careful with divisions by zero Vec2i A = t0 + (t2-t0)*alpha; Vec2i B = t0 + (t1-t0)*beta; if (A.x>B.x) std::swap(A, B); for (int j=A.x; j<=B.x; j++) { image.set(j, y, color); // attention, due to int casts t0.y+i != A.y } } for (int y=t1.y; y<=t2.y; y++) { int segment_height = t2.y-t1.y+1; float alpha = (float)(y-t0.y)/total_height; float beta = (float)(y-t1.y)/segment_height; // be careful with divisions by zero Vec2i A = t0 + (t2-t0)*alpha; Vec2i B = t1 + (t2-t1)*beta; if (A.x>B.x) std::swap(A, B); for (int j=A.x; j<=B.x; j++) { image.set(j, y, color); // attention, due to int casts t0.y+i != A.y } }
5. 推导:p = A + u(AB) + v(AC)
---------------------------------
u(AB) + v(AC) + (PA) = 0
---------------------------------
u(ABx) + v(ACx) + (PAx) = 0
u(ABy) + v(ACy) + (PAy) = 0
--------------------------------
(u,v,1)同时垂直于(ABx,ACx,PAx)和(ABy,ACy,PAy)
(u,v,1) = cross(vec3(ABx,ACx,PAx) ,vec3 (ABy,ACy,PAy))
--------------------------------
u > 0
v > 0
u+1 < 1
#include <vector> #include <iostream> #include ”geometry.h” #include ”tgaimage.h” const int width = 200; const int height = 200; Vec3f barycentric(Vec2i *pts, Vec2i P) { Vec3f u = cross(Vec3f(pts[2][0]-pts[0][0], pts[1][0]-pts[0][0], pts[0][0]-P[0]), Vec3f(pts[2][1]-pts[0][1], pts[1][1]-pts[0][1], pts[0][1]-P[1])); if (std::abs(u[2])<1) return Vec3f(-1,1,1); // triangle is degenerate, in this case return smth with negative coordinates return Vec3f(1.f-(u.x+u.y)/u.z, u.y/u.z, u.x/u.z); } void triangle(Vec2i *pts, TGAImage &image, TGAColor color) { Vec2i bboxmin(image.get_width()-1, image.get_height()-1); Vec2i bboxmax(0, 0); Vec2i clamp(image.get_width()-1, image.get_height()-1); for (int i=0; i<3; i++) { for (int j=0; j<2; j++) { bboxmin[j] = std::max(0, std::min(bboxmin[j], pts[i][j])); bboxmax[j] = std::min(clamp[j], std::max(bboxmax[j], pts[i][j])); } } Vec2i P; for (P.x=bboxmin.x; P.x<=bboxmax.x; P.x++) { for (P.y=bboxmin.y; P.y<=bboxmax.y; P.y++) { Vec3f bc_screen = barycentric(pts, P); if (bc_screen.x<0 || bc_screen.y<0 || bc_screen.z<0) continue; image.set(P.x, P.y, color); } } } int main(int argc, char** argv) { TGAImage frame(200, 200, TGAImage::RGB); Vec2i pts[3] = {Vec2i(10,10), Vec2i(100, 30), Vec2i(190, 160)}; triangle(pts, frame, TGAColor(255, 0, 0)); frame.flip_vertically(); // to place the origin in the bottom left corner of the image frame.write_tga_file(”framebuffer.tga”); return 0; }